// // FocusedAttachmentController.swift // ComposeUI // // Created by Shadowfacts on 4/29/23. // import SwiftUI import MatchedGeometryPresentation class FocusedAttachmentController: ViewController { unowned let parent: ComposeController let attachment: DraftAttachment let thumbnailController: AttachmentThumbnailController init(parent: ComposeController, attachment: DraftAttachment, thumbnailController: AttachmentThumbnailController) { self.parent = parent self.attachment = attachment self.thumbnailController = thumbnailController } var view: some View { FocusedAttachmentView(attachment: attachment) } struct FocusedAttachmentView: View { @ObservedObject var attachment: DraftAttachment @EnvironmentObject private var controller: FocusedAttachmentController @Environment(\.dismiss) private var dismiss @FocusState private var textEditorFocused: Bool @EnvironmentObject private var matchedGeomState: MatchedGeometryState var body: some View { VStack(spacing: 0) { Spacer(minLength: 0) let attachmentView = ControllerView(controller: { controller.thumbnailController }) .environment(\.attachmentThumbnailConfiguration, .init(contentMode: .fit, fullSize: true)) .matchedGeometryDestination(id: attachment.id) if #available(iOS 16.0, *) { ZoomableScrollView { attachmentView } } else { attachmentView } Spacer(minLength: 0) FocusedAttachmentDescriptionView(attachment: attachment) .environment(\.colorScheme, .dark) .matchedGeometryDestination(id: AttachmentDescriptionTextViewID(attachment)) .frame(height: 150) .focused($textEditorFocused) } .background(.black) .overlay(alignment: .topLeading, content: { Button { // set the mode to dismissing immediately, so that layout changes due to the keyboard hiding // (which happens before the dismiss animation controller starts running) don't alter the destination frames if textEditorFocused { matchedGeomState.mode = .dismissing } dismiss() } label: { Image(systemName: "arrow.down.forward.and.arrow.up.backward") } .buttonStyle(DismissFocusedAttachmentButtonStyle()) .padding([.top, .leading], 4) }) } } } private struct DismissFocusedAttachmentButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { ZStack { RoundedRectangle(cornerRadius: 4) .fill(.black.opacity(0.5)) configuration.label .foregroundColor(.white) .imageScale(.large) } .frame(width: 40, height: 40) } } struct AttachmentDescriptionTextViewID: Hashable { let attachmentID: UUID init(_ attachment: DraftAttachment) { self.attachmentID = attachment.id } func hash(into hasher: inout Hasher) { hasher.combine(attachmentID) hasher.combine("descriptionTextView") } }