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.
		
		
		
		
		
			
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Swift
		
	
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
 | 
						|
 | 
						|
import UIKit
 | 
						|
import Reachability
 | 
						|
import SessionUIKit
 | 
						|
 | 
						|
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))
 | 
						|
    }
 | 
						|
}
 |