Files
mattermost-mobile/ios/MattermostShare/Utils/LocalFileManager.swift
Elias Nahum 3a3123674a [Gekidou] iOS Share extension (#6432)
* iOS Share extension

* Add Fastlane steps for iOS Share Extension

* new multi file layout

* Add recent label

* Refactor code & identation

* ux feedback

* downsample images

* remove options horizontal padding
2022-07-27 10:31:45 -04:00

219 lines
7.3 KiB
Swift

//
// LocalFileManager.swift
// MattermostShare
//
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
//
import Foundation
import UIKit
import UniformTypeIdentifiers
typealias ExtractContentCompletionHandler = (_ attachments: [AttachmentModel], _ linkPreviewUrl: String?, _ message: String?) -> Void
class LocalFileManager {
private var cacheURL: URL?
private var dispatchGroup = DispatchGroup()
init() {
let filemgr = FileManager.default
let appGroupId = Bundle.main.infoDictionary!["AppGroupIdentifier"] as! String
let containerUrl = filemgr.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)
if let url = containerUrl,
let cacheURL = url.appendingPathComponent("Library", isDirectory: true) as URL? {
self.cacheURL = cacheURL.appendingPathComponent("Caches", isDirectory: true)
createDirectoryIfNeeded()
}
}
private func createDirectoryIfNeeded() {
var isDirectory = ObjCBool(false)
if let cachePath = cacheURL?.path {
let exists = FileManager.default.fileExists(atPath: cachePath, isDirectory: &isDirectory)
if !exists && !isDirectory.boolValue {
try? FileManager.default.createDirectory(atPath: cachePath, withIntermediateDirectories: true, attributes: nil)
}
}
}
private func getURLForImage(imageName: String) -> URL? {
guard let url = cacheURL else {return nil}
createDirectoryIfNeeded()
return url.appendingPathComponent(imageName + ".png")
}
func clearTempDirectory(_ files: [String]) {
guard let _ = self.cacheURL else {return}
let fileMgr = FileManager.default
files.forEach{ path in
do {
try fileMgr.removeItem(atPath: path)
} catch {
print("Error deleting file \(path)")
}
}
}
func saveAttachment(url: URL, type: AttachmentType) -> AttachmentModel? {
let fileMgr = FileManager.default
let fileName = url.lastPathComponent
let tempFileURL = cacheURL?
.appendingPathComponent(fileName)
do {
if (tempFileURL != url) {
try? FileManager.default.removeItem(at: tempFileURL!)
try fileMgr.copyItem(at: url, to: tempFileURL!)
}
let attr = try fileMgr.attributesOfItem(atPath: (tempFileURL?.path)!) as NSDictionary
let attachment = AttachmentModel(
fileName: fileName,
fileSize: Int64(attr.fileSize()),
fileUrl: tempFileURL!,
type: type
)
return attachment
} catch {
return nil
}
}
func saveAttachmentImage(_ data: Data) -> AttachmentModel? {
guard let tempImageURL = cacheURL?
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension(".png")
else {return nil}
if (try? data.write(to: tempImageURL)) != nil {
return saveAttachment(url: tempImageURL, type: .image)
}
return nil
}
func saveProfileImage(image: UIImage, userId: String) {
guard let data = image.pngData(),
let url = getURLForImage(imageName: userId)
else { return }
do {
try data.write(to: url)
} catch let error {
print("Erro saving image. \(error)")
}
}
func getProfileImage(userId: String) -> UIImage? {
guard let url = getURLForImage(imageName: userId) else { return nil }
return UIImage(contentsOfFile: url.path)
}
func getImagePixels(imageUrl: URL) -> Int64 {
if let imageSourceRef = CGImageSourceCreateWithURL(imageUrl as CFURL, nil),
let props = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, nil) as? NSDictionary,
let height = props["PixelHeight"] as? NSNumber,
let width = props["PixelWidth"] as? NSNumber {
return Int64(width.intValue * height.intValue)
}
return 0
}
func getImagePixels(image: UIImage) -> Int64 {
guard let cgImage = image.cgImage else {
return 0
}
return Int64(cgImage.width * cgImage.height)
}
public func extractDataFromContext(_ inputItems: [Any], completionHander: @escaping ExtractContentCompletionHandler) -> Void {
var models: [AttachmentModel] = []
var linkPreviewUrl: String? = nil
var message: String? = nil
for item in inputItems as! [NSExtensionItem] {
guard let attachments = item.attachments else {continue}
for itemProvider in attachments {
if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: UTType.movie.identifier, options: nil, completionHandler: {[weak self] movie, error in
if error == nil,
let url = movie as? URL,
let attachment = self?.saveAttachment(url: url, type: .video) {
models.append(attachment)
}
self?.dispatchGroup.leave()
})
}
else if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil, completionHandler: {[weak self] image, error in
if error == nil {
if let url = image as? URL,
var attachment = self?.saveAttachment(url: url, type: .image) {
attachment.imagePixels = self?.getImagePixels(imageUrl: url)
models.append(attachment)
} else if let uiImage = image as? UIImage,
let data = uiImage.pngData(),
var attachment = self?.saveAttachmentImage(data) {
attachment.imagePixels = self?.getImagePixels(image: uiImage)
models.append(attachment)
}
}
self?.dispatchGroup.leave()
})
}
else if itemProvider.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil, completionHandler: {[weak self] file, error in
if error == nil,
let url = file as? URL,
let attachment = self?.saveAttachment(url: url, type: .file) {
models.append(attachment)
}
self?.dispatchGroup.leave()
})
}
else if itemProvider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil, completionHandler: {[weak self] itemURL, error in
if error == nil,
let url = itemURL as? URL {
linkPreviewUrl = url.absoluteString
}
self?.dispatchGroup.leave()
})
}
else if itemProvider.hasItemConformingToTypeIdentifier(UTType.text.identifier) {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil, completionHandler: {[weak self] text, error in
if error == nil,
let msg = text as? String {
message = msg
}
self?.dispatchGroup.leave()
})
}
}
}
dispatchGroup.notify(queue: DispatchQueue.main) {
completionHander(
models,
linkPreviewUrl,
message
)
}
}
}