session-ios/Session/Path/PathStatusView.swift
Morgan Pretty d020a7a05f Fixed a couple of reachability oddities and bugs
Updated the PathVC to indicate the network reachability
Updated messages sent to 'Note to Self' to properly indicate whether they were sent to the swarm
Fixed an issue where 'Note to Self' messages weren't actually getting sent to the swarm
2023-02-10 17:36:40 +11:00

158 lines
4.4 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import Reachability
import SessionUIKit
import SessionSnodeKit
final class PathStatusView: UIView {
enum Size {
case small
case large
var pointSize: CGFloat {
switch self {
case .small: return 8
case .large: return 16
}
}
func offset(for interfaceStyle: UIUserInterfaceStyle) -> CGFloat {
switch self {
case .small: return (interfaceStyle == .light ? 6 : 8)
case .large: return (interfaceStyle == .light ? 6 : 8)
}
}
}
enum Status {
case unknown
case connecting
case connected
case error
var themeColor: ThemeValue {
switch self {
case .unknown: return .path_unknown
case .connecting: return .path_connecting
case .connected: return .path_connected
case .error: return .path_error
}
}
}
// MARK: - Initialization
private let size: Size
private let reachability: Reachability = Reachability.forInternetConnection()
init(size: Size = .small) {
self.size = size
super.init(frame: .zero)
setUpViewHierarchy()
registerObservers()
}
required init?(coder: NSCoder) {
self.size = .small
super.init(coder: coder)
setUpViewHierarchy()
registerObservers()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: - Layout
private func setUpViewHierarchy() {
layer.cornerRadius = (self.size.pointSize / 2)
layer.masksToBounds = false
self.set(.width, to: self.size.pointSize)
self.set(.height, to: self.size.pointSize)
switch (reachability.isReachable(), OnionRequestAPI.paths.isEmpty) {
case (false, _): setStatus(to: .error)
case (true, true): setStatus(to: .connecting)
case (true, false): setStatus(to: .connected)
}
}
// MARK: - Functions
private func registerObservers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handleBuildingPathsNotification),
name: .buildingPaths,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(handlePathsBuiltNotification),
name: .pathsBuilt,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged),
name: .reachabilityChanged,
object: nil
)
}
private func setStatus(to status: Status) {
themeBackgroundColor = status.themeColor
layer.themeShadowColor = status.themeColor
layer.shadowOffset = CGSize(width: 0, height: 0.8)
layer.shadowPath = UIBezierPath(
ovalIn: CGRect(
origin: CGPoint.zero,
size: CGSize(width: self.size.pointSize, height: self.size.pointSize)
)
).cgPath
ThemeManager.onThemeChange(observer: self) { [weak self] theme, _ in
self?.layer.shadowOpacity = (theme.interfaceStyle == .light ? 0.4 : 1)
self?.layer.shadowRadius = (self?.size.offset(for: theme.interfaceStyle) ?? 0)
}
}
@objc private func handleBuildingPathsNotification() {
guard reachability.isReachable() else {
setStatus(to: .error)
return
}
setStatus(to: .connecting)
}
@objc private func handlePathsBuiltNotification() {
guard reachability.isReachable() else {
setStatus(to: .error)
return
}
setStatus(to: .connected)
}
@objc private func reachabilityChanged() {
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in self?.reachabilityChanged() }
return
}
guard reachability.isReachable() else {
setStatus(to: .error)
return
}
setStatus(to: (!OnionRequestAPI.paths.isEmpty ? .connected : .connecting))
}
}