mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			158 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			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))
 | |
|     }
 | |
| }
 |