Skip to content

Commit

Permalink
Fix internet is offline error issue
Browse files Browse the repository at this point in the history
  • Loading branch information
dmigach committed Apr 13, 2021
1 parent 4a0b0a3 commit 90c45a1
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 34 deletions.
61 changes: 29 additions & 32 deletions DemoApp/BannerShowingConnectionDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ final class BannerShowingConnectionDelegate {
// MARK: - Private Properties

private let navigationController: UINavigationController
private var connectionEstablishmentTime: Date?
private let bannerView = BannerView()
private let bannerAppearanceDuration: TimeInterval = 0.5

// MARK: -

init(navigationController: UINavigationController) {
self.navigationController = navigationController
setupViews(superview: navigationController.view)
}
}

Expand All @@ -23,19 +25,13 @@ final class BannerShowingConnectionDelegate {
extension BannerShowingConnectionDelegate: ChatConnectionControllerDelegate {
public func connectionController(_ controller: ChatConnectionController, didUpdateConnectionStatus status: ConnectionStatus) {
switch status {
case .disconnected:
showBanner()
case .connected:
connectionEstablishmentTime = Date()
case .disconnecting:
break
case .connecting:
if let time = connectionEstablishmentTime {
let elapsedTime = time.distance(to: Date())
if elapsedTime > 5 {
// TODO: We need to reset the property we make desicion on whether to show the banner or not
showBanner()
}
}
case .disconnected, .initialized:
hideBanner()
case .initialized,
.disconnecting,
.connecting:
break
}
}
Expand All @@ -44,30 +40,31 @@ extension BannerShowingConnectionDelegate: ChatConnectionControllerDelegate {
// MARK: - Private Methods

private extension BannerShowingConnectionDelegate {
func showBanner() {
guard let view = navigationController.topViewController?.view else { return }
let bannerView = BannerView()
view.addSubview(bannerView)
bannerView.alpha = 0
bannerView.update(text: "Reconnecting...")

UIView.animate(withDuration: 0.5) {
bannerView.alpha = 1
}
func setupViews(superview: UIView) {
bannerView.isHidden = true
superview.addSubview(bannerView)

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
UIView.animate(withDuration: 1) {
bannerView.alpha = 0
} completion: { _ in
bannerView.removeFromSuperview()
}
}

let guide = view.safeAreaLayoutGuide
let guide = superview.safeAreaLayoutGuide
NSLayoutConstraint.activate(
[
bannerView.topAnchor.constraint(equalTo: guide.topAnchor)
]
)

bannerView.update(text: "Connecting...")
}

func showBanner() {
animateBannerAlpha(to: 1)
}

func hideBanner() {
animateBannerAlpha(to: 0)
}

func animateBannerAlpha(to value: CGFloat) {
UIView.animate(withDuration: bannerAppearanceDuration) {
self.bannerView.alpha = value
}
}
}
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ var streamChatSourcesExcluded: [String] { [
"Utils/Database/NSManagedObject_Tests.swift",
"Utils/MulticastDelegate_Tests.swift",
"Utils/InternetConnection/InternetConnection_Tests.swift",
"Utils/InternetConnection/Error+InternetNotAvailable_Tests.swift",
"Utils/Atomic_Tests.swift",
"Utils/LazyCachedMapCollection_Tests.swift",
"Utils/Dictionary_Tests.swift",
Expand Down
2 changes: 1 addition & 1 deletion Sources/StreamChat/ChatClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public class _ChatClient<ExtraData: ExtraDataTypes> {
/// required header auth parameters to make a successful request.
private var urlSessionConfiguration: URLSessionConfiguration {
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
config.waitsForConnectivity = false
config.httpAdditionalHeaders = sessionHeaders
return config
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ private let offlineErrors: [(domain: String, errorCode: Int)] = [
extension Error {
/// Returns `true` if the error is one of the known errors for internet connection not being available.
var isInternetOfflineError: Bool {
let engineError = (self as? WebSocketEngineError)?.engineError
return offlineErrors.contains {
self.has(parameters: $0) || (engineError?.has(parameters: $0) ?? false)
}
}

private func has(parameters: (domain: String, errorCode: Int)) -> Bool {
let error = self as NSError
return offlineErrors.contains { $0.domain == error.domain && $0.errorCode == error.code }
return error.domain == parameters.domain && error.code == parameters.errorCode
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// Copyright © 2021 Stream.io Inc. All rights reserved.
//

@testable import StreamChat
import XCTest

final class ErrorInternetNotAvailable_Tests: XCTestCase {
func test_errorIsNSURLErrorNotConnectedToInternet() throws {
let error = NSError(
domain: NSURLErrorDomain,
code: NSURLErrorNotConnectedToInternet,
userInfo: nil
)

XCTAssertTrue(error.isInternetOfflineError)
}

func test_errorIsNSPOSIXErrorDomain50() throws {
let error = NSError(
domain: NSPOSIXErrorDomain,
code: 50,
userInfo: nil
)

XCTAssertTrue(error.isInternetOfflineError)
}

func test_errorDomainIsNotOneOfInternetOfflineError() throws {
let error = NSError(
domain: "Some domain",
code: 50,
userInfo: nil
)

XCTAssertFalse(error.isInternetOfflineError)
}

func test_errorCodeIsNotOneOfInternetOfflineError() throws {
let error = NSError(
domain: NSURLErrorDomain,
code: 50,
userInfo: nil
)

XCTAssertFalse(error.isInternetOfflineError)
}

func test_websocketEngineErrorInternetIsOffline() throws {
let error = WebSocketEngineError(
reason: "",
code: -1009,
engineError: NSError(
domain: NSURLErrorDomain,
code: NSURLErrorNotConnectedToInternet,
userInfo: nil
)
)

XCTAssertTrue(error.isInternetOfflineError)
}

func test_websocketEngineErrorDomainIsNotInternetIsOffline() throws {
let error = WebSocketEngineError(
reason: "",
code: 304,
engineError: NSError(
domain: "Some domain",
code: NSURLErrorNotConnectedToInternet,
userInfo: nil
)
)

XCTAssertFalse(error.isInternetOfflineError)
}

func test_websocketEngineErrorCodeIsNotInternetIsOffline() throws {
let error = WebSocketEngineError(
reason: "",
code: 304,
engineError: NSError(
domain: NSURLErrorDomain,
code: 304,
userInfo: nil
)
)

XCTAssertFalse(error.isInternetOfflineError)
}
}
4 changes: 4 additions & 0 deletions StreamChat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
6428DD5526201DCC0065DA1D /* BannerShowingConnectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6428DD5426201DCC0065DA1D /* BannerShowingConnectionDelegate.swift */; };
647F66D5261E22C200111B19 /* BannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F66D4261E22C200111B19 /* BannerView.swift */; };
648EC576261EF9D400B8F05F /* DemoAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648EC575261EF9D400B8F05F /* DemoAppCoordinator.swift */; };
64F70D4B26257FD400C9F979 /* Error+InternetNotAvailable_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F70D4A26257FD400C9F979 /* Error+InternetNotAvailable_Tests.swift */; };
6971257E260CA503003C7B47 /* NSManagedObjectContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6971256C260CA4CB003C7B47 /* NSManagedObjectContext+Extensions.swift */; };
697C6F90260CFA37000E9023 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69712522260BC9B4003C7B47 /* Deprecations.swift */; };
780057FF25F6353600D21095 /* ChatChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780057F625F634FC00D21095 /* ChatChannel.swift */; };
Expand Down Expand Up @@ -1173,6 +1174,7 @@
6428DD5426201DCC0065DA1D /* BannerShowingConnectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerShowingConnectionDelegate.swift; sourceTree = "<group>"; };
647F66D4261E22C200111B19 /* BannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerView.swift; sourceTree = "<group>"; };
648EC575261EF9D400B8F05F /* DemoAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppCoordinator.swift; sourceTree = "<group>"; };
64F70D4A26257FD400C9F979 /* Error+InternetNotAvailable_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+InternetNotAvailable_Tests.swift"; sourceTree = "<group>"; };
69712522260BC9B4003C7B47 /* Deprecations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecations.swift; sourceTree = "<group>"; };
6971256C260CA4CB003C7B47 /* NSManagedObjectContext+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Extensions.swift"; sourceTree = "<group>"; };
698E2A3425F7C8AF00ED9CCC /* APIPathConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIPathConvertible.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3847,6 +3849,7 @@
8AE335A424FCF999002B6677 /* InternetConnection_Tests.swift */,
8AE335A524FCF999002B6677 /* Reachability_Vendor.swift */,
79200D4B25025B81002F4EB1 /* Error+InternetNotAvailable.swift */,
64F70D4A26257FD400C9F979 /* Error+InternetNotAvailable_Tests.swift */,
);
path = InternetConnection;
sourceTree = "<group>";
Expand Down Expand Up @@ -5294,6 +5297,7 @@
8A62705E24BE2CD70040BFD6 /* XCTestCase+MockJSON.swift in Sources */,
DA84074B2526417B005A0F62 /* JSONEncoder+Extensions.swift in Sources */,
88381E6E258259310047A6A3 /* FileUploadPayload_Tests.swift in Sources */,
64F70D4B26257FD400C9F979 /* Error+InternetNotAvailable_Tests.swift in Sources */,
F63CC37124E591990052844D /* EventObserver_Tests.swift in Sources */,
22CAFA7625CAE278005935D9 /* RawJSON_Tests.swift in Sources */,
795297062583B52000435B2E /* UserSearchController_Tests.swift in Sources */,
Expand Down

0 comments on commit 90c45a1

Please sign in to comment.