Last active
April 5, 2021 05:23
-
-
Save gilbox/1a19e1e18ffcaa70e7d6b0fe0e837e10 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Created by gil_birman on 11/22/19. | |
import Combine | |
import FirebaseFirestore | |
import FirebaseStorage | |
import Foundation | |
enum FirebaseCombineError: Error { | |
case encodeImageFailed | |
case nilResultError | |
case uploadFailed | |
} | |
extension StorageReference { | |
/// Retrieves a download URL for this object. | |
/// Returns a publisher that you can use to track the progress. | |
var downloadURLPublisher: AnyPublisher<URL, Error> { | |
Future<URL, Error> { [weak self] promise in | |
self?.downloadURL { (url, error) in | |
if let error = error { | |
promise(.failure(error)) | |
} else if let url = url { | |
promise(.success(url)) | |
} else { | |
promise(.failure(FirebaseCombineError.nilResultError)) | |
} | |
} | |
}.eraseToAnyPublisher() | |
} | |
/// Uploads data. | |
/// Returns a publisher that you can use to track the progress. | |
func putDataPublisher(_ uploadData: Data, metadata: StorageMetadata) | |
-> AnyPublisher<StorageMetadata, Error> | |
{ | |
return Future<StorageMetadata, Error> { [weak self] promise in | |
self?.putData(uploadData, metadata: metadata) { (metadata, error) in | |
if let error = error { | |
promise(.failure(error)) | |
return | |
} | |
guard let metadata = metadata else { | |
promise(.failure(FirebaseCombineError.uploadFailed)) | |
return | |
} | |
promise(.success(metadata)) | |
} | |
}.eraseToAnyPublisher() | |
} | |
/// Uploads an image with the specified file type | |
/// Returns a publisher that you can use to track the progress. | |
func uploadImagePublisher( | |
_ image: CGImage, | |
fileType: NSBitmapImageRep.FileType = .jpeg) | |
-> AnyPublisher<StorageMetadata, Error> | |
{ | |
let nsImage = NSImage(cgImage: image, size: .zero) | |
guard | |
let tiffData = nsImage.tiffRepresentation, | |
let bitmap = NSBitmapImageRep(data: tiffData), | |
let data = bitmap.representation(using: fileType, properties: [:]) | |
else { | |
return Fail(error: FirebaseCombineError.encodeImageFailed).eraseToAnyPublisher() | |
} | |
let metadata = StorageMetadata() | |
switch fileType { | |
case .jpeg, .jpeg2000: | |
metadata.contentType = "image/jpeg" | |
case .png: | |
metadata.contentType = "image/png" | |
case .gif: | |
metadata.contentType = "image/gif" | |
case .bmp: | |
metadata.contentType = "image/bmp" | |
case .tiff: | |
metadata.contentType = "image/tiff" | |
@unknown default: | |
metadata.contentType = "image/unknown" | |
} | |
return putDataPublisher(data, metadata: metadata) | |
} | |
/// Uploads an image with the specified name and extension based on the file type. | |
/// Returns a publisher that you can use to track the progress. | |
func uploadImageWithFilenamePublisher( | |
_ image: CGImage, | |
fileName: String, | |
fileType: NSBitmapImageRep.FileType = .jpeg) | |
-> AnyPublisher<(storageReference: StorageReference, metadata: StorageMetadata), Error> | |
{ | |
let ext: String | |
switch fileType { | |
case .jpeg, .jpeg2000: | |
ext = "jpg" | |
case .png: | |
ext = "png" | |
case .gif: | |
ext = "gif" | |
case .bmp: | |
ext = "bmp" | |
case .tiff: | |
ext = "tiff" | |
@unknown default: | |
ext = "image" | |
} | |
let fileName = "\(fileName).\(ext)" | |
let storageReference = child(fileName) | |
return storageReference.uploadImagePublisher(image) | |
.map { metadata in (storageReference, metadata) } | |
.eraseToAnyPublisher() | |
} | |
/// Uploads an image and creates a file named with the UUID() function | |
/// and the specified extension based on the file type | |
/// Returns a publisher that you can use to track the progress. | |
func uploadImageWithRandomFilenamePublisher( | |
_ image: CGImage, | |
fileType: NSBitmapImageRep.FileType = .jpeg) | |
-> AnyPublisher<(storageReference: StorageReference, metadata: StorageMetadata), Error> | |
{ | |
return uploadImageWithFilenamePublisher( | |
image, | |
fileName: UUID().uuidString, | |
fileType: fileType) | |
} | |
} | |
extension DocumentReference { | |
func snapshotPublisher(includeMetadataChanges: Bool = false) -> AnyPublisher<DocumentSnapshot, Error> { | |
return Future<DocumentSnapshot, Error> { [weak self] promise in | |
self?.addSnapshotListener(includeMetadataChanges: includeMetadataChanges) { snapshot, error in | |
if let error = error { | |
promise(.failure(error)) | |
} else if let snapshot = snapshot { | |
promise(.success(snapshot)) | |
} else { | |
promise(.failure(FirebaseCombineError.nilResultError)) | |
} | |
} | |
}.eraseToAnyPublisher() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please checkout: https://github.com/rever-ai/CombineFirebase