swiftenjoyer
swiftenjoyer

Reputation: 85

Video doesn't save to Gallery when implementing save and delete feature in iOS app

I'm trying to implement a feature on my iOS app where users can select multiple media files (images and videos) from the app's storage, then save them to the device's Photos gallery and then delete them from the app's storage to free up space with the "Save" button. Initially, the save mechanism worked fine if there was no delete mechanism (the mediaFiles.removeAll {} block):

struct GalleryView: View {
    @ObservedObject var model: CameraModel
    @Binding var mediaFiles: [Media]
    
    @State private var isSelecting: Bool = false
    @State private var selectedItems: Set<UUID> = Set<UUID>()
    @State private var selectedMedia: Media?
    @State private var showingDeleteConfirmation: Bool = false
    @State private var showingSaveConfirmation: Bool = false
    @State private var showToast: Bool = false
    @State private var toastMessage: String = ""
    
    var body: some View {
        // ...
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Save") {
                    if !selectedItems.isEmpty {
                        showingSaveConfirmation = true
                    }
                }
                .alert(isPresented: $showingSaveConfirmation) {
                    Alert(title: Text("Save to Device"),
                          message: Text("Save selected items to your device? They'll be deleted from the app to save space."),
                          primaryButton: .default(Text("Save")) {
                        let selectedMediaFiles = mediaFiles.filter { media in
                            selectedItems.contains(media.id)
                        }
                        // Request permission to access the photo library
                        PHPhotoLibrary.requestAuthorization { status in
                            if status == .authorized {
                                // Save each selected media file to the photo library
                                for media in selectedMediaFiles {
                                    if let image = media.image {
                                        // Save image
                                        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
                                    } else if let videoURL = media.videoURL {
                                        // Save video
                                        UISaveVideoAtPathToSavedPhotosAlbum(videoURL.path, nil, nil, nil)
                                    }
                                }
                                // Delete the selected items from the app's storage
                                mediaFiles.removeAll { media in
                                    if selectedItems.contains(media.id) {
                                        // Delete the corresponding file from the app's storage
                                        if let image = media.image {
                                            let timestamp = "\(media.creationTime.timeIntervalSince1970)"
                                            model.deleteImageFromAppStorage(withName: timestamp)
                                        } else if let videoURL = media.videoURL {
                                            model.deleteFileFromAppStorage(at: videoURL)
                                        }
                                        return true
                                    }
                                    return false
                                }
                                
                                selectedItems.removeAll()
                                isSelecting = false
                                // Show toast message
                                toastMessage = "Selected Items Saved & Deleted"
                                showToast = true
                            } else {
                                // Handle the case where the user denied access
                                print("User denied access to the photo library.")
                            }
                        }
                    },
                          secondaryButton: .cancel())
                }
            }
        }
    }
}

struct Media: Identifiable {
    let id = UUID()
    let creationTime: Date
    var image: UIImage?
    var videoURL: URL?
}

struct MediaFileView: View {
    var media: Media
    var width: CGFloat
    @Binding var isSelecting: Bool
    @Binding var selectedItems: Set<UUID>
    @Binding var selectedMedia: Media?
    
    var body: some View {
        // Display media file thumbnail
        // ...
    }
}

However, after introducing the delete functionality, the selected images were being saved and deleted correctly, but selected videos were only being deleted and not saved. I tried to address this issue by implementing an integer mechanism called VideosToBeSavedThenDelete where the idea was to decrement this integer each time a video is saved and only run the delete block once this integer reaches 0:

// Top of GalleryView:
@State private var VideosToBeSavedThenDelete: Int = 0

// Save each selected media file to the photo library
for media in selectedMediaFiles {
    if let image = media.image {
        // Save image
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
    } else if let videoURL = media.videoURL {
        // Save video
        UISaveVideoAtPathToSavedPhotosAlbum(videoURL.path, nil, nil, nil)
        VideosToBeSavedThenDelete -= 1
    }
}

// Delete the selected items from the app's storage
if VideosToBeSavedThenDelete == 0 {
    mediaFiles.removeAll { media in
        if selectedItems.contains(media.id) {
            // Delete the corresponding file from the app's storage
            if let image = media.image {
                let timestamp = "\(media.creationTime.timeIntervalSince1970)"
                model.deleteImageFromAppStorage(withName: timestamp)
            } else if let videoURL = media.videoURL {
                model.deleteFileFromAppStorage(at: videoURL)
            }
            return true
        }
        return false
    }
}

However, videos were still not being saved to the Gallery and were only being deleted even with this approach. I understand that the saving images line runs synchronously while the saving videos line runs asynchronously. Why didn't the integer approach work as expected? Is there a better way to approach this problem?

Upvotes: 0

Views: 49

Answers (0)

Related Questions