80 lines
2.5 KiB
Swift
80 lines
2.5 KiB
Swift
import SwiftUI
|
|
import PhotosUI
|
|
import Bedrock
|
|
|
|
/// A combined photo picker and cropper flow.
|
|
/// Shows the system PhotosPicker, and when an image is selected,
|
|
/// immediately overlays the cropper. Both dismiss together when done.
|
|
struct PhotoPickerWithCropper: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
let onSave: (Data) -> Void
|
|
let onCancel: () -> Void
|
|
|
|
@State private var selectedItem: PhotosPickerItem?
|
|
@State private var imageData: Data?
|
|
@State private var showingCropper = false
|
|
|
|
var body: some View {
|
|
PhotosPicker(
|
|
selection: $selectedItem,
|
|
matching: .images,
|
|
photoLibrary: .shared()
|
|
) {
|
|
// This is never shown - we use it in inline mode
|
|
EmptyView()
|
|
}
|
|
.photosPickerStyle(.inline)
|
|
.photosPickerDisabledCapabilities([.selectionActions])
|
|
.ignoresSafeArea()
|
|
.onChange(of: selectedItem) { _, newValue in
|
|
guard let newValue else { return }
|
|
Task { @MainActor in
|
|
if let data = try? await newValue.loadTransferable(type: Data.self) {
|
|
imageData = data
|
|
showingCropper = true
|
|
}
|
|
}
|
|
}
|
|
.overlay {
|
|
// Cropper overlay
|
|
if showingCropper, let imageData {
|
|
PhotoCropperSheet(
|
|
imageData: imageData,
|
|
shouldDismissOnComplete: false
|
|
) { croppedData in
|
|
if let croppedData {
|
|
onSave(croppedData)
|
|
} else {
|
|
// User cancelled cropper, go back to picker
|
|
showingCropper = false
|
|
self.imageData = nil
|
|
self.selectedItem = nil
|
|
}
|
|
}
|
|
.transition(.move(edge: .trailing))
|
|
}
|
|
}
|
|
.animation(.easeInOut(duration: Design.Animation.quick), value: showingCropper)
|
|
.toolbar {
|
|
// Only show cancel when cropper is NOT showing (cropper has its own toolbar)
|
|
if !showingCropper {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button(String.localized("Cancel")) {
|
|
onCancel()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
NavigationStack {
|
|
PhotoPickerWithCropper(
|
|
onSave: { _ in print("Saved") },
|
|
onCancel: { print("Cancelled") }
|
|
)
|
|
}
|
|
}
|