From c6e06fe9f3d761c419e8ded35bcb9b2be01b2caf Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 28 Jun 2022 17:27:41 -0700 Subject: [PATCH] Use SwiftUI for sheet presentation detents on iOS 16 --- .../Compose/ComposeAttachmentsList.swift | 51 ++++++++++++++++++- Tusker/Screens/Compose/ComposeUIState.swift | 1 + 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Tusker/Screens/Compose/ComposeAttachmentsList.swift b/Tusker/Screens/Compose/ComposeAttachmentsList.swift index b83e39ab..0576f688 100644 --- a/Tusker/Screens/Compose/ComposeAttachmentsList.swift +++ b/Tusker/Screens/Compose/ComposeAttachmentsList.swift @@ -50,7 +50,7 @@ struct ComposeAttachmentsList: View { .disabled(!canAddAttachment) .foregroundColor(.blue) .frame(height: cellHeight / 2) - .popover(isPresented: $isShowingAssetPickerPopover, content: self.assetPickerPopover) + .sheetOrPopover(isPresented: $isShowingAssetPickerPopover, content: self.assetPickerPopover) .listRowInsets(EdgeInsets(top: cellPadding / 2, leading: cellPadding / 2, bottom: cellPadding / 2, trailing: cellPadding / 2)) Button(action: self.createDrawing) { @@ -134,14 +134,21 @@ struct ComposeAttachmentsList: View { private func assetPickerPopover() -> some View { ComposeAssetPicker(draft: draft, delegate: uiState.delegate?.assetPickerDelegate) .onDisappear { + // on iPadOS 16, this is necessary to dismiss the popover when collapsing from regular -> compact size class + // otherwise, the popover isn't visible but it's still "presented", so the sheet can't be shown self.isShowingAssetPickerPopover = false } + // on iPadOS 16, this is necessary to show the dark color in the popover arrow + .background(Color(.systemBackground)) .environment(\.colorScheme, .dark) .edgesIgnoringSafeArea(.bottom) + .withSheetDetentsIfAvailable() } private func addAttachment() { - if horizontalSizeClass == .regular { + if #available(iOS 16.0, *) { + isShowingAssetPickerPopover = true + } else if horizontalSizeClass == .regular { isShowingAssetPickerPopover = true } else { uiState.delegate?.presentAssetPickerSheet() @@ -184,6 +191,7 @@ struct ComposeAttachmentsList: View { } fileprivate extension View { + @available(iOS, obsoleted: 15.0) @ViewBuilder func onDragWithPreviewIfAvailable(_ data: @escaping () -> NSItemProvider, preview: () -> V) -> some View where V : View { if #available(iOS 15.0, *) { @@ -192,6 +200,45 @@ fileprivate extension View { self.onDrag(data) } } + + @available(iOS, obsoleted: 16.0) + @ViewBuilder + func sheetOrPopover(isPresented: Binding, @ViewBuilder content: @escaping () -> some View) -> some View { + if #available(iOS 16.0, *) { + self.modifier(SheetOrPopover(isPresented: isPresented, view: content)) + } else { + self.popover(isPresented: isPresented, content: content) + } + } + + @available(iOS, obsoleted: 16.0) + @ViewBuilder + func withSheetDetentsIfAvailable() -> some View { + if #available(iOS 16.0, *) { + self + .presentationDetents([.medium, .large]) + .presentationDragIndicator(.visible) + } else { + self + } + } +} + +@available(iOS 16.0, *) +struct SheetOrPopover: ViewModifier { + @Binding var isPresented: Bool + @ViewBuilder let view: () -> V + + @Environment(\.horizontalSizeClass) var sizeClass + + func body(content: Content) -> some View { + let _ = print("isPresented: \(isPresented)") + if sizeClass == .compact { + content.sheet(isPresented: $isPresented, content: view) + } else { + content.popover(isPresented: $isPresented, content: view) + } + } } //struct ComposeAttachmentsList_Previews: PreviewProvider { diff --git a/Tusker/Screens/Compose/ComposeUIState.swift b/Tusker/Screens/Compose/ComposeUIState.swift index 0e038b73..4ff53ce5 100644 --- a/Tusker/Screens/Compose/ComposeUIState.swift +++ b/Tusker/Screens/Compose/ComposeUIState.swift @@ -12,6 +12,7 @@ protocol ComposeUIStateDelegate: AnyObject { var assetPickerDelegate: AssetPickerViewControllerDelegate? { get } func dismissCompose(mode: ComposeUIState.DismissMode) + // @available(iOS, obsoleted: 16.0) func presentAssetPickerSheet() func presentComposeDrawing()