diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 9ce74c5bd6..95a47d3dec 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -341,6 +341,7 @@ 9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */; }; BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; }; BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; }; + BC4294742A7430FF00566E03 /* ImageSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC4294732A7430FF00566E03 /* ImageSaver.swift */; }; D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; }; E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */; }; E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; }; @@ -845,6 +846,7 @@ 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachMediaUtility.swift; sourceTree = ""; }; BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = ""; }; BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectWalletView.swift; sourceTree = ""; }; + BC4294732A7430FF00566E03 /* ImageSaver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSaver.swift; sourceTree = ""; }; D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = ""; }; E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = ""; }; @@ -1066,6 +1068,7 @@ isa = PBXGroup; children = ( 4C198DF429F88D2E004C165C /* ImageMetadata.swift */, + BC4294732A7430FF00566E03 /* ImageSaver.swift */, ); path = Images; sourceTree = ""; @@ -2032,6 +2035,7 @@ 64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */, 4C1A9A2329DDDB8100516EAC /* IconLabel.swift in Sources */, 4C3EA64928FF597700C48A62 /* bech32.c in Sources */, + BC4294742A7430FF00566E03 /* ImageSaver.swift in Sources */, 4CE879522996B68900F758CC /* RelayType.swift in Sources */, 4CE8795B2996C47A00F758CC /* ZapsModel.swift in Sources */, 4C3A1D3729637E0500558C0F /* PreviewCache.swift in Sources */, diff --git a/damus/Util/Images/ImageSaver.swift b/damus/Util/Images/ImageSaver.swift new file mode 100644 index 0000000000..813767ac03 --- /dev/null +++ b/damus/Util/Images/ImageSaver.swift @@ -0,0 +1,19 @@ +// ImageSaver.swift + +import UIKit + +class ImageSaver: NSObject, ObservableObject { + @Published var error = false + + func writeToPhotoAlbum(image: UIImage) { + UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveCompleted), nil) + } + + @objc func saveCompleted( + _ image: UIImage, + didFinishSavingWithError error: Error?, + contextInfo: UnsafeRawPointer + ) { + self.error = error != nil ? true : false + } +} diff --git a/damus/Views/Images/ImageContainerView.swift b/damus/Views/Images/ImageContainerView.swift index cd4499a793..b173401896 100644 --- a/damus/Views/Images/ImageContainerView.swift +++ b/damus/Views/Images/ImageContainerView.swift @@ -15,6 +15,7 @@ struct ImageContainerView: View { @State private var image: UIImage? @State private var showShareSheet = false + @ObservedObject var imageSaver = ImageSaver() let disable_animation: Bool @@ -35,10 +36,18 @@ struct ImageContainerView: View { } .imageModifier(ImageHandler(handler: $image)) .clipped() - .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet)) + .modifier(ImageContextMenuModifier(url: url, image: image, imageSaver: imageSaver, showShareSheet: $showShareSheet)) .sheet(isPresented: $showShareSheet) { ShareSheet(activityItems: [url]) } + .alert( + "Failed to save photo", + isPresented: $imageSaver.error, + actions: {}, + message: { + Text("Please check the photo permissions in your Settings") + } + ) } var body: some View { diff --git a/damus/Views/Images/ImageContextMenuModifier.swift b/damus/Views/Images/ImageContextMenuModifier.swift index a3090bb5f8..d27cb76b0c 100644 --- a/damus/Views/Images/ImageContextMenuModifier.swift +++ b/damus/Views/Images/ImageContextMenuModifier.swift @@ -12,6 +12,7 @@ import UIKit struct ImageContextMenuModifier: ViewModifier { let url: URL? let image: UIImage? + let imageSaver: ImageSaver @Binding var showShareSheet: Bool func body(content: Content) -> some View { @@ -28,7 +29,7 @@ struct ImageContextMenuModifier: ViewModifier { Label(NSLocalizedString("Copy Image", comment: "Context menu option to copy an image into clipboard."), image: "copy2.fill") } Button { - UIImageWriteToSavedPhotosAlbum(someImage, nil, nil, nil) + imageSaver.writeToPhotoAlbum(image: someImage) } label: { Label(NSLocalizedString("Save Image", comment: "Context menu option to save an image."), image: "download") } diff --git a/damus/Views/Images/ProfilePicImageView.swift b/damus/Views/Images/ProfilePicImageView.swift index 97f9b63d4c..7f2cf2020f 100644 --- a/damus/Views/Images/ProfilePicImageView.swift +++ b/damus/Views/Images/ProfilePicImageView.swift @@ -12,6 +12,7 @@ struct ProfileImageContainerView: View { @State private var image: UIImage? @State private var showShareSheet = false + @ObservedObject var imageSaver = ImageSaver() let disable_animation: Bool @@ -33,7 +34,7 @@ struct ProfileImageContainerView: View { } .imageModifier(ImageHandler(handler: $image)) .clipShape(Circle()) - .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet)) + .modifier(ImageContextMenuModifier(url: url, image: image, imageSaver: imageSaver, showShareSheet: $showShareSheet)) .sheet(isPresented: $showShareSheet) { ShareSheet(activityItems: [url]) }