Эх сурвалжийг харах

create new class NCUtility+Image

Signed-off-by: Marino Faggiana <8616947+marinofaggiana@users.noreply.github.com>
Marino Faggiana 1 жил өмнө
parent
commit
bfaed18d38

+ 16 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -185,6 +185,11 @@
 		F711A4E02AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
 		F711A4E12AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
 		F711A4E22AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */; };
+		F711A4E32AF9310400095DD8 /* NCUtility+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93474B27E34120002537EE /* NCUtility+Image.swift */; };
+		F711A4E52AF9310500095DD8 /* NCUtility+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93474B27E34120002537EE /* NCUtility+Image.swift */; };
+		F711A4E92AF9327600095DD8 /* UIImage+animatedGIF.m in Sources */ = {isa = PBXBuildFile; fileRef = F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */; };
+		F711A4EB2AF9327D00095DD8 /* UIImage+animatedGIF.m in Sources */ = {isa = PBXBuildFile; fileRef = F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */; };
+		F711A4EF2AF932B900095DD8 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F711A4EE2AF932B900095DD8 /* SVGKitSwift */; };
 		F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9739428F17131002C43E2 /* IntentHandler.swift */; };
 		F7134186259747BA00768D21 /* NCPushNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = F7134185259747BA00768D21 /* NCPushNotification.m */; };
 		F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */ = {isa = PBXBuildFile; fileRef = F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */; };
@@ -1464,6 +1469,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F711A4EF2AF932B900095DD8 /* SVGKitSwift in Frameworks */,
 				F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */,
 				F74C863D2AEFBFD9009A1D4A /* LRUCache in Frameworks */,
 				F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */,
@@ -2828,6 +2834,7 @@
 				F7A560472AE15D5000BE8FD6 /* Queuer */,
 				F760DE082AE66ED00027D78A /* KeychainAccess */,
 				F74C863C2AEFBFD9009A1D4A /* LRUCache */,
+				F711A4EE2AF932B900095DD8 /* SVGKitSwift */,
 			);
 			productName = "Share Ext";
 			productReference = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */;
@@ -3530,6 +3537,7 @@
 				F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */,
 				F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */,
 				F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */,
+				F711A4EB2AF9327D00095DD8 /* UIImage+animatedGIF.m in Sources */,
 				F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */,
 				F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				AF730AFA27843E4C00B7520E /* NCShareExtension+NCDelegate.swift in Sources */,
@@ -3538,6 +3546,7 @@
 				F72FD3B8297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7EDE4E0262D7BAF00414FE6 /* NCGridCell.swift in Sources */,
 				F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */,
+				F711A4E52AF9310500095DD8 /* NCUtility+Image.swift in Sources */,
 				F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
@@ -3578,6 +3587,7 @@
 				F359D8682A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7346E1628B0EF5C006CE2D2 /* Widget.swift in Sources */,
 				F78302F828B4C3E100B84583 /* NCManageDatabase+Activity.swift in Sources */,
+				F711A4E92AF9327600095DD8 /* UIImage+animatedGIF.m in Sources */,
 				F783030228B4C4B800B84583 /* NCUtility.swift in Sources */,
 				F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */,
 				F76DEE9728F808AF0041B1C9 /* LockscreenData.swift in Sources */,
@@ -3599,6 +3609,7 @@
 				F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F757CC8329E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F74B6D962A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
+				F711A4E32AF9310400095DD8 /* NCUtility+Image.swift in Sources */,
 				F749B652297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F783030628B4C51E00B84583 /* String+Extension.swift in Sources */,
 				F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
@@ -5293,6 +5304,11 @@
 			package = F710FC78277B7CFF00AA9FBF /* XCRemoteSwiftPackageReference "realm-swift" */;
 			productName = RealmSwift;
 		};
+		F711A4EE2AF932B900095DD8 /* SVGKitSwift */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F75E57A725BF0D61002B72C2 /* XCRemoteSwiftPackageReference "SVGKit" */;
+			productName = SVGKitSwift;
+		};
 		F72AD70C28C24B93006CB92D /* NextcloudKit */ = {
 			isa = XCSwiftPackageProductDependency;
 			package = F783034028B511D200B84583 /* XCRemoteSwiftPackageReference "NextcloudKit" */;

+ 1 - 0
Share/Share-Bridging-Header.h

@@ -4,3 +4,4 @@
 
 #import "NCEndToEndEncryption.h"
 #import "CCUtility.h"
+#import "UIImage+animatedGIF.h"

+ 1 - 0
Widget/Widget-Brinding-header.h

@@ -3,3 +3,4 @@
 //
 
 #import "CCUtility.h"
+#import "UIImage+animatedGIF.h"

+ 1 - 1
iOSClient/Login/NCLogin.swift

@@ -396,7 +396,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                 if error == .success, let userProfile {
 
                     if NCManageDatabase.shared.getAccounts() == nil {
-                        NCUtility().removeAllSettings()
+                        NCUtilityFileSystem().removeAllSettings()
                     }
 
                     NCManageDatabase.shared.deleteAccount(account)

+ 1 - 1
iOSClient/Login/NCLoginWeb.swift

@@ -294,7 +294,7 @@ extension NCLoginWeb: WKNavigationDelegate {
             if error == .success, let userProfile {
 
                 if NCManageDatabase.shared.getAccounts() == nil {
-                    self.utility.removeAllSettings()
+                    NCUtilityFileSystem().removeAllSettings()
                 }
 
                 NCManageDatabase.shared.deleteAccount(account)

+ 37 - 0
iOSClient/Utility/NCUtility+Date.swift

@@ -45,4 +45,41 @@ extension NCUtility {
             return DateFormatter.localizedString(from: date, dateStyle: .long, timeStyle: .none)
         }
     }
+
+    func dateDiff(_ date: Date?) -> String {
+
+        guard let date else { return "" }
+        let today = Date()
+        var ti = date.timeIntervalSince(today)
+        ti = ti * -1
+        if ti < 60 {
+            return NSLocalizedString("_less_a_minute_", comment: "")
+        } else if ti < 3600 {
+            let diff = Int(round(ti / 60))
+            if diff == 1 {
+                return NSLocalizedString("_a_minute_ago_", comment: "")
+            } else {
+                return String.localizedStringWithFormat(NSLocalizedString("_minutes_ago_", comment: ""), diff)
+            }
+        } else if ti < 86400 {
+            let diff = Int(round(ti / 60))
+            if diff == 1 {
+                return NSLocalizedString("_an_hour_ago_", comment: "")
+            } else {
+                return String.localizedStringWithFormat(NSLocalizedString("_hours_ago_", comment: ""), diff)
+            }
+        } else if ti < 86400 * 30 {
+            let diff = Int(round(ti / 60 / 60 / 24))
+            if diff == 1 {
+                return NSLocalizedString("_a_day_ago_", comment: "")
+            } else {
+                return String.localizedStringWithFormat(NSLocalizedString("_days_ago_", comment: ""), diff)
+            }
+        } else {
+            let formatter = DateFormatter()
+            formatter.formatterBehavior = .behavior10_4
+            formatter.dateStyle = .medium
+            return formatter.string(from: date)
+        }
+    }
 }

+ 281 - 4
iOSClient/Utility/NCUtility+Image.swift

@@ -2,10 +2,10 @@
 //  NCUtility+Image.swift
 //  Nextcloud
 //
-//  Created by Henrik Storch on 17.03.22.
-//  Copyright © 2022 Henrik Storch. All rights reserved.
+//  Created by Marino Faggiana on 06/11/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
 //
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -22,10 +22,112 @@
 //
 
 import UIKit
-import SVGKit
 import NextcloudKit
+import PDFKit
+import Accelerate
+import CoreMedia
+import Photos
+import SVGKit
 
 extension NCUtility {
+
+    func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage {
+
+        var image: UIImage?
+
+        // see https://stackoverflow.com/questions/71764255
+        let sfSymbolName = imageName.replacingOccurrences(of: "_", with: ".")
+        if let symbolConfiguration {
+            image = UIImage(systemName: sfSymbolName, withConfiguration: symbolConfiguration as? UIImage.Configuration)?.withTintColor(color, renderingMode: renderingMode)
+        } else {
+            image = UIImage(systemName: sfSymbolName)?.withTintColor(color, renderingMode: renderingMode)
+        }
+        if image == nil {
+            image = UIImage(named: imageName)?.image(color: color, size: size)
+        }
+        if let image {
+            return image
+        }
+
+        return  UIImage(named: "file")!.image(color: color, size: size)
+    }
+
+    @objc func loadUserImage(for user: String, displayName: String?, userBaseUrl: NCUserBaseUrl) -> UIImage {
+
+        let fileName = userBaseUrl.userBaseUrl + "-" + user + ".png"
+        let localFilePath = utilityFileSystem.directoryUserData + "/" + fileName
+
+        if var localImage = UIImage(contentsOfFile: localFilePath) {
+            let rect = CGRect(x: 0, y: 0, width: 30, height: 30)
+            UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
+            UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
+            localImage.draw(in: rect)
+            localImage = UIGraphicsGetImageFromCurrentImageContext() ?? localImage
+            UIGraphicsEndImageContext()
+            return localImage
+        } else if let loadedAvatar = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
+            return loadedAvatar
+        } else if let displayName = displayName, !displayName.isEmpty, let avatarImg = createAvatar(displayName: displayName, size: 30) {
+            return avatarImg
+        } else {
+            let config = UIImage.SymbolConfiguration(pointSize: 30)
+            return loadImage(named: "person.crop.circle", symbolConfiguration: config)
+        }
+    }
+
+    func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? {
+
+        let asset = AVURLAsset(url: url)
+        let assetIG = AVAssetImageGenerator(asset: asset)
+
+        assetIG.appliesPreferredTrackTransform = true
+        assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
+
+        let cmTime = CMTime(seconds: time, preferredTimescale: 60)
+        let thumbnailImageRef: CGImage
+        do {
+            thumbnailImageRef = try assetIG.copyCGImage(at: cmTime, actualTime: nil)
+        } catch let error {
+            print("Error: \(error)")
+            return nil
+        }
+
+        return UIImage(cgImage: thumbnailImageRef)
+    }
+
+    func createImageFrom(fileNameView: String, ocId: String, etag: String, classFile: String) {
+
+        var originalImage, scaleImagePreview, scaleImageIcon: UIImage?
+
+        let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)
+        let fileNamePathPreview = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(ocId, etag: etag)
+        let fileNamePathIcon = utilityFileSystem.getDirectoryProviderStorageIconOcId(ocId, etag: etag)
+
+        if utilityFileSystem.fileProviderStorageSize(ocId, fileNameView: fileNameView) > 0 && FileManager().fileExists(atPath: fileNamePathPreview) && FileManager().fileExists(atPath: fileNamePathIcon) { return }
+        if classFile != NKCommon.TypeClassFile.image.rawValue && classFile != NKCommon.TypeClassFile.video.rawValue { return }
+
+        if classFile == NKCommon.TypeClassFile.image.rawValue {
+
+            originalImage = UIImage(contentsOfFile: fileNamePath)
+
+            scaleImagePreview = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizePreview, height: NCGlobal.shared.sizePreview))
+            scaleImageIcon = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon))
+
+            try? scaleImagePreview?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
+            try? scaleImageIcon?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
+
+        } else if classFile == NKCommon.TypeClassFile.video.rawValue {
+
+            let videoPath = NSTemporaryDirectory() + "tempvideo.mp4"
+            utilityFileSystem.linkItem(atPath: fileNamePath, toPath: videoPath)
+
+            originalImage = imageFromVideo(url: URL(fileURLWithPath: videoPath), at: 0)
+
+            try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
+            try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
+        }
+    }
+
     func getImageMetadata(_ metadata: tableMetadata, for size: CGFloat) -> UIImage? {
 
         if let image = getImage(metadata: metadata) {
@@ -87,4 +189,179 @@ extension NCUtility {
         }
         return image
     }
+
+    func imageFromVideo(url: URL, at time: TimeInterval, completion: @escaping (UIImage?) -> Void) {
+        DispatchQueue.global().async {
+
+            let asset = AVURLAsset(url: url)
+            let assetIG = AVAssetImageGenerator(asset: asset)
+
+            assetIG.appliesPreferredTrackTransform = true
+            assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
+
+            let cmTime = CMTime(seconds: time, preferredTimescale: 60)
+            let thumbnailImageRef: CGImage
+            do {
+                thumbnailImageRef = try assetIG.copyCGImage(at: cmTime, actualTime: nil)
+            } catch let error {
+                print("Error: \(error)")
+                return completion(nil)
+            }
+
+            DispatchQueue.main.async {
+                completion(UIImage(cgImage: thumbnailImageRef))
+            }
+        }
+    }
+
+    func createFilePreviewImage(ocId: String, etag: String, fileNameView: String, classFile: String, status: Int, createPreviewMedia: Bool) -> UIImage? {
+
+        var imagePreview: UIImage?
+        let filePath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)
+        let iconImagePath = utilityFileSystem.getDirectoryProviderStorageIconOcId(ocId, etag: etag)
+
+        if FileManager.default.fileExists(atPath: iconImagePath) {
+            imagePreview = UIImage(contentsOfFile: iconImagePath)
+        } else if !createPreviewMedia {
+            return nil
+        } else if createPreviewMedia && status >= NCGlobal.shared.metadataStatusNormal && classFile == NKCommon.TypeClassFile.image.rawValue && FileManager().fileExists(atPath: filePath) {
+            if let image = UIImage(contentsOfFile: filePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon)), let data = image.jpegData(compressionQuality: 0.5) {
+                do {
+                    try data.write(to: URL(fileURLWithPath: iconImagePath), options: .atomic)
+                    imagePreview = image
+                } catch { }
+            }
+        } else if createPreviewMedia && status >= NCGlobal.shared.metadataStatusNormal && classFile == NKCommon.TypeClassFile.video.rawValue && FileManager().fileExists(atPath: filePath) {
+            if let image = imageFromVideo(url: URL(fileURLWithPath: filePath), at: 0), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon)), let data = image.jpegData(compressionQuality: 0.5) {
+                do {
+                    try data.write(to: URL(fileURLWithPath: iconImagePath), options: .atomic)
+                    imagePreview = image
+                } catch { }
+            }
+        }
+
+        return imagePreview
+    }
+
+    @objc func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? {
+
+        guard let data = try? Data(contentsOf: url), let page = PDFDocument(data: data)?.page(at: 0) else {
+            return nil
+        }
+
+        let pageSize = page.bounds(for: .mediaBox)
+        let pdfScale = width / pageSize.width
+
+        // Apply if you're displaying the thumbnail on screen
+        let scale = UIScreen.main.scale * pdfScale
+        let screenSize = CGSize(width: pageSize.width * scale, height: pageSize.height * scale)
+
+        return page.thumbnail(of: screenSize, for: .mediaBox)
+    }
+
+    func createAvatar(displayName: String, size: CGFloat) -> UIImage? {
+        guard let initials = displayName.uppercaseInitials else {
+            return nil
+        }
+        let userColor = NCGlobal.shared.usernameToColor(displayName)
+        let rect = CGRect(x: 0, y: 0, width: size, height: size)
+        var avatarImage: UIImage?
+
+        UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
+        let context = UIGraphicsGetCurrentContext()
+        UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
+        context?.setFillColor(userColor)
+        context?.fill(rect)
+        let textStyle = NSMutableParagraphStyle()
+        textStyle.alignment = NSTextAlignment.center
+        let lineHeight = UIFont.systemFont(ofSize: UIFont.systemFontSize).pointSize
+        NSString(string: initials)
+            .draw(
+                in: CGRect(x: 0, y: (size - lineHeight) / 2, width: size, height: lineHeight),
+                withAttributes: [NSAttributedString.Key.paragraphStyle: textStyle])
+        avatarImage = UIGraphicsGetImageFromCurrentImageContext()
+        UIGraphicsEndImageContext()
+
+        return avatarImage
+    }
+
+    func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String? = nil, width: CGFloat? = nil, rewrite: Bool, account: String, id: Int? = nil, completion: @escaping (_ imageNamePath: String?, _ id: Int?) -> Void) {
+
+        var fileNamePNG = ""
+
+        guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
+              let iconURL = URL(string: svgUrlString) else {
+            return completion(nil, id)
+        }
+
+        if let fileName = fileName {
+            fileNamePNG = fileName
+        } else {
+            fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
+        }
+
+        let imageNamePath = utilityFileSystem.directoryUserData + "/" + fileNamePNG
+
+        if !FileManager.default.fileExists(atPath: imageNamePath) || rewrite == true {
+
+            NextcloudKit.shared.downloadContent(serverUrl: iconURL.absoluteString) { _, data, error in
+
+                if error == .success && data != nil {
+
+                    if let image = UIImage(data: data!) {
+
+                        var newImage: UIImage = image
+
+                        if width != nil {
+
+                            let ratio = image.size.height / image.size.width
+                            let newSize = CGSize(width: width!, height: width! * ratio)
+
+                            let renderFormat = UIGraphicsImageRendererFormat.default()
+                            renderFormat.opaque = false
+                            let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
+                            newImage = renderer.image { _ in
+                                image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
+                            }
+                        }
+
+                        guard let pngImageData = newImage.pngData() else {
+                            return completion(nil, id)
+                        }
+
+                        try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
+
+                        return completion(imageNamePath, id)
+
+                    } else {
+
+                        guard let svgImage: SVGKImage = SVGKImage(data: data) else {
+                            return completion(nil, id)
+                        }
+
+                        if width != nil {
+                            let scale = svgImage.size.height / svgImage.size.width
+                            svgImage.size = CGSize(width: width!, height: width! * scale)
+                        }
+
+                        guard let image: UIImage = svgImage.uiImage else {
+                            return completion(nil, id)
+                        }
+                        guard let pngImageData = image.pngData() else {
+                            return completion(nil, id)
+                        }
+
+                        try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
+
+                        return completion(imageNamePath, id)
+                    }
+                } else {
+                    return completion(nil, id)
+                }
+            }
+
+        } else {
+            return completion(imageNamePath, id)
+        }
+    }
 }

+ 0 - 335
iOSClient/Utility/NCUtility.swift

@@ -29,96 +29,10 @@ import CoreMedia
 import Photos
 import Alamofire
 
-#if !EXTENSION
-import SVGKit
-#endif
-
 class NCUtility: NSObject {
 
     let utilityFileSystem = NCUtilityFileSystem()
 
-#if !EXTENSION
-    func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String? = nil, width: CGFloat? = nil, rewrite: Bool, account: String, id: Int? = nil, completion: @escaping (_ imageNamePath: String?, _ id: Int?) -> Void) {
-
-        var fileNamePNG = ""
-
-        guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
-              let iconURL = URL(string: svgUrlString) else {
-            return completion(nil, id)
-        }
-
-        if let fileName = fileName {
-            fileNamePNG = fileName
-        } else {
-            fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
-        }
-
-        let imageNamePath = utilityFileSystem.directoryUserData + "/" + fileNamePNG
-
-        if !FileManager.default.fileExists(atPath: imageNamePath) || rewrite == true {
-
-            NextcloudKit.shared.downloadContent(serverUrl: iconURL.absoluteString) { _, data, error in
-
-                if error == .success && data != nil {
-
-                    if let image = UIImage(data: data!) {
-
-                        var newImage: UIImage = image
-
-                        if width != nil {
-
-                            let ratio = image.size.height / image.size.width
-                            let newSize = CGSize(width: width!, height: width! * ratio)
-
-                            let renderFormat = UIGraphicsImageRendererFormat.default()
-                            renderFormat.opaque = false
-                            let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
-                            newImage = renderer.image { _ in
-                                image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
-                            }
-                        }
-
-                        guard let pngImageData = newImage.pngData() else {
-                            return completion(nil, id)
-                        }
-
-                        try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
-
-                        return completion(imageNamePath, id)
-
-                    } else {
-
-                        guard let svgImage: SVGKImage = SVGKImage(data: data) else {
-                            return completion(nil, id)
-                        }
-
-                        if width != nil {
-                            let scale = svgImage.size.height / svgImage.size.width
-                            svgImage.size = CGSize(width: width!, height: width! * scale)
-                        }
-
-                        guard let image: UIImage = svgImage.uiImage else {
-                            return completion(nil, id)
-                        }
-                        guard let pngImageData = image.pngData() else {
-                            return completion(nil, id)
-                        }
-
-                        try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
-
-                        return completion(imageNamePath, id)
-                    }
-                } else {
-                    return completion(nil, id)
-                }
-            }
-
-        } else {
-            return completion(imageNamePath, id)
-        }
-    }
-#endif
-
     @objc func isSimulatorOrTestFlight() -> Bool {
         guard let path = Bundle.main.appStoreReceiptURL?.path else {
             return false
@@ -196,26 +110,6 @@ class NCUtility: NSObject {
         return Array(Set(editor))
     }
 
-#if !EXTENSION
-    @objc func removeAllSettings() {
-
-        URLCache.shared.memoryCapacity = 0
-        URLCache.shared.diskCapacity = 0
-
-        NCManageDatabase.shared.clearDatabase(account: nil, removeAccount: true)
-
-        utilityFileSystem.removeGroupDirectoryProviderStorage()
-        utilityFileSystem.removeGroupLibraryDirectory()
-
-        utilityFileSystem.removeDocumentsDirectory()
-        utilityFileSystem.removeTemporaryDirectory()
-
-        utilityFileSystem.createDirectoryStandard()
-
-        NCKeychain().removeAll()
-    }
-#endif
-
     func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool {
 
         for char in permissions {
@@ -248,22 +142,6 @@ class NCUtility: NSObject {
         }
     }
 
-    @objc func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? {
-
-        guard let data = try? Data(contentsOf: url), let page = PDFDocument(data: data)?.page(at: 0) else {
-            return nil
-        }
-
-        let pageSize = page.bounds(for: .mediaBox)
-        let pdfScale = width / pageSize.width
-
-        // Apply if you're displaying the thumbnail on screen
-        let scale = UIScreen.main.scale * pdfScale
-        let screenSize = CGSize(width: pageSize.width * scale, height: pageSize.height * scale)
-
-        return page.thumbnail(of: screenSize, for: .mediaBox)
-    }
-
     @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
         return true
     }
@@ -318,83 +196,6 @@ class NCUtility: NSObject {
         return(onlineStatus, statusMessage, descriptionMessage)
     }
 
-    func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? {
-
-        let asset = AVURLAsset(url: url)
-        let assetIG = AVAssetImageGenerator(asset: asset)
-
-        assetIG.appliesPreferredTrackTransform = true
-        assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
-
-        let cmTime = CMTime(seconds: time, preferredTimescale: 60)
-        let thumbnailImageRef: CGImage
-        do {
-            thumbnailImageRef = try assetIG.copyCGImage(at: cmTime, actualTime: nil)
-        } catch let error {
-            print("Error: \(error)")
-            return nil
-        }
-
-        return UIImage(cgImage: thumbnailImageRef)
-    }
-
-    func imageFromVideo(url: URL, at time: TimeInterval, completion: @escaping (UIImage?) -> Void) {
-        DispatchQueue.global().async {
-
-            let asset = AVURLAsset(url: url)
-            let assetIG = AVAssetImageGenerator(asset: asset)
-
-            assetIG.appliesPreferredTrackTransform = true
-            assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
-
-            let cmTime = CMTime(seconds: time, preferredTimescale: 60)
-            let thumbnailImageRef: CGImage
-            do {
-                thumbnailImageRef = try assetIG.copyCGImage(at: cmTime, actualTime: nil)
-            } catch let error {
-                print("Error: \(error)")
-                return completion(nil)
-            }
-
-            DispatchQueue.main.async {
-                completion(UIImage(cgImage: thumbnailImageRef))
-            }
-        }
-    }
-
-    func createImageFrom(fileNameView: String, ocId: String, etag: String, classFile: String) {
-
-        var originalImage, scaleImagePreview, scaleImageIcon: UIImage?
-
-        let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)
-        let fileNamePathPreview = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(ocId, etag: etag)
-        let fileNamePathIcon = utilityFileSystem.getDirectoryProviderStorageIconOcId(ocId, etag: etag)
-
-        if utilityFileSystem.fileProviderStorageSize(ocId, fileNameView: fileNameView) > 0 && FileManager().fileExists(atPath: fileNamePathPreview) && FileManager().fileExists(atPath: fileNamePathIcon) { return }
-        if classFile != NKCommon.TypeClassFile.image.rawValue && classFile != NKCommon.TypeClassFile.video.rawValue { return }
-
-        if classFile == NKCommon.TypeClassFile.image.rawValue {
-
-            originalImage = UIImage(contentsOfFile: fileNamePath)
-
-            scaleImagePreview = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizePreview, height: NCGlobal.shared.sizePreview))
-            scaleImageIcon = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon))
-
-            try? scaleImagePreview?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
-            try? scaleImageIcon?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
-
-        } else if classFile == NKCommon.TypeClassFile.video.rawValue {
-
-            let videoPath = NSTemporaryDirectory() + "tempvideo.mp4"
-            utilityFileSystem.linkItem(atPath: fileNamePath, toPath: videoPath)
-
-            originalImage = imageFromVideo(url: URL(fileURLWithPath: videoPath), at: 0)
-
-            try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
-            try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
-        }
-    }
-
     @objc func getVersionApp(withBuild: Bool = true) -> String {
         if let dictionary = Bundle.main.infoDictionary {
             if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
@@ -408,76 +209,6 @@ class NCUtility: NSObject {
         return ""
     }
 
-    func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage {
-
-        var image: UIImage?
-
-        // see https://stackoverflow.com/questions/71764255
-        let sfSymbolName = imageName.replacingOccurrences(of: "_", with: ".")
-        if let symbolConfiguration {
-            image = UIImage(systemName: sfSymbolName, withConfiguration: symbolConfiguration as? UIImage.Configuration)?.withTintColor(color, renderingMode: renderingMode)
-        } else {
-            image = UIImage(systemName: sfSymbolName)?.withTintColor(color, renderingMode: renderingMode)
-        }
-        if image == nil {
-            image = UIImage(named: imageName)?.image(color: color, size: size)
-        }
-        if let image {
-            return image
-        }
-
-        return  UIImage(named: "file")!.image(color: color, size: size)
-    }
-
-    @objc func loadUserImage(for user: String, displayName: String?, userBaseUrl: NCUserBaseUrl) -> UIImage {
-
-        let fileName = userBaseUrl.userBaseUrl + "-" + user + ".png"
-        let localFilePath = utilityFileSystem.directoryUserData + "/" + fileName
-
-        if var localImage = UIImage(contentsOfFile: localFilePath) {
-            let rect = CGRect(x: 0, y: 0, width: 30, height: 30)
-            UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
-            UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
-            localImage.draw(in: rect)
-            localImage = UIGraphicsGetImageFromCurrentImageContext() ?? localImage
-            UIGraphicsEndImageContext()
-            return localImage
-        } else if let loadedAvatar = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
-            return loadedAvatar
-        } else if let displayName = displayName, !displayName.isEmpty, let avatarImg = createAvatar(displayName: displayName, size: 30) {
-            return avatarImg
-        } else {
-            let config = UIImage.SymbolConfiguration(pointSize: 30)
-            return loadImage(named: "person.crop.circle", symbolConfiguration: config)
-        }
-    }
-
-    func createAvatar(displayName: String, size: CGFloat) -> UIImage? {
-        guard let initials = displayName.uppercaseInitials else {
-            return nil
-        }
-        let userColor = NCGlobal.shared.usernameToColor(displayName)
-        let rect = CGRect(x: 0, y: 0, width: size, height: size)
-        var avatarImage: UIImage?
-
-        UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
-        let context = UIGraphicsGetCurrentContext()
-        UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
-        context?.setFillColor(userColor)
-        context?.fill(rect)
-        let textStyle = NSMutableParagraphStyle()
-        textStyle.alignment = NSTextAlignment.center
-        let lineHeight = UIFont.systemFont(ofSize: UIFont.systemFontSize).pointSize
-        NSString(string: initials)
-            .draw(
-                in: CGRect(x: 0, y: (size - lineHeight) / 2, width: size, height: lineHeight),
-                withAttributes: [NSAttributedString.Key.paragraphStyle: textStyle])
-        avatarImage = UIGraphicsGetImageFromCurrentImageContext()
-        UIGraphicsEndImageContext()
-
-        return avatarImage
-    }
-
     /*
      Facebook's comparison algorithm:
      */
@@ -562,35 +293,6 @@ class NCUtility: NSObject {
         return isEqual
     }
 
-    func createFilePreviewImage(ocId: String, etag: String, fileNameView: String, classFile: String, status: Int, createPreviewMedia: Bool) -> UIImage? {
-
-        var imagePreview: UIImage?
-        let filePath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)
-        let iconImagePath = utilityFileSystem.getDirectoryProviderStorageIconOcId(ocId, etag: etag)
-
-        if FileManager().fileExists(atPath: iconImagePath) {
-            imagePreview = UIImage(contentsOfFile: iconImagePath)
-        } else if !createPreviewMedia {
-            return nil
-        } else if createPreviewMedia && status >= NCGlobal.shared.metadataStatusNormal && classFile == NKCommon.TypeClassFile.image.rawValue && FileManager().fileExists(atPath: filePath) {
-            if let image = UIImage(contentsOfFile: filePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon)), let data = image.jpegData(compressionQuality: 0.5) {
-                do {
-                    try data.write(to: URL(fileURLWithPath: iconImagePath), options: .atomic)
-                    imagePreview = image
-                } catch { }
-            }
-        } else if createPreviewMedia && status >= NCGlobal.shared.metadataStatusNormal && classFile == NKCommon.TypeClassFile.video.rawValue && FileManager().fileExists(atPath: filePath) {
-            if let image = imageFromVideo(url: URL(fileURLWithPath: filePath), at: 0), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon)), let data = image.jpegData(compressionQuality: 0.5) {
-                do {
-                    try data.write(to: URL(fileURLWithPath: iconImagePath), options: .atomic)
-                    imagePreview = image
-                } catch { }
-            }
-        }
-
-        return imagePreview
-    }
-
     func getLocation(latitude: Double, longitude: Double, completion: @escaping (String?) -> Void) {
         let geocoder = CLGeocoder()
         let llocation = CLLocation(latitude: latitude, longitude: longitude)
@@ -654,41 +356,4 @@ class NCUtility: NSObject {
         }
         return fileName
     }
-
-    func dateDiff(_ date: Date?) -> String {
-
-        guard let date else { return "" }
-        let today = Date()
-        var ti = date.timeIntervalSince(today)
-        ti = ti * -1
-        if ti < 60 {
-            return NSLocalizedString("_less_a_minute_", comment: "")
-        } else if ti < 3600 {
-            let diff = Int(round(ti / 60))
-            if diff == 1 {
-                return NSLocalizedString("_a_minute_ago_", comment: "")
-            } else {
-                return String.localizedStringWithFormat(NSLocalizedString("_minutes_ago_", comment: ""), diff)
-            }
-        } else if ti < 86400 {
-            let diff = Int(round(ti / 60))
-            if diff == 1 {
-                return NSLocalizedString("_an_hour_ago_", comment: "")
-            } else {
-                return String.localizedStringWithFormat(NSLocalizedString("_hours_ago_", comment: ""), diff)
-            }
-        } else if ti < 86400 * 30 {
-            let diff = Int(round(ti / 60 / 60 / 24))
-            if diff == 1 {
-                return NSLocalizedString("_a_day_ago_", comment: "")
-            } else {
-                return String.localizedStringWithFormat(NSLocalizedString("_days_ago_", comment: ""), diff)
-            }
-        } else {
-            let formatter = DateFormatter()
-            formatter.formatterBehavior = .behavior10_4
-            formatter.dateStyle = .medium
-            return formatter.string(from: date)
-        }
-    }
 }

+ 18 - 0
iOSClient/Utility/NCUtilityFileSystem.swift

@@ -594,4 +594,22 @@ class NCUtilityFileSystem: NSObject {
             }
         }
     }
+
+    func removeAllSettings() {
+
+        URLCache.shared.memoryCapacity = 0
+        URLCache.shared.diskCapacity = 0
+
+        NCManageDatabase.shared.clearDatabase(account: nil, removeAccount: true)
+
+        removeGroupDirectoryProviderStorage()
+        removeGroupLibraryDirectory()
+
+        removeDocumentsDirectory()
+        removeTemporaryDirectory()
+
+        createDirectoryStandard()
+
+        NCKeychain().removeAll()
+    }
 }