Skip to content

Commit

Permalink
Always popover
Browse files Browse the repository at this point in the history
  • Loading branch information
michele-theleftbit committed Jun 21, 2024
1 parent 27d3c64 commit 7efbe95
Showing 1 changed file with 99 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import SwiftUI

extension View {
func alwaysPopover<Content: View, Value: Identifiable>(id: Value.ID, isPresented: Binding<Value?>, @ViewBuilder content: @escaping () -> Content) -> some View {
self.modifier(AlwaysPopoverModifier(id: id, isPresented: isPresented, contentBlock: content))
}

}

private struct AlwaysPopoverModifier<PopoverContent: View, Value: Identifiable>: ViewModifier {

let id: Value.ID
let isPresented: Binding<Value?>
let contentBlock: () -> PopoverContent
@State private var anchorView = UIView()

Check failure on line 15 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

cannot find 'UIView' in scope

func body(content: Content) -> some View {
if let value = isPresented.wrappedValue, value.id == id {
presentPopover(value: value)
}

return content
.background(InternalAnchorView(uiView: anchorView))
}

func presentPopover(value: Value) {
let contentController = ContentViewController(
// Ensures the text wraps to fit the content
rootView: contentBlock()
.fixedSize(horizontal: false, vertical: true),
isPresented: isPresented
)
contentController.modalPresentationStyle = .popover

let view = anchorView
guard let popover = contentController.popoverPresentationController else { return }
popover.sourceView = view
popover.sourceRect = view.bounds
popover.delegate = contentController

guard let sourceVC = view.next() as UIViewController? else { return }
sourceVC.present(contentController, animated: true)
}

struct InternalAnchorView: UIViewRepresentable {

Check failure on line 45 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

cannot find type 'UIViewRepresentable' in scope
let uiView: UIView

Check failure on line 46 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

cannot find type 'UIView' in scope

func makeUIView(context: Self.Context) -> UIView {

Check failure on line 48 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

cannot find type 'UIView' in scope

Check failure on line 48 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

'Context' is not a member type of struct 'BSWInterfaceKit.AlwaysPopoverModifier<PopoverContent, Value>.InternalAnchorView'
uiView
}

func updateUIView(_ uiView: UIView, context: Self.Context) { }

Check failure on line 52 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

cannot find type 'UIView' in scope

Check failure on line 52 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

'Context' is not a member type of struct 'BSWInterfaceKit.AlwaysPopoverModifier<PopoverContent, Value>.InternalAnchorView'
}

class ContentViewController<FinalView: View>: UIHostingController<FinalView>, UIPopoverPresentationControllerDelegate {

var isPresented: Binding<Value?>

init(rootView: FinalView, isPresented: Binding<Value?>) {
self.isPresented = isPresented
super.init(rootView: rootView)
}

@preconcurrency required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {

Check failure on line 68 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

method does not override any method from its superclass
super.viewDidLoad()
updatePreferredContentSize()
}

override func viewDidLayoutSubviews() {

Check failure on line 73 in Sources/BSWInterfaceKit/SwiftUI/Extensions/SwiftUI+AlwaysPopover.swift

View workflow job for this annotation

GitHub Actions / build

method does not override any method from its superclass
super.viewDidLayoutSubviews()
updatePreferredContentSize()
}

private let MaxWidth: CGFloat = 320

private func updatePreferredContentSize() {
let size = view.systemLayoutSizeFitting(
CGSize(width: MaxWidth, height: UIView.layoutFittingCompressedSize.height),
withHorizontalFittingPriority: .required,
verticalFittingPriority: .fittingSizeLevel
)
preferredContentSize = size
}

// MARK: UIPopoverPresentationControllerDelegate

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}

func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
self.isPresented.wrappedValue = nil
}
}
}

0 comments on commit 7efbe95

Please sign in to comment.