// 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(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) ) } } extension Binding { public func onChange(_ handler: @escaping (Value) -> Void) -> Binding { Binding( get: { self.wrappedValue }, set: { newValue in handler(newValue) self.wrappedValue = newValue } ) } }