mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:12:26 +00:00
Switch to a custom HomeserverReachability instead of different publishers
This commit is contained in:
@@ -275,7 +275,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
let mediaProvider = authenticationService.classicAppAccount.map { account in
|
let mediaProvider = authenticationService.classicAppAccount.map { account in
|
||||||
MediaProvider(mediaLoader: ClassicAppMediaLoader(classicAppAccount: account),
|
MediaProvider(mediaLoader: ClassicAppMediaLoader(classicAppAccount: account),
|
||||||
imageCache: .onlyInMemory,
|
imageCache: .onlyInMemory,
|
||||||
homeserverReachabilityPublisher: appMediator.networkMonitor.reachabilityPublisher) // Close enough approximation
|
homeserverReachabilityPublisher: appMediator.networkMonitor.reachabilityPublisher.map(HomeserverReachability.init)) // Close enough approximation
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters = AuthenticationStartScreenParameters(authenticationService: authenticationService,
|
let parameters = AuthenticationStartScreenParameters(authenticationService: authenticationService,
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
let reachabilityNotificationID = "io.element.elementx.reachability.notification"
|
let reachabilityNotificationID = "io.element.elementx.reachability.notification"
|
||||||
userSession.clientProxy.homeserverConnectivityPublisher.removeDuplicates()
|
userSession.clientProxy.homeserverReachabilityPublisher.removeDuplicates()
|
||||||
.combineLatest(flowParameters.appMediator.networkMonitor.reachabilityPublisher.removeDuplicates())
|
.combineLatest(flowParameters.appMediator.networkMonitor.reachabilityPublisher.removeDuplicates())
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] homeserverReachability, networkReachability in
|
.sink { [weak self] homeserverReachability, networkReachability in
|
||||||
@@ -293,16 +293,17 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
switch (networkReachability, homeserverReachability) {
|
switch (networkReachability, homeserverReachability) {
|
||||||
case (.reachable, .reachable):
|
|
||||||
flowParameters.userIndicatorController.retractIndicatorWithId(reachabilityNotificationID)
|
|
||||||
case (.reachable, .unreachable):
|
|
||||||
flowParameters.userIndicatorController.submitIndicator(.init(id: reachabilityNotificationID,
|
|
||||||
title: L10n.commonServerUnreachable,
|
|
||||||
persistent: true))
|
|
||||||
case (.unreachable, _):
|
case (.unreachable, _):
|
||||||
flowParameters.userIndicatorController.submitIndicator(.init(id: reachabilityNotificationID,
|
flowParameters.userIndicatorController.submitIndicator(.init(id: reachabilityNotificationID,
|
||||||
title: L10n.commonOffline,
|
title: L10n.commonOffline,
|
||||||
persistent: true))
|
persistent: true))
|
||||||
|
case (.reachable, .unreachable):
|
||||||
|
flowParameters.userIndicatorController.submitIndicator(.init(id: reachabilityNotificationID,
|
||||||
|
title: L10n.commonServerUnreachable,
|
||||||
|
persistent: true))
|
||||||
|
// Don't alarm the user while we've intentionally suspended the client.
|
||||||
|
case (.reachable, .reachable), (.reachable, .suspended):
|
||||||
|
flowParameters.userIndicatorController.retractIndicatorWithId(reachabilityNotificationID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ extension ClientProxyMock {
|
|||||||
loadingStatePublisher = .init(.notLoading)
|
loadingStatePublisher = .init(.notLoading)
|
||||||
verificationStatePublisher = .init(.unknown)
|
verificationStatePublisher = .init(.unknown)
|
||||||
homeserverReachabilityPublisher = .init(.reachable)
|
homeserverReachabilityPublisher = .init(.reachable)
|
||||||
homeserverConnectivityPublisher = .init(.reachable)
|
|
||||||
|
|
||||||
userAvatarURLPublisher = .init(nil)
|
userAvatarURLPublisher = .init(nil)
|
||||||
userDisplayNamePublisher = .init("User display name")
|
userDisplayNamePublisher = .init("User display name")
|
||||||
|
|||||||
@@ -2227,16 +2227,11 @@ nonisolated class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
|
|||||||
set(value) { underlyingVerificationStatePublisher = value }
|
set(value) { underlyingVerificationStatePublisher = value }
|
||||||
}
|
}
|
||||||
nonisolated(unsafe) var underlyingVerificationStatePublisher: CurrentValuePublisher<SessionVerificationState, Never>!
|
nonisolated(unsafe) var underlyingVerificationStatePublisher: CurrentValuePublisher<SessionVerificationState, Never>!
|
||||||
var homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> {
|
var homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never> {
|
||||||
get { return underlyingHomeserverReachabilityPublisher }
|
get { return underlyingHomeserverReachabilityPublisher }
|
||||||
set(value) { underlyingHomeserverReachabilityPublisher = value }
|
set(value) { underlyingHomeserverReachabilityPublisher = value }
|
||||||
}
|
}
|
||||||
nonisolated(unsafe) var underlyingHomeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>!
|
nonisolated(unsafe) var underlyingHomeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>!
|
||||||
var homeserverConnectivityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> {
|
|
||||||
get { return underlyingHomeserverConnectivityPublisher }
|
|
||||||
set(value) { underlyingHomeserverConnectivityPublisher = value }
|
|
||||||
}
|
|
||||||
nonisolated(unsafe) var underlyingHomeserverConnectivityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>!
|
|
||||||
var userID: String {
|
var userID: String {
|
||||||
get { return underlyingUserID }
|
get { return underlyingUserID }
|
||||||
set(value) { underlyingUserID = value }
|
set(value) { underlyingUserID = value }
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ import Combine
|
|||||||
/// `CurrentValueSubject` is documented as thread-safe but is not formally `Sendable`, hence `@unchecked`.
|
/// `CurrentValueSubject` is documented as thread-safe but is not formally `Sendable`, hence `@unchecked`.
|
||||||
nonisolated struct CurrentValuePublisher<Output, Failure: Error>: Publisher, @unchecked Sendable {
|
nonisolated struct CurrentValuePublisher<Output, Failure: Error>: Publisher, @unchecked Sendable {
|
||||||
private let subject: CurrentValueSubject<Output, Failure>
|
private let subject: CurrentValueSubject<Output, Failure>
|
||||||
|
/// Retains the upstream subscription feeding ``subject`` when this publisher is derived via ``map(_:)``.
|
||||||
|
private let cancellable: AnyCancellable?
|
||||||
|
|
||||||
init(_ subject: CurrentValueSubject<Output, Failure>) {
|
init(_ subject: CurrentValueSubject<Output, Failure>, cancellable: AnyCancellable? = nil) {
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
|
self.cancellable = cancellable
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_ value: Output) {
|
init(_ value: Output) {
|
||||||
@@ -32,6 +35,14 @@ nonisolated struct CurrentValuePublisher<Output, Failure: Error>: Publisher, @un
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonisolated extension CurrentValuePublisher where Failure == Never {
|
||||||
|
func map<T>(_ transform: @escaping (Output) -> T) -> CurrentValuePublisher<T, Never> {
|
||||||
|
let subject = CurrentValueSubject<T, Never>(transform(value))
|
||||||
|
let cancellable = sink { subject.send(transform($0)) }
|
||||||
|
return .init(subject, cancellable: cancellable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nonisolated extension CurrentValueSubject {
|
nonisolated extension CurrentValueSubject {
|
||||||
func asCurrentValuePublisher() -> CurrentValuePublisher<Output, Failure> {
|
func asCurrentValuePublisher() -> CurrentValuePublisher<Output, Failure> {
|
||||||
.init(self)
|
.init(self)
|
||||||
|
|||||||
@@ -13,6 +13,19 @@ enum NetworkMonitorReachability {
|
|||||||
case unreachable
|
case unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HomeserverReachability {
|
||||||
|
/// The store is open and the homeserver is reachable.
|
||||||
|
case reachable
|
||||||
|
/// The homeserver can't be reached even though we're trying to sync (i.e. offline).
|
||||||
|
case unreachable
|
||||||
|
/// The client is suspended, so the store is closed and we're not trying to reach the homeserver.
|
||||||
|
case suspended
|
||||||
|
|
||||||
|
init(_ reachability: NetworkMonitorReachability) {
|
||||||
|
self = reachability == .reachable ? .reachable : .unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protocol NetworkMonitorProtocol {
|
protocol NetworkMonitorProtocol {
|
||||||
var reachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> { get }
|
var reachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> { get }
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct SecureBackupLogoutConfirmationScreenCoordinatorParameters {
|
struct SecureBackupLogoutConfirmationScreenCoordinatorParameters {
|
||||||
let secureBackupController: SecureBackupControllerProtocol
|
let secureBackupController: SecureBackupControllerProtocol
|
||||||
let homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>
|
let homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SecureBackupLogoutConfirmationScreenCoordinatorAction {
|
enum SecureBackupLogoutConfirmationScreenCoordinatorAction {
|
||||||
|
|||||||
+4
-4
@@ -13,7 +13,7 @@ typealias SecureBackupLogoutConfirmationScreenViewModelType = StateStoreViewMode
|
|||||||
|
|
||||||
class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmationScreenViewModelType, SecureBackupLogoutConfirmationScreenViewModelProtocol {
|
class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmationScreenViewModelType, SecureBackupLogoutConfirmationScreenViewModelProtocol {
|
||||||
private let secureBackupController: SecureBackupControllerProtocol
|
private let secureBackupController: SecureBackupControllerProtocol
|
||||||
private let homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>
|
private let homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>
|
||||||
|
|
||||||
private let backupUploadStateSubject: CurrentValueSubject<SecureBackupSteadyState, Never> = .init(.waiting)
|
private let backupUploadStateSubject: CurrentValueSubject<SecureBackupSteadyState, Never> = .init(.waiting)
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmat
|
|||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(secureBackupController: SecureBackupControllerProtocol, homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>) {
|
init(secureBackupController: SecureBackupControllerProtocol, homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>) {
|
||||||
self.secureBackupController = secureBackupController
|
self.secureBackupController = secureBackupController
|
||||||
self.homeserverReachabilityPublisher = homeserverReachabilityPublisher
|
self.homeserverReachabilityPublisher = homeserverReachabilityPublisher
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateMode(backupState: SecureBackupSteadyState, reachability: NetworkMonitorReachability) {
|
private func updateMode(backupState: SecureBackupSteadyState, reachability: HomeserverReachability) {
|
||||||
switch (backupState, reachability) {
|
switch (backupState, reachability) {
|
||||||
case (.waiting, .reachable):
|
case (.waiting, .reachable):
|
||||||
state.mode = .waitingToStart(hasStalled: false)
|
state.mode = .waitingToStart(hasStalled: false)
|
||||||
@@ -101,7 +101,7 @@ class SecureBackupLogoutConfirmationScreenViewModel: SecureBackupLogoutConfirmat
|
|||||||
break // Nothing to do here, it will be handled with the result.
|
break // Nothing to do here, it will be handled with the result.
|
||||||
case (.done, .reachable):
|
case (.done, .reachable):
|
||||||
state.mode = .backupOngoing(progress: 1.0)
|
state.mode = .backupOngoing(progress: 1.0)
|
||||||
case (_, .unreachable):
|
case (_, .unreachable), (_, .suspended):
|
||||||
state.mode = .offline
|
state.mode = .offline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -160,7 +160,7 @@ struct SecureBackupLogoutConfirmationScreen_Previews: PreviewProvider, TestableP
|
|||||||
return .success(())
|
return .success(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let reachability: NetworkMonitorReachability = mode == .offline ? .unreachable : .reachable
|
let reachability: HomeserverReachability = mode == .offline ? .unreachable : .reachable
|
||||||
|
|
||||||
let viewModel = SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: secureBackupController,
|
let viewModel = SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: secureBackupController,
|
||||||
homeserverReachabilityPublisher: .init(reachability))
|
homeserverReachabilityPublisher: .init(reachability))
|
||||||
|
|||||||
@@ -180,21 +180,11 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
verificationStateSubject.asCurrentValuePublisher()
|
verificationStateSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports unreachable while suspended (the store is closed) as well as when offline. Use this to gate
|
private let homeserverReachabilitySubject = CurrentValueSubject<HomeserverReachability, Never>(.reachable)
|
||||||
/// work that needs an open store, such as media loading.
|
var homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never> {
|
||||||
private let homeserverReachabilitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable)
|
|
||||||
var homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> {
|
|
||||||
homeserverReachabilitySubject.asCurrentValuePublisher()
|
homeserverReachabilitySubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The homeserver's reachability derived from the sync service alone, i.e. it stays reachable while the
|
|
||||||
/// client is suspended. Use this for user-facing messaging so we don't claim the server is unreachable
|
|
||||||
/// when we've simply paused syncing.
|
|
||||||
private let homeserverConnectivitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable)
|
|
||||||
var homeserverConnectivityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> {
|
|
||||||
homeserverConnectivitySubject.asCurrentValuePublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
private let timelineMediaVisibilitySubject = CurrentValueSubject<TimelineMediaVisibility, Never>(.always)
|
private let timelineMediaVisibilitySubject = CurrentValueSubject<TimelineMediaVisibility, Never>(.always)
|
||||||
var timelineMediaVisibilityPublisher: CurrentValuePublisher<TimelineMediaVisibility, Never> {
|
var timelineMediaVisibilityPublisher: CurrentValuePublisher<TimelineMediaVisibility, Never> {
|
||||||
timelineMediaVisibilitySubject.asCurrentValuePublisher()
|
timelineMediaVisibilitySubject.asCurrentValuePublisher()
|
||||||
@@ -1210,12 +1200,12 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateHomeserverReachability() {
|
private func updateHomeserverReachability() {
|
||||||
homeserverConnectivitySubject.send(syncServiceState == .offline ? .unreachable : .reachable)
|
let reachability: HomeserverReachability = if desiredServiceState != .running {
|
||||||
|
.suspended
|
||||||
let reachability: NetworkMonitorReachability = if desiredServiceState == .running, syncServiceState != .offline {
|
} else if syncServiceState == .offline {
|
||||||
.reachable
|
|
||||||
} else {
|
|
||||||
.unreachable
|
.unreachable
|
||||||
|
} else {
|
||||||
|
.reachable
|
||||||
}
|
}
|
||||||
|
|
||||||
homeserverReachabilitySubject.send(reachability)
|
homeserverReachabilitySubject.send(reachability)
|
||||||
|
|||||||
@@ -108,9 +108,7 @@ protocol ClientProxyProtocol: AnyObject {
|
|||||||
|
|
||||||
var verificationStatePublisher: CurrentValuePublisher<SessionVerificationState, Never> { get }
|
var verificationStatePublisher: CurrentValuePublisher<SessionVerificationState, Never> { get }
|
||||||
|
|
||||||
var homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> { get }
|
var homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never> { get }
|
||||||
|
|
||||||
var homeserverConnectivityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never> { get }
|
|
||||||
|
|
||||||
var userID: String { get }
|
var userID: String { get }
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import UIKit
|
|||||||
nonisolated struct MediaProvider: MediaProviderProtocol {
|
nonisolated struct MediaProvider: MediaProviderProtocol {
|
||||||
private let mediaLoader: MediaLoaderProtocol
|
private let mediaLoader: MediaLoaderProtocol
|
||||||
private let imageCache: Kingfisher.ImageCache
|
private let imageCache: Kingfisher.ImageCache
|
||||||
private let homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>?
|
private let homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>?
|
||||||
|
|
||||||
init(mediaLoader: MediaLoaderProtocol,
|
init(mediaLoader: MediaLoaderProtocol,
|
||||||
imageCache: Kingfisher.ImageCache,
|
imageCache: Kingfisher.ImageCache,
|
||||||
homeserverReachabilityPublisher: CurrentValuePublisher<NetworkMonitorReachability, Never>?) {
|
homeserverReachabilityPublisher: CurrentValuePublisher<HomeserverReachability, Never>?) {
|
||||||
self.mediaLoader = mediaLoader
|
self.mediaLoader = mediaLoader
|
||||||
self.imageCache = imageCache
|
self.imageCache = imageCache
|
||||||
self.homeserverReachabilityPublisher = homeserverReachabilityPublisher
|
self.homeserverReachabilityPublisher = homeserverReachabilityPublisher
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import Testing
|
|||||||
struct MediaProviderTests {
|
struct MediaProviderTests {
|
||||||
private var mediaLoader: MediaLoaderMock
|
private var mediaLoader: MediaLoaderMock
|
||||||
private var imageCache: MockImageCache
|
private var imageCache: MockImageCache
|
||||||
private var reachabilitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable)
|
private var reachabilitySubject = CurrentValueSubject<HomeserverReachability, Never>(.reachable)
|
||||||
|
|
||||||
var mediaProvider: MediaProvider!
|
var mediaProvider: MediaProvider!
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ struct MediaProviderTests {
|
|||||||
|
|
||||||
mediaLoader.loadMediaContentForSourceClosure = { [reachabilitySubject] _ in
|
mediaLoader.loadMediaContentForSourceClosure = { [reachabilitySubject] _ in
|
||||||
switch reachabilitySubject.value {
|
switch reachabilitySubject.value {
|
||||||
case .unreachable:
|
case .unreachable, .suspended:
|
||||||
reachabilitySubject.send(.reachable)
|
reachabilitySubject.send(.reachable)
|
||||||
throw MediaProviderTestsError.error
|
throw MediaProviderTestsError.error
|
||||||
case .reachable:
|
case .reachable:
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ struct SecureBackupLogoutConfirmationScreenViewModelTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var secureBackupController: SecureBackupControllerMock
|
private var secureBackupController: SecureBackupControllerMock
|
||||||
private var reachabilitySubject: CurrentValueSubject<NetworkMonitorReachability, Never>
|
private var reachabilitySubject: CurrentValueSubject<HomeserverReachability, Never>
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
secureBackupController = SecureBackupControllerMock()
|
secureBackupController = SecureBackupControllerMock()
|
||||||
secureBackupController.keyBackupState = CurrentValueSubject<SecureBackupKeyBackupState, Never>(.enabled).asCurrentValuePublisher()
|
secureBackupController.keyBackupState = CurrentValueSubject<SecureBackupKeyBackupState, Never>(.enabled).asCurrentValuePublisher()
|
||||||
|
|
||||||
reachabilitySubject = CurrentValueSubject<NetworkMonitorReachability, Never>(.reachable)
|
reachabilitySubject = CurrentValueSubject<HomeserverReachability, Never>(.reachable)
|
||||||
|
|
||||||
viewModel = SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: secureBackupController,
|
viewModel = SecureBackupLogoutConfirmationScreenViewModel(secureBackupController: secureBackupController,
|
||||||
homeserverReachabilityPublisher: reachabilitySubject.asCurrentValuePublisher())
|
homeserverReachabilityPublisher: reachabilitySubject.asCurrentValuePublisher())
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ struct UserSessionFlowCoordinatorTests {
|
|||||||
private let stateMachineFactory = PublishedStateMachineFactory()
|
private let stateMachineFactory = PublishedStateMachineFactory()
|
||||||
|
|
||||||
private let networkReachabilitySubject: CurrentValueSubject<NetworkMonitorReachability, Never> = .init(.reachable)
|
private let networkReachabilitySubject: CurrentValueSubject<NetworkMonitorReachability, Never> = .init(.reachable)
|
||||||
private let homeserverReachabilitySubject: CurrentValueSubject<NetworkMonitorReachability, Never> = .init(.reachable)
|
private let homeserverReachabilitySubject: CurrentValueSubject<HomeserverReachability, Never> = .init(.reachable)
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
private var tabCoordinator: NavigationTabCoordinator<UserSessionFlowCoordinator.HomeTab>? {
|
private var tabCoordinator: NavigationTabCoordinator<UserSessionFlowCoordinator.HomeTab>? {
|
||||||
@@ -228,6 +228,14 @@ struct UserSessionFlowCoordinatorTests {
|
|||||||
// Then the indicator should be hidden now as everything is back to normal
|
// Then the indicator should be hidden now as everything is back to normal
|
||||||
#expect(userIndicatorController.submitIndicatorDelayCallsCount == 3)
|
#expect(userIndicatorController.submitIndicatorDelayCallsCount == 3)
|
||||||
#expect(retractReachabilityIndicatorCallsCount == 2)
|
#expect(retractReachabilityIndicatorCallsCount == 2)
|
||||||
|
|
||||||
|
// When the client is suspended.
|
||||||
|
homeserverReachabilitySubject.send(.suspended)
|
||||||
|
try await Task.sleep(for: .milliseconds(100))
|
||||||
|
|
||||||
|
// Then no unreachable indicator should be shown as the pause is intentional.
|
||||||
|
#expect(userIndicatorController.submitIndicatorDelayCallsCount == 3)
|
||||||
|
#expect(retractReachabilityIndicatorCallsCount == 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Helpers
|
// MARK: - Helpers
|
||||||
|
|||||||
Reference in New Issue
Block a user