diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj
index 9ff84fc..5618406 100644
--- a/Vernissage.xcodeproj/project.pbxproj
+++ b/Vernissage.xcodeproj/project.pbxproj
@@ -1172,7 +1172,7 @@
CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageWidget/Info.plist;
@@ -1200,7 +1200,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageWidget/Info.plist;
@@ -1227,7 +1227,7 @@
CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageShare/Info.plist;
@@ -1254,7 +1254,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = VernissageShare/VernissageShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_TEAM = B2U9FEKYP8;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = VernissageShare/Info.plist;
@@ -1403,7 +1403,7 @@
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
@@ -1443,7 +1443,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 104;
+ CURRENT_PROJECT_VERSION = 105;
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
DEVELOPMENT_TEAM = B2U9FEKYP8;
ENABLE_PREVIEWS = YES;
diff --git a/Vernissage/Views/ComposeView.swift b/Vernissage/Views/ComposeView.swift
index b7d65c6..10ee470 100644
--- a/Vernissage/Views/ComposeView.swift
+++ b/Vernissage/Views/ComposeView.swift
@@ -530,6 +530,9 @@ struct ComposeView: View {
self.photosAreUploading = false
self.refreshScreenState()
} catch {
+ self.photosAreUploading = false
+ self.refreshScreenState()
+
ErrorService.shared.handle(error, message: "compose.error.loadingPhotosFailed", showToastr: true)
}
}
@@ -554,8 +557,8 @@ struct ComposeView: View {
}
// We are sending orginal file (not file compressed from memory).
- guard let imageFileTranseferable = photoAttachment.imageFileTranseferable,
- let data = try? Data(contentsOf: imageFileTranseferable.url),
+ guard let photoUrl = photoAttachment.photoUrl,
+ let data = try? Data(contentsOf: photoUrl),
let uiImage = UIImage(data: data) else {
return
}
diff --git a/VernissageShare/ComposeView.swift b/VernissageShare/ComposeView.swift
index 1c0220d..9e85df0 100644
--- a/VernissageShare/ComposeView.swift
+++ b/VernissageShare/ComposeView.swift
@@ -469,54 +469,54 @@ struct ComposeView: View {
}
private func loadPhotos() async {
- do {
- self.photosAreUploading = true
- self.publishDisabled = self.isPublishButtonDisabled()
- self.interactiveDismissDisabled = self.isInteractiveDismissDisabled()
+ self.photosAreUploading = true
+ self.publishDisabled = self.isPublishButtonDisabled()
+ self.interactiveDismissDisabled = self.isInteractiveDismissDisabled()
- // We have to create list with existing photos.
- var temporaryPhotosAttachment: [PhotoAttachment] = []
+ // We have to create list with existing photos.
+ var temporaryPhotosAttachment: [PhotoAttachment] = []
- // Add to collection photos selected on photo picker.
- for item in self.selectedItems {
- if let photoAttachment = self.photosAttachment.first(where: { $0.photosPickerItem == item }) {
- temporaryPhotosAttachment.append(photoAttachment)
- continue
- }
-
- temporaryPhotosAttachment.append(PhotoAttachment(photosPickerItem: item))
+ // Add to collection photos selected on photo picker.
+ for item in self.selectedItems {
+ if let photoAttachment = self.photosAttachment.first(where: { $0.photosPickerItem == item }) {
+ temporaryPhotosAttachment.append(photoAttachment)
+ continue
}
- // Add to collection photos from share sheet.
- for item in self.attachments {
- if let photoAttachment = self.photosAttachment.first(where: { $0.nsItemProvider == item }) {
- temporaryPhotosAttachment.append(photoAttachment)
- continue
- }
-
- temporaryPhotosAttachment.append(PhotoAttachment(nsItemProvider: item))
- }
-
- // We can show new list on the screen.
- self.photosAttachment = temporaryPhotosAttachment
-
- // Now we have to get from photos images as JPEG.
- for item in self.photosAttachment.filter({ $0.photoData == nil }) {
- try await item.loadImage()
- }
-
- // Open again the keyboard.
- self.focusedField = .content
-
- // Upload images which hasn't been uploaded yet.
- await self.upload()
-
- // Change state of the screen.
- self.photosAreUploading = false
- self.refreshScreenState()
- } catch {
- ErrorService.shared.handle(error, message: "compose.error.loadingPhotosFailed", showToastr: true)
+ temporaryPhotosAttachment.append(PhotoAttachment(photosPickerItem: item))
}
+
+ // Add to collection photos from share sheet.
+ for item in self.attachments {
+ if let photoAttachment = self.photosAttachment.first(where: { $0.nsItemProvider == item }) {
+ temporaryPhotosAttachment.append(photoAttachment)
+ continue
+ }
+
+ temporaryPhotosAttachment.append(PhotoAttachment(nsItemProvider: item))
+ }
+
+ // We can show new list on the screen.
+ self.photosAttachment = temporaryPhotosAttachment
+
+ // Now we have to get from photos images as JPEG.
+ for item in self.photosAttachment.filter({ $0.photoData == nil }) {
+ do {
+ try await item.loadImage()
+ } catch {
+ ErrorService.shared.handle(error, message: "Cannot load image from external library.")
+ }
+ }
+
+ // Open again the keyboard.
+ self.focusedField = .content
+
+ // Upload images which hasn't been uploaded yet.
+ await self.upload()
+
+ // Change state of the screen.
+ self.photosAreUploading = false
+ self.refreshScreenState()
}
private func refreshScreenState() {
diff --git a/VernissageShare/Info.plist b/VernissageShare/Info.plist
index 28e9785..8a3a95e 100644
--- a/VernissageShare/Info.plist
+++ b/VernissageShare/Info.plist
@@ -10,14 +10,6 @@
NSExtensionActivationSupportsImageWithMaxCount
4
- NSExtensionActivationSupportsMovieWithMaxCount
- 0
- NSExtensionActivationSupportsText
-
- NSExtensionActivationSupportsWebPageWithMaxCount
- 0
- NSExtensionActivationSupportsWebURLWithMaxCount
- 0
NSExtensionPointIdentifier
diff --git a/WidgetsKit/Sources/WidgetsKit/Models/FileTypeSupported.swift b/WidgetsKit/Sources/WidgetsKit/Models/FileTypeSupported.swift
new file mode 100644
index 0000000..486d146
--- /dev/null
+++ b/WidgetsKit/Sources/WidgetsKit/Models/FileTypeSupported.swift
@@ -0,0 +1,78 @@
+//
+// https://mczachurski.dev
+// Copyright © 2023 Marcin Czachurski and the repository contributors.
+// Licensed under the Apache License 2.0.
+//
+
+import AVFoundation
+import Foundation
+import PhotosUI
+import SwiftUI
+import UIKit
+import UniformTypeIdentifiers
+import ServicesKit
+
+@MainActor
+enum FileTypeSupported: String, CaseIterable {
+ case image = "public.image"
+ case jpeg = "public.jpeg"
+ case png = "public.png"
+ case tiff = "public.tiff"
+ case gif = "public.gif"
+
+ case gif2 = "com.compuserve.gif"
+ case adobeRawImage = "com.adobe.raw-image"
+ case uiimage = "com.apple.uikit.image"
+
+ public nonisolated static var allCases: [FileTypeSupported] {
+ [.image, .jpeg, .png, .tiff, .gif, .gif2, .uiimage, .adobeRawImage]
+ }
+
+ func loadItemContent(item: NSItemProvider) async throws -> TransferedFile? {
+ let result = try await item.loadItem(forTypeIdentifier: rawValue)
+
+ if isImageFile() {
+ if let image = result as? UIImage,
+ let data = image.getJpegData() {
+ let fileUrl = getTmpFileUrl()
+ try data.write(to: fileUrl)
+
+ return TransferedFile(file: data, url: fileUrl)
+ } else if let imageURL = result as? URL,
+ let data = await ImageCompressService.shared.compressImageFrom(url: imageURL) {
+ let fileUrl = getTmpFileUrl()
+ try data.write(to: fileUrl)
+
+ return TransferedFile(file: data, url: fileUrl)
+ } else if let data = result as? Data {
+ let fileUrl = getTmpFileUrl()
+ try data.write(to: fileUrl)
+
+ return TransferedFile(file: data, url: fileUrl)
+ }
+ }
+
+ if let transferable = try await item.createImageFileTranseferable(),
+ let data = await ImageCompressService.shared.compressImageFrom(url: transferable.url) {
+ return TransferedFile(file: data, url: transferable.url)
+ }
+
+ if let image = result as? UIImage,
+ let data = image.getJpegData() {
+ let fileUrl = getTmpFileUrl()
+ try data.write(to: fileUrl)
+
+ return TransferedFile(file: data, url: fileUrl)
+ }
+
+ return nil
+ }
+
+ func isImageFile() -> Bool {
+ return self == .jpeg || self == .png || self == .tiff || self == .image || self == .uiimage || self == .adobeRawImage
+ }
+
+ func getTmpFileUrl() -> URL {
+ return URL.temporaryDirectory.appending(path: "\(UUID().uuidString).jpeg")
+ }
+}
diff --git a/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift b/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift
index 6b09e2c..9ff640f 100644
--- a/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift
+++ b/WidgetsKit/Sources/WidgetsKit/Models/PhotoAttachment.swift
@@ -23,7 +23,7 @@ public class PhotoAttachment: ObservableObject, Identifiable, Equatable, Hashabl
@Published public var photoData: Data?
/// Property which stores orginal image file copied from Photos to tmp folder.
- @Published public var imageFileTranseferable: ImageFileTranseferable?
+ @Published public var photoUrl: URL?
/// Property stores information after upload to Pixelfed.
@Published public var uploadedAttachment: UploadedAttachment?
@@ -53,14 +53,20 @@ public extension PhotoAttachment {
func loadImage() async throws {
if let pickerItem = self.photosPickerItem,
let transferable = try await pickerItem.createImageFileTranseferable() {
- self.imageFileTranseferable = transferable
+ self.photoUrl = transferable.url
self.photoData = await ImageCompressService.shared.compressImageFrom(url: transferable.url)
+
+ return
}
if let itemProvider = self.nsItemProvider,
- let transferable = try await itemProvider.createImageFileTranseferable() {
- self.imageFileTranseferable = transferable
- self.photoData = await ImageCompressService.shared.compressImageFrom(url: transferable.url)
+ let identifier = itemProvider.registeredTypeIdentifiers.first,
+ let handledItemType = FileTypeSupported(rawValue: identifier),
+ let transferredFile = try await handledItemType.loadItemContent(item: itemProvider) {
+ self.photoUrl = transferredFile.url
+ self.photoData = transferredFile.file
+
+ return
}
}
}
@@ -86,7 +92,7 @@ public extension [PhotoAttachment] {
func removeTmpFiles() {
for file in self {
- if let fileUrl = file.imageFileTranseferable?.url {
+ if let fileUrl = file.photoUrl {
do {
try FileManager.default.removeItem(at: fileUrl)
} catch {
diff --git a/WidgetsKit/Sources/WidgetsKit/Models/TransferedFile.swift b/WidgetsKit/Sources/WidgetsKit/Models/TransferedFile.swift
new file mode 100644
index 0000000..71e106a
--- /dev/null
+++ b/WidgetsKit/Sources/WidgetsKit/Models/TransferedFile.swift
@@ -0,0 +1,17 @@
+//
+// https://mczachurski.dev
+// Copyright © 2023 Marcin Czachurski and the repository contributors.
+// Licensed under the MIT License.
+//
+
+import Foundation
+
+public struct TransferedFile {
+ public let file: Data
+ public let url: URL
+
+ public init(file: Data, url: URL) {
+ self.file = file
+ self.url = url
+ }
+}