|  |  |  | // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import SwiftUI | 
					
						
							|  |  |  | import UIKit | 
					
						
							|  |  |  | import SessionUtilitiesKit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ViewControllerHolder { | 
					
						
							|  |  |  |     weak var value: UIViewController? | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ViewControllerKey: EnvironmentKey { | 
					
						
							|  |  |  |     static var defaultValue: ViewControllerHolder { | 
					
						
							|  |  |  |         return ViewControllerHolder(value: CurrentAppContext().mainWindow?.rootViewController) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension EnvironmentValues { | 
					
						
							|  |  |  |     public var viewController: UIViewController? { | 
					
						
							|  |  |  |         get { return self[ViewControllerKey.self].value } | 
					
						
							|  |  |  |         set { self[ViewControllerKey.self].value = newValue } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension UIViewController { | 
					
						
							|  |  |  |     public func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) { | 
					
						
							|  |  |  |         let toPresent = UIHostingController(rootView: AnyView(EmptyView())) | 
					
						
							|  |  |  |         toPresent.modalPresentationStyle = style | 
					
						
							|  |  |  |         toPresent.rootView = AnyView( | 
					
						
							|  |  |  |             builder() | 
					
						
							|  |  |  |                 .environment(\.viewController, toPresent) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "dismissModal"), object: nil, queue: nil) { [weak toPresent] _ in | 
					
						
							|  |  |  |             toPresent?.dismiss(animated: true, completion: nil) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self.present(toPresent, animated: true, completion: nil) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct EdgeBorder: Shape { | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     var width: CGFloat | 
					
						
							|  |  |  |     var edges: [Edge] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     func path(in rect: CGRect) -> Path { | 
					
						
							|  |  |  |         var path = Path() | 
					
						
							|  |  |  |         for edge in edges { | 
					
						
							|  |  |  |             var x: CGFloat { | 
					
						
							|  |  |  |                 switch edge { | 
					
						
							|  |  |  |                 case .top, .bottom, .leading: return rect.minX | 
					
						
							|  |  |  |                 case .trailing: return rect.maxX - width | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             var y: CGFloat { | 
					
						
							|  |  |  |                 switch edge { | 
					
						
							|  |  |  |                 case .top, .leading, .trailing: return rect.minY | 
					
						
							|  |  |  |                 case .bottom: return rect.maxY - width | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             var w: CGFloat { | 
					
						
							|  |  |  |                 switch edge { | 
					
						
							|  |  |  |                 case .top, .bottom: return rect.width | 
					
						
							|  |  |  |                 case .leading, .trailing: return self.width | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             var h: CGFloat { | 
					
						
							|  |  |  |                 switch edge { | 
					
						
							|  |  |  |                 case .top, .bottom: return self.width | 
					
						
							|  |  |  |                 case .leading, .trailing: return rect.height | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             path.addPath(Path(CGRect(x: x, y: y, width: w, height: h))) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return path | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension View { | 
					
						
							|  |  |  |     public func border(width: CGFloat, edges: [Edge], color: ThemeValue) -> some View { | 
					
						
							|  |  |  |         overlay( | 
					
						
							|  |  |  |             EdgeBorder(width: width, edges: edges) | 
					
						
							|  |  |  |                 .foregroundColor(themeColor: color) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     public func toastView(message: Binding<String?>) -> some View { | 
					
						
							|  |  |  |         self.modifier(ToastModifier(message: message)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension Binding { | 
					
						
							|  |  |  |     public func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> { | 
					
						
							|  |  |  |         Binding( | 
					
						
							|  |  |  |             get: { self.wrappedValue }, | 
					
						
							|  |  |  |             set: { newValue in | 
					
						
							|  |  |  |                 handler(newValue) | 
					
						
							|  |  |  |                 self.wrappedValue = newValue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |