// // Swiftfin is subject to the terms of the Mozilla Public // License, v2.0. If a copy of the MPL was not distributed with this // file, you can obtain one at https://mozilla.org/MPL/2.0/. // // Copyright (c) 2023 Jellyfin & Jellyfin Contributors // import SwiftUI struct NavBarDrawerView: UIViewControllerRepresentable { private let buttons: () -> any View private let content: () -> any View init( @ViewBuilder buttons: @escaping () -> any View, @ViewBuilder content: @escaping () -> any View ) { self.buttons = buttons self.content = content } func makeUIViewController(context: Context) -> UINavBarDrawerHostingController { UINavBarDrawerHostingController(buttons: buttons, content: content) } func updateUIViewController(_ uiViewController: UINavBarDrawerHostingController, context: Context) {} } class UINavBarDrawerHostingController: UIViewController { private let buttons: () -> any View private let content: () -> any View private let drawerHeight: CGFloat = 36 private lazy var navBarBlurView: UIVisualEffectView = { let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThinMaterial)) blurView.translatesAutoresizingMaskIntoConstraints = false return blurView }() private lazy var contentView: UIHostingController = { let contentView = UIHostingController(rootView: content().eraseToAnyView()) contentView.view.translatesAutoresizingMaskIntoConstraints = false contentView.view.backgroundColor = nil return contentView }() private lazy var drawerButtonsView: UIHostingController = { let drawerButtonsView = UIHostingController(rootView: buttons().eraseToAnyView()) drawerButtonsView.view.translatesAutoresizingMaskIntoConstraints = false drawerButtonsView.view.backgroundColor = nil return drawerButtonsView }() init( buttons: @escaping () -> any View, content: @escaping () -> any View ) { self.buttons = buttons self.content = content super.init(nibName: nil, bundle: nil) } @available(*, unavailable) required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = nil addChild(contentView) view.addSubview(contentView.view) contentView.didMove(toParent: self) view.addSubview(navBarBlurView) addChild(drawerButtonsView) view.addSubview(drawerButtonsView.view) drawerButtonsView.didMove(toParent: self) NSLayoutConstraint.activate([ drawerButtonsView.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -drawerHeight), drawerButtonsView.view.heightAnchor.constraint(equalToConstant: drawerHeight), drawerButtonsView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), drawerButtonsView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), ]) NSLayoutConstraint.activate([ navBarBlurView.topAnchor.constraint(equalTo: view.topAnchor), navBarBlurView.bottomAnchor.constraint(equalTo: drawerButtonsView.view.bottomAnchor), navBarBlurView.leadingAnchor.constraint(equalTo: view.leadingAnchor), navBarBlurView.trailingAnchor.constraint(equalTo: view.trailingAnchor), ]) NSLayoutConstraint.activate([ contentView.view.topAnchor.constraint(equalTo: view.topAnchor), contentView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), contentView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), contentView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), ]) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) navigationController?.navigationBar.shadowImage = UIImage() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.navigationBar.setBackgroundImage(nil, for: .default) navigationController?.navigationBar.shadowImage = nil } override var additionalSafeAreaInsets: UIEdgeInsets { get { .init(top: drawerHeight, left: 0, bottom: 0, right: 0) } set { super.additionalSafeAreaInsets = .init(top: drawerHeight, left: 0, bottom: 0, right: 0) } } }