Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
c2056e719d
commit
9c4d9304e6
@ -46,10 +46,10 @@ struct CardEditorView: View {
|
|||||||
|
|
||||||
// Photo picker state
|
// Photo picker state
|
||||||
@State private var pendingImageType: ImageType? // For showing PhotoSourcePicker
|
@State private var pendingImageType: ImageType? // For showing PhotoSourcePicker
|
||||||
@State private var activeImageType: ImageType? // Tracks which type we're editing through the full flow
|
@State private var nextImageType: ImageType? // Stored when user selects action, used after dismiss
|
||||||
|
@State private var photoPickerImageType: ImageType? // For showing PhotoPickerWithCropper (item-based)
|
||||||
|
@State private var cameraImageType: ImageType? // For showing CameraWithCropper (item-based)
|
||||||
@State private var pendingAction: PendingPhotoAction? // Action to take after source picker dismisses
|
@State private var pendingAction: PendingPhotoAction? // Action to take after source picker dismisses
|
||||||
@State private var showingPhotoPicker = false
|
|
||||||
@State private var showingCamera = false
|
|
||||||
|
|
||||||
private enum PendingPhotoAction {
|
private enum PendingPhotoAction {
|
||||||
case library
|
case library
|
||||||
@ -225,17 +225,18 @@ struct CardEditorView: View {
|
|||||||
}
|
}
|
||||||
.sheet(item: $pendingImageType, onDismiss: {
|
.sheet(item: $pendingImageType, onDismiss: {
|
||||||
// After source picker dismisses, show the appropriate picker
|
// After source picker dismisses, show the appropriate picker
|
||||||
guard let action = pendingAction else { return }
|
guard let action = pendingAction, let imageType = nextImageType else { return }
|
||||||
pendingAction = nil
|
pendingAction = nil
|
||||||
|
nextImageType = nil
|
||||||
|
|
||||||
// Small delay to ensure sheet is fully dismissed
|
// Small delay to ensure sheet is fully dismissed
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
try? await Task.sleep(for: .milliseconds(100))
|
try? await Task.sleep(for: .milliseconds(100))
|
||||||
switch action {
|
switch action {
|
||||||
case .library:
|
case .library:
|
||||||
showingPhotoPicker = true
|
photoPickerImageType = imageType // Triggers fullScreenCover(item:)
|
||||||
case .camera:
|
case .camera:
|
||||||
showingCamera = true
|
cameraImageType = imageType // Triggers fullScreenCover(item:)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) { imageType in
|
}) { imageType in
|
||||||
@ -243,11 +244,11 @@ struct CardEditorView: View {
|
|||||||
title: imageType.title,
|
title: imageType.title,
|
||||||
hasExistingPhoto: hasExistingPhoto(for: imageType),
|
hasExistingPhoto: hasExistingPhoto(for: imageType),
|
||||||
onSelectFromLibrary: {
|
onSelectFromLibrary: {
|
||||||
activeImageType = imageType
|
nextImageType = imageType // Store for use after dismiss
|
||||||
pendingAction = .library
|
pendingAction = .library
|
||||||
},
|
},
|
||||||
onTakePhoto: {
|
onTakePhoto: {
|
||||||
activeImageType = imageType
|
nextImageType = imageType // Store for use after dismiss
|
||||||
pendingAction = .camera
|
pendingAction = .camera
|
||||||
},
|
},
|
||||||
onRemovePhoto: {
|
onRemovePhoto: {
|
||||||
@ -255,33 +256,29 @@ struct CardEditorView: View {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $showingPhotoPicker) {
|
.fullScreenCover(item: $photoPickerImageType) { imageType in
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
PhotoPickerWithCropper(
|
PhotoPickerWithCropper(
|
||||||
aspectRatio: activeImageType?.cropAspectRatio ?? .square,
|
aspectRatio: imageType.cropAspectRatio,
|
||||||
onSave: { croppedData in
|
onSave: { croppedData in
|
||||||
savePhoto(croppedData, for: activeImageType)
|
savePhoto(croppedData, for: imageType)
|
||||||
showingPhotoPicker = false
|
photoPickerImageType = nil
|
||||||
activeImageType = nil
|
|
||||||
},
|
},
|
||||||
onCancel: {
|
onCancel: {
|
||||||
showingPhotoPicker = false
|
photoPickerImageType = nil
|
||||||
activeImageType = nil
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $showingCamera) {
|
.fullScreenCover(item: $cameraImageType) { imageType in
|
||||||
CameraWithCropper(
|
CameraWithCropper(
|
||||||
aspectRatio: activeImageType?.cropAspectRatio ?? .square,
|
aspectRatio: imageType.cropAspectRatio,
|
||||||
onSave: { croppedData in
|
onSave: { croppedData in
|
||||||
savePhoto(croppedData, for: activeImageType)
|
savePhoto(croppedData, for: imageType)
|
||||||
showingCamera = false
|
cameraImageType = nil
|
||||||
activeImageType = nil
|
|
||||||
},
|
},
|
||||||
onCancel: {
|
onCancel: {
|
||||||
showingCamera = false
|
cameraImageType = nil
|
||||||
activeImageType = nil
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -734,8 +731,7 @@ private extension CardEditorView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func savePhoto(_ data: Data, for imageType: ImageType?) {
|
func savePhoto(_ data: Data, for imageType: ImageType) {
|
||||||
guard let imageType else { return }
|
|
||||||
switch imageType {
|
switch imageType {
|
||||||
case .profile: photoData = data
|
case .profile: photoData = data
|
||||||
case .cover: coverPhotoData = data
|
case .cover: coverPhotoData = data
|
||||||
@ -805,6 +801,7 @@ private extension CardEditorView {
|
|||||||
bio: bio,
|
bio: bio,
|
||||||
accreditations: accreditations,
|
accreditations: accreditations,
|
||||||
photoData: photoData,
|
photoData: photoData,
|
||||||
|
coverPhotoData: coverPhotoData,
|
||||||
logoData: logoData
|
logoData: logoData
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -837,6 +834,7 @@ private extension CardEditorView {
|
|||||||
bio: bio,
|
bio: bio,
|
||||||
accreditations: accreditations,
|
accreditations: accreditations,
|
||||||
photoData: photoData,
|
photoData: photoData,
|
||||||
|
coverPhotoData: coverPhotoData,
|
||||||
logoData: logoData
|
logoData: logoData
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -54,6 +54,7 @@ struct CameraWithCropper: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.transition(.move(edge: .trailing))
|
.transition(.move(edge: .trailing))
|
||||||
|
.id(aspectRatio.ratio) // Force recreate cropper when aspect ratio changes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(.easeInOut(duration: Design.Animation.quick), value: showingCropper)
|
.animation(.easeInOut(duration: Design.Animation.quick), value: showingCropper)
|
||||||
|
|||||||
@ -25,6 +25,7 @@ struct PhotoPickerWithCropper: View {
|
|||||||
@State private var selectedItem: PhotosPickerItem?
|
@State private var selectedItem: PhotosPickerItem?
|
||||||
@State private var imageData: Data?
|
@State private var imageData: Data?
|
||||||
@State private var showingCropper = false
|
@State private var showingCropper = false
|
||||||
|
@State private var pickerRefreshID = UUID() // Force picker refresh after cancel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
PhotosPicker(
|
PhotosPicker(
|
||||||
@ -38,6 +39,7 @@ struct PhotoPickerWithCropper: View {
|
|||||||
.photosPickerStyle(.inline)
|
.photosPickerStyle(.inline)
|
||||||
.photosPickerDisabledCapabilities([.selectionActions])
|
.photosPickerDisabledCapabilities([.selectionActions])
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
.id(pickerRefreshID) // Force recreate picker when ID changes
|
||||||
.onChange(of: selectedItem) { _, newValue in
|
.onChange(of: selectedItem) { _, newValue in
|
||||||
guard let newValue else { return }
|
guard let newValue else { return }
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
@ -62,9 +64,12 @@ struct PhotoPickerWithCropper: View {
|
|||||||
showingCropper = false
|
showingCropper = false
|
||||||
self.imageData = nil
|
self.imageData = nil
|
||||||
self.selectedItem = nil
|
self.selectedItem = nil
|
||||||
|
// Generate new ID to force picker refresh, allowing same image to be reselected
|
||||||
|
pickerRefreshID = UUID()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.transition(.move(edge: .trailing))
|
.transition(.move(edge: .trailing))
|
||||||
|
.id(aspectRatio.ratio) // Force recreate cropper when aspect ratio changes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(.easeInOut(duration: Design.Animation.quick), value: showingCropper)
|
.animation(.easeInOut(duration: Design.Animation.quick), value: showingCropper)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user