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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 8 deletions

View File

@ -374,6 +374,7 @@
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
C4F784AABFF44E4716E7A8BC /* RoomDetailsViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B3A76EA6AB67910C11330F /* RoomDetailsViewModelProtocol.swift */; };
C55A44C99F64A479ABA85B46 /* RoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */; };
C6136E848E55D2C86BF760F5 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */; };
C74EE50257ED925C2B8EFCE6 /* MockSoftLogoutScreenState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B869438A1B52836F912A702 /* MockSoftLogoutScreenState.swift */; };
C76892321558E75101E68ED6 /* ReadableFrameModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */; };
C7B251DC896C0867C51B616D /* AnalyticsPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541542F5AC323709D8563458 /* AnalyticsPrompt.swift */; };
@ -915,6 +916,7 @@
C687844F60BFF532D49A994C /* AnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = "<group>"; };
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportUITests.swift; sourceTree = "<group>"; };
C75EF87651B00A176AB08E97 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; };
C88508B6F7974CFABEC4B261 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
C888BCD78E2A55DCE364F160 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
@ -2142,6 +2144,7 @@
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */,
6A580295A56B55A856CC4084 /* InfoPlistReader.swift */,
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
BB3073CCD77D906B330BC1D6 /* Tests.swift */,
@ -3008,6 +3011,7 @@
FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */,
71C1347F23868324A4F43940 /* NavigationModule.swift in Sources */,
B5E455C9689EA600EDB3E9E0 /* NavigationRootCoordinator.swift in Sources */,
C6136E848E55D2C86BF760F5 /* NetworkMonitor.swift in Sources */,
8BBD3AA589DEE02A1B0923B2 /* NoticeRoomTimelineItem.swift in Sources */,
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */,
3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */,

View File

@ -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

View File

@ -32,4 +32,10 @@ class ServiceLocator {
func register(appSettings: AppSettings) {
settings = appSettings
}
private(set) var networkMonitor: NetworkMonitor!
func register(networkMonitor: NetworkMonitor) {
self.networkMonitor = networkMonitor
}
}

View File

@ -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)
}
}

View File

@ -120,7 +120,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
func stop() {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()
state.contextMenuBuilder = nil
}

1
changelog.d/258.feature Normal file
View File

@ -0,0 +1 @@
Display an indicator if the network is currently unreachable