Browse Source

fix image cache

alqindiirsyam123 8 months ago
parent
commit
4a56515f1c

BIN
.DS_Store


BIN
ExampleCode/.DS_Store


BIN
NexilisLite/.DS_Store


+ 88 - 36
NexilisLite/NexilisLite/Source/Extension.swift

@@ -11,6 +11,7 @@ import UIKit
 import SDWebImage
 import ImageIO
 import MobileCoreServices
+import CommonCrypto
 
 extension Date {
     
@@ -547,10 +548,8 @@ extension String {
             let langDefault = UserDefaults.standard.stringArray(forKey: "AppleLanguages")
             if langDefault![0].contains("id") {
                 SecureUserDefaults.shared.set("id", forKey: "i18n_language")
-                SecureUserDefaults.shared.sync()
             } else {
                 SecureUserDefaults.shared.set("en", forKey: "i18n_language")
-                SecureUserDefaults.shared.sync()
             }
         }
         let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? ""
@@ -1311,63 +1310,116 @@ public class ImageCache {
     public static let shared = ImageCache()
     private let cache = NSCache<NSString, UIImage>()
     private let cacheGif = NSCache<NSString, NSData>()
+    private var cacheKeyMap: [String: String] = [:]
 
     private init() {
-        loadCache()
-        NotificationCenter.default.addObserver(self, selector: #selector(saveCache), name: UIApplication.didEnterBackgroundNotification, object: nil)
+        if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
+            let cacheDirectory = documentsDirectory.appendingPathComponent("fileCacheImage")
+            loadCacheFromDisk(directory: cacheDirectory)
+            
+            let cacheGifDirectory = documentsDirectory.appendingPathComponent("fileCacheGif")
+            loadCacheFromDisk(directory: cacheGifDirectory)
+        }
     }
 
     public func save(image: UIImage, forKey key: String) {
-        cache.setObject(image, forKey: key as NSString)
-        cacheKeys.append(key)
-        saveCache()
+        let sanitizedKey = sanitizeKey(key)
+        cache.setObject(image, forKey: sanitizedKey as NSString)
+        cacheKeyMap[key] = sanitizedKey
+        if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
+            let cacheDirectory = documentsDirectory.appendingPathComponent("fileCacheImage")
+            saveCacheToDisk(directory: cacheDirectory)
+        }
     }
     
     public func saveGif(data: NSData, forKey key: String) {
-        cacheGif.setObject(data, forKey: key as NSString)
-        cacheKeys.append(key)
-        saveCache()
+        let sanitizedKey = sanitizeKey(key)
+        cacheGif.setObject(data, forKey: sanitizedKey as NSString)
+        cacheKeyMap[key] = sanitizedKey
+        if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
+            let cacheDirectory = documentsDirectory.appendingPathComponent("fileCacheGif")
+            saveCacheToDisk(directory: cacheDirectory)
+        }
     }
 
     public func image(forKey key: String) -> UIImage? {
-        return cache.object(forKey: key as NSString)
+        let sanitizedKey = sanitizeKey(key)
+        return cache.object(forKey: sanitizedKey as NSString)
     }
     public func imageGif(forKey key: String) -> NSData? {
-        return cacheGif.object(forKey: key as NSString)
+        let sanitizedKey = sanitizeKey(key)
+        return cacheGif.object(forKey: sanitizedKey as NSString)
     }
     
-    private var cacheKeys: [String] = []
-    private func loadCache() {
-        if let cachedData: Data = SecureUserDefaults.shared.value(forKey: "imageCache") {
-            if let decodedCache = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(cachedData) as? [String: Data] {
-                for (key, valueData) in decodedCache {
-                    if let image = UIImage(data: valueData) {
-                        cache.setObject(image, forKey: key as NSString)
-                        cacheKeys.append(key)
-                    }
-                    let dataGif = NSData(data: valueData)
-                    cacheGif.setObject(dataGif, forKey: key as NSString)
-                    cacheKeys.append(key)
+    func saveCacheToDisk(directory: URL) {
+        let fileManager = FileManager.default
+
+        if !fileManager.fileExists(atPath: directory.path) {
+            do {
+                try fileManager.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
+            } catch {
+                return
+            }
+        }
+
+        let mappingFilePath = directory.appendingPathComponent("keyMapping.json")
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: cacheKeyMap, options: [])
+            try jsonData.write(to: mappingFilePath)
+        } catch {
+            return
+        }
+
+        for (originalKey, sanitizedKey) in cacheKeyMap {
+            if let image = cache.object(forKey: sanitizedKey as NSString),
+               let imageData = image.pngData() {
+                let filePath = directory.appendingPathComponent("\(sanitizedKey).png")
+                do {
+                    try imageData.write(to: filePath)
+                } catch {
                 }
             }
         }
     }
+    
+    func loadCacheFromDisk(directory: URL) {
+        let fileManager = FileManager.default
 
-    @objc private func saveCache() {
-        var cacheDictionary = [String: Data]()
-        for key in cacheKeys {
-            if let dataGif = cacheGif.object(forKey: key as NSString) {
-                cacheDictionary[key] = Data(referencing: dataGif)
-            } else {
-                if let image = cache.object(forKey: key as NSString) {
-                    if let imageData = image.pngData() {
-                        cacheDictionary[key] = imageData
-                    }
+        // Load mapping
+        let mappingFilePath = directory.appendingPathComponent("keyMapping.json")
+        guard let jsonData = try? Data(contentsOf: mappingFilePath),
+              let loadedMapping = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] else {
+            return
+        }
+
+        if cacheKeyMap.count == 0 {
+            cacheKeyMap = loadedMapping
+        }
+
+        // Load images
+        do {
+            let fileURLs = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil)
+            for fileURL in fileURLs {
+                if fileURL.lastPathComponent == "keyMapping.json" { continue } // Skip mapping file
+
+                let sanitizedKey = fileURL.deletingPathExtension().lastPathComponent
+                if let imageData = try? Data(contentsOf: fileURL),
+                   let image = UIImage(data: imageData) {
+                    cache.setObject(image, forKey: sanitizedKey as NSString)
                 }
             }
+        } catch {
+//            print("Failed to load cache from disk: \(error)")
+        }
+    }
+    
+    private func sanitizeKey(_ key: String) -> String {
+        let data = Data(key.utf8)
+        var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
+        data.withUnsafeBytes {
+            _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
         }
-        let encodedData = try? NSKeyedArchiver.archivedData(withRootObject: cacheDictionary, requiringSecureCoding: false)
-        SecureUserDefaults.shared.set(encodedData, forKey: "imageCache")
+        return hash.map { String(format: "%02x", $0) }.joined()
     }
 }
 

+ 0 - 2
NexilisLite/NexilisLite/Source/IncomingThread.swift

@@ -241,12 +241,10 @@ class IncomingThread {
 //                            Nexilis.changeUser(f_pin: id)
                     SecureUserDefaults.shared.set(id, forKey: "me")
                     Utils.setProfile(value: false)
-                    SecureUserDefaults.shared.sync()
                     if Utils.getForceAnonymous() {
                         viewController?.deleteAllRecordDatabase()
                         SecureUserDefaults.shared.removeValue(forKey: "device_id")
                         Nexilis.destroyAll()
-                        _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
                     }
                     DispatchQueue.main.async {
                         Nexilis.hideLoader(completion: {

+ 0 - 1
NexilisLite/NexilisLite/Source/Utils.swift

@@ -1823,7 +1823,6 @@ public class DialogVerifyYou: UIViewController {
                         Utils.setLoginMultipleFPin(value: "")
                         SecureUserDefaults.shared.set(device_id, forKey: "device_id")
                         Utils.setProfile(value: true)
-                        SecureUserDefaults.shared.sync()
                         // pos registration
                         _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: fPin))
                         DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {

+ 46 - 7
NexilisLite/NexilisLite/Source/View/Control/ChangeDeviceViewController.swift

@@ -150,10 +150,9 @@ public class ChangeDeviceViewController: UIViewController {
                         if(!id.isEmpty) {
 //                            Nexilis.changeUser(f_pin: id)
                             Utils.setProfile(value: true)
-                            SecureUserDefaults.shared.sync()
                             // pos registration
                             _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
-                            DispatchQueue.main.async {
+                            DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                                 Nexilis.hideLoader(completion: {
                                     let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
                                     imageView.tintColor = .white
@@ -179,7 +178,7 @@ public class ChangeDeviceViewController: UIViewController {
                                     }
                                     self.isDismiss?(thumb)
                                 })
-                            }
+                            })
                         }
                     }
                 } else {
@@ -267,18 +266,58 @@ public class ChangeDeviceViewController: UIViewController {
                 } else {
                     self.deleteAllRecordDatabase()
                     let id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
+                    let f_pin = response.getBody(key: CoreMessage_TMessageKey.F_PIN_REAL, default_value: "")
                     let thumb = response.getBody(key: CoreMessage_TMessageKey.THUMB_ID, default_value: "")
                     let device_id = response.getBody(key: CoreMessage_TMessageKey.IMEI, default_value: id)
                     let last_sign = response.getBody(key: CoreMessage_TMessageKey.LAST_SIGN, default_value: "0")
                     //print("last sign: \(last_sign)")
+                    if last_sign != "0" {
+                        Utils.setLoginMultipleFPin(value: f_pin)
+                        DispatchQueue.main.async {
+                            let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
+                            imageView.tintColor = .white
+                            let banner = FloatingNotificationBanner(title: "Multiple Login Detected...".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .info, colors: nil, iconPosition: .center)
+                            banner.show()
+                        }
+                        DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
+                            Nexilis.hideLoader(completion: {
+                                if Nexilis.showFB {
+                                    Nexilis.floatingButton.removeFromSuperview()
+                                    Nexilis.floatingButton = FloatingButton()
+                                    let viewController = (UIApplication.shared.windows.first?.rootViewController)!
+                                    Nexilis.addFB(viewController: viewController, fromMAB: true)
+                                }
+                                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil, userInfo: nil)
+                                if self.fromChangeNamePass{
+                                    var vc = self.navigationController?.presentingViewController
+                                    while vc?.presentingViewController != nil {
+                                        vc = vc?.presentingViewController
+                                    }
+                                    vc?.dismiss(animated: true, completion: nil)
+                                }
+                                else if !self.forceLogin {
+                                    self.navigationController?.popViewController(animated: true)
+                                } else {
+                                    self.navigationController?.dismiss(animated: true)
+                                }
+                                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
+                                    let dialog = DialogUnableAccess()
+                                    dialog.modalTransitionStyle = .crossDissolve
+                                    dialog.modalPresentationStyle = .overCurrentContext
+                                    UIApplication.shared.visibleViewController?.present(dialog, animated: true)
+                                })
+                            })
+                        })
+                        return
+                    }
+                    self.deleteAllRecordDatabase()
                     if(!id.isEmpty) {
-//                        Nexilis.changeUser(f_pin: device_id)
+//                            Nexilis.changeUser(f_pin: device_id)
                         SecureUserDefaults.shared.set(device_id, forKey: "device_id")
                         Utils.setProfile(value: true)
-                        SecureUserDefaults.shared.sync()
                         // pos registration
                         _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
-                        DispatchQueue.main.async {
+                        DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                             Nexilis.hideLoader(completion: {
                                 let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
                                 imageView.tintColor = .white
@@ -305,7 +344,7 @@ public class ChangeDeviceViewController: UIViewController {
                                 }
                                 self.isDismiss?(thumb)
                             })
-                        }
+                        })
                     }
                 }
             } else {

+ 0 - 1
NexilisLite/NexilisLite/Source/View/Control/ChangeNamePassswordViewController.swift

@@ -164,7 +164,6 @@ public class ChangeNamePassswordViewController: UIViewController {
                                 }
                             })
                             Utils.setProfile(value: true)
-                            SecureUserDefaults.shared.sync()
         //                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateFifthTab"), object: nil, userInfo: nil)
                             DispatchQueue.main.async {
                                 Nexilis.hideLoader(completion: {

+ 0 - 1
NexilisLite/NexilisLite/Source/View/Control/SettingTableViewController.swift

@@ -534,7 +534,6 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
 //                            Nexilis.changeUser(f_pin: id)
                             SecureUserDefaults.shared.set(id, forKey: "me")
                             Utils.setProfile(value: false)
-                            SecureUserDefaults.shared.sync()
                             if Utils.getForceAnonymous() {
                                 self.deleteAllRecordDatabase()
                                 SecureUserDefaults.shared.removeValue(forKey: "device_id")

+ 2 - 5
NexilisLite/NexilisLite/Source/View/Control/SignUpSignIn.swift

@@ -157,10 +157,9 @@ public class SignUpSignIn: UIViewController {
                         if(!id.isEmpty) {
 //                            Nexilis.changeUser(f_pin: id)
                             Utils.setProfile(value: true)
-                            SecureUserDefaults.shared.sync()
                             // pos registration
                             _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
-                            DispatchQueue.main.async {
+                            DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                                 Nexilis.hideLoader(completion: {
                                     let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
                                     imageView.tintColor = .white
@@ -186,7 +185,7 @@ public class SignUpSignIn: UIViewController {
                                     }
                                     self.isDismiss?(thumb)
                                 })
-                            }
+                            })
                         }
                     }
                 } else {
@@ -364,7 +363,6 @@ public class SignUpSignIn: UIViewController {
 //                            Nexilis.changeUser(f_pin: device_id)
                             SecureUserDefaults.shared.set(device_id, forKey: "device_id")
                             Utils.setProfile(value: true)
-                            SecureUserDefaults.shared.sync()
                             // pos registration
                             _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
                             DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
@@ -413,7 +411,6 @@ public class SignUpSignIn: UIViewController {
                             }
                         })
                         Utils.setProfile(value: true)
-                        SecureUserDefaults.shared.sync()
     //                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateFifthTab"), object: nil, userInfo: nil)
                         DispatchQueue.main.async {
                             Nexilis.hideLoader(completion: {