Fixes #258 - Display an indicator if the network is currently unreachable (#379)

This commit is contained in:
Stefan Ceriu
2022-12-19 18:29:14 +02:00
committed by GitHub
parent e0e2d26b4b
commit 39fcd3b9c9
6 changed files with 81 additions and 8 deletions
@@ -47,6 +47,7 @@ class AppCoordinator: AppCoordinatorProtocol {
private let bugReportService: BugReportServiceProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol
private var userSessionCancellables = Set<AnyCancellable>()
private var cancellables = Set<AnyCancellable>()
private(set) var notificationManager: NotificationManagerProtocol?
@@ -79,9 +80,8 @@ class AppCoordinator: AppCoordinatorProtocol {
Bundle.elementFallbackLanguage = "en"
startObservingApplicationState()
// Benchmark.trackingEnabled = true
observeApplicationState()
observeNetworkState()
}
func start() {
@@ -101,6 +101,7 @@ class AppCoordinator: AppCoordinatorProtocol {
private static func setupServiceLocator(navigationRootCoordinator: NavigationRootCoordinator) {
ServiceLocator.shared.register(userNotificationController: UserNotificationController(rootCoordinator: navigationRootCoordinator))
ServiceLocator.shared.register(appSettings: AppSettings())
ServiceLocator.shared.register(networkMonitor: NetworkMonitor())
}
private static func setupLogging() {
@@ -329,12 +330,11 @@ class AppCoordinator: AppCoordinatorProtocol {
break
}
}
.store(in: &cancellables)
.store(in: &userSessionCancellables)
}
private func deobserveUserSessionChanges() {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()
userSessionCancellables.removeAll()
}
// MARK: Toasts and loading indicators
@@ -366,7 +366,7 @@ class AppCoordinator: AppCoordinatorProtocol {
userSession?.clientProxy.startSync()
}
private func startObservingApplicationState() {
private func observeApplicationState() {
NotificationCenter.default.addObserver(self,
selector: #selector(applicationWillResignActive),
name: UIApplication.willResignActiveNotification,
@@ -401,6 +401,19 @@ class AppCoordinator: AppCoordinatorProtocol {
resume()
}
}
private func observeNetworkState() {
let reachabilityNotificationIdentifier = "io.element.elementx.reachability.notification"
ServiceLocator.shared.networkMonitor.reachabilityPublisher.sink { reachable in
if reachable {
ServiceLocator.shared.userNotificationController.retractNotificationWithId(reachabilityNotificationIdentifier)
} else {
ServiceLocator.shared.userNotificationController.submitNotification(.init(id: reachabilityNotificationIdentifier,
title: ElementL10n.a11yPresenceOffline,
persistent: true))
}
}.store(in: &cancellables)
}
}
// MARK: - AuthenticationCoordinatorDelegate
@@ -32,4 +32,10 @@ class ServiceLocator {
func register(appSettings: AppSettings) {
settings = appSettings
}
private(set) var networkMonitor: NetworkMonitor!
func register(networkMonitor: NetworkMonitor) {
self.networkMonitor = networkMonitor
}
}
@@ -0,0 +1,50 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Combine
import Foundation
import Network
class NetworkMonitor {
private let pathMonitor: NWPathMonitor
private let queue: DispatchQueue
let reachabilityPublisher: CurrentValueSubject<Bool, Never>
var isCurrentConnectionExpensive: Bool {
pathMonitor.currentPath.isExpensive
}
var isCurrentConnectionConstrained: Bool {
pathMonitor.currentPath.isConstrained
}
init() {
queue = DispatchQueue(label: "io.element.elementx.networkmonitor")
pathMonitor = NWPathMonitor()
reachabilityPublisher = CurrentValueSubject<Bool, Never>(pathMonitor.currentPath.status == .satisfied)
pathMonitor.pathUpdateHandler = { [weak self] path in
DispatchQueue.main.async {
if path.status == .satisfied {
self?.reachabilityPublisher.send(true)
} else {
self?.reachabilityPublisher.send(false)
}
}
}
pathMonitor.start(queue: queue)
}
}
@@ -120,7 +120,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
func stop() {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()
state.contextMenuBuilder = nil
}