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

fix bugs and release for 5.0.72

alqindiirsyam 1 сар өмнө
parent
commit
b76c34dbd4

+ 4 - 4
AppBuilder/AppBuilder.xcodeproj/project.pbxproj

@@ -568,7 +568,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 5.0.71;
+				MARKETING_VERSION = 5.0.72;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -604,7 +604,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 5.0.71;
+				MARKETING_VERSION = 5.0.72;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -640,7 +640,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.71;
+				MARKETING_VERSION = 5.0.72;
 				OTHER_CFLAGS = "-fstack-protector-strong";
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -679,7 +679,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.71;
+				MARKETING_VERSION = 5.0.72;
 				OTHER_CFLAGS = "-fstack-protector-strong";
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 8 - 1
NexilisLite/NexilisLite/Source/APIS.swift

@@ -580,6 +580,10 @@ public class APIS: NSObject {
         return mfaCallback
     }
     
+    static func setMFACallback(mfaCallback: @escaping (Int) -> Void) {
+        self.mfaCallback = mfaCallback
+    }
+    
     public static func signUp(userId: String, mfaCallback: @escaping (Int) -> Void) {
         self.mfaCallback = mfaCallback
         let method = "Sign Up"
@@ -602,7 +606,10 @@ public class APIS: NSObject {
         if !methodSetted.isEmpty {
             method = methodSetted
         }
-        let dataTxn = Utils.getTxnLevel()
+        var dataTxn = Utils.getTxnLevel()
+        dataTxn = dataTxn.replacingOccurrences(of: "\\\"", with: "\"")
+                                    .replacingOccurrences(of: "\"[", with: "[")
+                                    .replacingOccurrences(of: "]\"", with: "]")
         var policyLevel = "1,2"
 //        print("txnAuth: \(dataTxn)")
         if !dataTxn.isEmpty {

+ 1 - 1
NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -19,7 +19,7 @@ import CryptoKit
 import WebKit
 
 public class Nexilis: NSObject {
-    public static var cpaasVersion = "5.0.71"
+    public static var cpaasVersion = "5.0.72"
     public static var sAPIKey = ""
     
     public static var ADDRESS = ""

+ 33 - 3
NexilisLite/NexilisLite/Source/View/Chat/ChatGPTBotView.swift

@@ -61,6 +61,7 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
     var lastScrollIdxSearch = 0
     var buttonUp: UIButton!
     var buttonDown: UIButton!
+    var amountTx = "0"
     
     public var fromNotification = true
     
@@ -277,8 +278,11 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
     @objc func sendTapped() {
         if self.chatGPTMessages.last?["confirmation"] as? String == "1" {
             DispatchQueue.global().async {
-                let dataTxn = Utils.getTxnLevel()
+                var dataTxn = Utils.getTxnLevel()
                 var policyLevel = "1,2"
+                dataTxn = dataTxn.replacingOccurrences(of: "\\\"", with: "\"")
+                                            .replacingOccurrences(of: "\"[", with: "[")
+                                            .replacingOccurrences(of: "]\"", with: "]")
                 if !dataTxn.isEmpty {
                     if let data = dataTxn.data(using: .utf8) {
                         do {
@@ -288,7 +292,7 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                                     let min = json["min"] as? Double ?? 0
                                     let max = json["max"] as? Double ?? 0
                                     let policy = json["policy"] as? String ?? ""
-                                    let amount = 0.0
+                                    let amount = Double(self.amountTx) ?? 0.0
                                     if max == -1 {
                                         if amount >= min {
                                             policyLevel = policy
@@ -309,7 +313,7 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                 }
                 var isBiometricOn = false
                 var result = false
-                if policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
+                if policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
                     isBiometricOn = true
                 }
                 if isBiometricOn {
@@ -322,6 +326,28 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                         semaphore.signal()
                     }
 
+                    semaphore.wait()
+                } else if policyLevel == MFAViewController.STEP_FIDO_PWD || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER {
+                    let semaphore = DispatchSemaphore(value: 0)
+                    APIS.setMFACallback { res in
+                        if res == 0 {
+                            result = true
+                        }
+                        semaphore.signal()
+                    }
+                    DispatchQueue.main.async {
+                        let controller = MFAViewController()
+                        controller.METHOD = ""
+                        controller.STEP_NEEDED = policyLevel
+                        let navigationController = CustomNavigationController(rootViewController: controller)
+                        navigationController.defaultStyle()
+                        
+                        if UIApplication.shared.visibleViewController?.navigationController != nil {
+                            UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
+                        } else {
+                            UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
+                        }
+                    }
                     semaphore.wait()
                 } else {
                     result = true
@@ -462,6 +488,10 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                             DispatchQueue.main.async {
                                 self.dataMessages.removeAll(where: { $0["is_loading"] as? Bool == true })
                                 self.tableChatView.reloadData()
+                                if json["parameters"] != nil {
+                                    let param = json["parameters"] as! [String: Any]
+                                    self.amountTx = param["amount"] as? String ?? "0"
+                                }
                                 self.chatGPTMessages.append(json)
                                 guard let me = User.getMyPin() else {
                                     return

+ 55 - 30
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -4084,7 +4084,7 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             if (Nexilis.checkingAccess(key: "secure_folder_forward") || (!(dataMessages[indexPath!.row][TypeDataMessage.message_text]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["image_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["video_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["file_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["audio_id"]  as? String ?? "").isEmpty) || (dataMessages[indexPath!.row][TypeDataMessage.spec_file] as? String ?? "").contains("forward")) && dataMessages[indexPath!.row]["read_receipts"] as? String != "8" && dataMessages[indexPath!.row]["attachment_flag"] as? String ?? "" != "11" {
                 children.insert(forward, at: 2)
             }
-            if dataMessages[indexPath!.row]["f_pin"] as? String ?? "" != "-999" && dataMessages[indexPath!.row]["f_pin"] as? String != User.getMyPin() && dataMessages[indexPath!.row]["attachment_flag"]  as? String ?? "" != "11" {
+            if dataMessages[indexPath!.row]["f_pin"] as? String ?? "" != "-999" && dataMessages[indexPath!.row]["f_pin"] as? String != User.getMyPin() && dataMessages[indexPath!.row]["attachment_flag"]  as? String ?? "" != "11" && dataMessages[indexPath!.row]["f_pin"] as? String ?? "" != "-997" {
                 children.insert(replyP, at: 2)
             }
             if (dataMessages[indexPath!.row]["f_pin"]  as? String ?? "") == idMe {
@@ -4092,11 +4092,17 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             }
             if !(dataMessages[indexPath!.row][TypeDataMessage.message_text]  as? String ?? "").isEmpty {
                 if (dataMessages[indexPath!.row]["f_pin"]  as? String ?? "") == idMe && ((dataMessages[indexPath!.row][TypeDataMessage.is_forwarded] as? Int) ?? 0) == 0 && (dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as? String ?? "") != "11" {
-                    let valueDate = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
-                    let nowDate = Date()
-                    let diffInSeconds = nowDate.timeIntervalSince(valueDate)
-                    if diffInSeconds <= 15 * 60 {
-                        children.insert(edit, at: children.count - 1)
+                    var textFile = dataMessages[indexPath!.row][TypeDataMessage.message_text] as? String ?? ""
+                    if !(dataMessages[indexPath!.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                        textFile = textFile.components(separatedBy: "|")[1]
+                    }
+                    if !textFile.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                        let valueDate = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
+                        let nowDate = Date()
+                        let diffInSeconds = nowDate.timeIntervalSince(valueDate)
+                        if diffInSeconds <= 15 * 60 {
+                            children.insert(edit, at: children.count - 1)
+                        }
                     }
                 }
                 if (dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as? String ?? "") != "11" && (dataMessages[indexPath!.row]["image_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["video_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["file_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["audio_id"]  as? String ?? "").isEmpty{
@@ -4234,7 +4240,10 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
         listMentionWithText.removeAll()
         listMentionInTextField.removeAll()
         let dataMessages = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
-        let oldText = dataMessages[indexPath.row][TypeDataMessage.message_text]  as? String ?? ""
+        var oldText = dataMessages[indexPath.row][TypeDataMessage.message_text]  as? String ?? ""
+        if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+            oldText = oldText.components(separatedBy: "|")[1]
+        }
         var oldTextForTextview = oldText
         let pattern = "@[\\w]+"
         do {
@@ -4342,6 +4351,10 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             buttonSendEdit.actionHandle(controlEvents: .touchUpInside,
              ForAction:{() -> Void in
                 var newText = self.editTextView.text ?? ""
+                if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                    let firstText = dataMessages[indexPath.row][TypeDataMessage.message_text] as? String ?? ""
+                    newText = firstText.components(separatedBy: "|")[0] + "|" + newText
+                }
                 if newText.contains("@") && self.listMentionInTextField.count > 0 {
                     var diff: Int = 0
                     for i in 0..<self.listMentionInTextField.count {
@@ -4374,28 +4387,38 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
                     }
                 }
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
-                    let lastEdited = Int64(Date().currentTimeMillis())
-                    let message = CoreMessage_TMessageBank.editMessage(message_id: dataMessages[indexPath.row][TypeDataMessage.message_id]  as? String ?? "", l_pin: dataMessages[indexPath.row][TypeDataMessage.l_pin]  as? String ?? "", message_scope_id: dataMessages[indexPath.row][TypeDataMessage.message_scope_id]  as? String ?? "", status: "1", message_text: newText, credential: dataMessages[indexPath.row][TypeDataMessage.credential]  as? String ?? "", attachment_flag: dataMessages[indexPath.row][TypeDataMessage.attachment_flag]  as? String ?? "", ex_blog_id: dataMessages[indexPath.row][TypeDataMessage.blog_id]  as? String ?? "", message_large_text: "", ex_format: "", image_id: dataMessages[indexPath.row][TypeDataMessage.image_id]  as? String ?? "", audio_id: dataMessages[indexPath.row][TypeDataMessage.audio_id]  as? String ?? "", video_id: dataMessages[indexPath.row][TypeDataMessage.video_id]  as? String ?? "", file_id: dataMessages[indexPath.row][TypeDataMessage.file_id]  as? String ?? "", thumb_id: dataMessages[indexPath.row][TypeDataMessage.thumb_id]  as? String ?? "", reff_id: dataMessages[indexPath.row][TypeDataMessage.reff_id]  as? String ?? "", read_receipts: dataMessages[indexPath.row][TypeDataMessage.read_receipts]  as? String ?? "", chat_id: dataMessages[indexPath.row][TypeDataMessage.chat_id]  as? String ?? "", is_call_center: dataMessages[indexPath.row][TypeDataMessage.is_call_center]  as? String ?? "", call_center_id: dataMessages[indexPath.row][TypeDataMessage.call_center_id]  as? String ?? "", opposite_pin: dataMessages[indexPath.row][TypeDataMessage.opposite_pin]  as? String ?? "", server_date: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", local_time_stamp: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", last_edit: lastEdited)
-                    Nexilis.addQueueMessage(message: message, isEditMessage: true)
-                    DispatchQueue.global().async {
-                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                            do {
-                                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
-                                    "message_text" : newText,
-                                    "last_edited" : lastEdited
-                                ], _where: "message_id = '\(dataMessages[indexPath.row]["message_id"]  as? String ?? "")'")
-                                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-                            } catch {
-                                rollback.pointee = true
-                                print("Access database error: \(error.localizedDescription)")
-                            }
-                        })
+                    if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                        let firstText = dataMessages[indexPath.row][TypeDataMessage.message_text] as? String ?? ""
+                        if newText != firstText {
+                            excEdit()
+                        }
+                    } else {
+                        excEdit()
                     }
-                    let idx = self.dataMessages.firstIndex(where: { $0[TypeDataMessage.message_id] as? String == dataMessages[indexPath.row][TypeDataMessage.message_id] as? String})
-                    if idx != nil{
-                        self.dataMessages[idx!][TypeDataMessage.message_text] = newText
-                        self.dataMessages[idx!][TypeDataMessage.last_edit] = lastEdited
-                        self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                    func excEdit() {
+                        let lastEdited = Int64(Date().currentTimeMillis())
+                        let message = CoreMessage_TMessageBank.editMessage(message_id: dataMessages[indexPath.row][TypeDataMessage.message_id]  as? String ?? "", l_pin: dataMessages[indexPath.row][TypeDataMessage.l_pin]  as? String ?? "", message_scope_id: dataMessages[indexPath.row][TypeDataMessage.message_scope_id]  as? String ?? "", status: "1", message_text: newText, credential: dataMessages[indexPath.row][TypeDataMessage.credential]  as? String ?? "", attachment_flag: dataMessages[indexPath.row][TypeDataMessage.attachment_flag]  as? String ?? "", ex_blog_id: dataMessages[indexPath.row][TypeDataMessage.blog_id]  as? String ?? "", message_large_text: "", ex_format: "", image_id: dataMessages[indexPath.row][TypeDataMessage.image_id]  as? String ?? "", audio_id: dataMessages[indexPath.row][TypeDataMessage.audio_id]  as? String ?? "", video_id: dataMessages[indexPath.row][TypeDataMessage.video_id]  as? String ?? "", file_id: dataMessages[indexPath.row][TypeDataMessage.file_id]  as? String ?? "", thumb_id: dataMessages[indexPath.row][TypeDataMessage.thumb_id]  as? String ?? "", reff_id: dataMessages[indexPath.row][TypeDataMessage.reff_id]  as? String ?? "", read_receipts: dataMessages[indexPath.row][TypeDataMessage.read_receipts]  as? String ?? "", chat_id: dataMessages[indexPath.row][TypeDataMessage.chat_id]  as? String ?? "", is_call_center: dataMessages[indexPath.row][TypeDataMessage.is_call_center]  as? String ?? "", call_center_id: dataMessages[indexPath.row][TypeDataMessage.call_center_id]  as? String ?? "", opposite_pin: dataMessages[indexPath.row][TypeDataMessage.opposite_pin]  as? String ?? "", server_date: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", local_time_stamp: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", last_edit: lastEdited)
+                        Nexilis.addQueueMessage(message: message, isEditMessage: true)
+                        DispatchQueue.global().async {
+                            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                do {
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                                        "message_text" : newText,
+                                        "last_edited" : lastEdited
+                                    ], _where: "message_id = '\(dataMessages[indexPath.row]["message_id"]  as? String ?? "")'")
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                                } catch {
+                                    rollback.pointee = true
+                                    print("Access database error: \(error.localizedDescription)")
+                                }
+                            })
+                        }
+                        let idx = self.dataMessages.firstIndex(where: { $0[TypeDataMessage.message_id] as? String == dataMessages[indexPath.row][TypeDataMessage.message_id] as? String})
+                        if idx != nil{
+                            self.dataMessages[idx!][TypeDataMessage.message_text] = newText
+                            self.dataMessages[idx!][TypeDataMessage.last_edit] = lastEdited
+                            self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                        }
                     }
                 }
                 self.isEditingMessage = false
@@ -7253,6 +7276,8 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
         let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
         let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
         let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+        let indexPath = sender.indexPath
+        let dataMessages = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
         func showMedia(data: Data? = nil, url: URL? = nil, type: Int = 0) {
             let image = UIImage(data: data ?? Data())
             let imageViewer = MediaViewerViewController()
@@ -7275,7 +7300,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
             }
             let backButton = UIBarButtonItem(title: nil, image: UIImage(systemName: "chevron.backward"), primaryAction: backAction, menu: nil)
             imageViewer.navigationItem.leftBarButtonItem = backButton
-            if Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share") {
+            if (Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share")) && dataMessages[indexPath.row]["credential"] as? String != "1" {
                 let shareAction = UIAction { _ in
                     var activityViewController = UIActivityViewController(activityItems: [""], applicationActivities: nil)
                     if type == 1 {
@@ -7468,7 +7493,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
                 }
                 let backButton = UIBarButtonItem(title: nil, image: UIImage(systemName: "chevron.backward"), primaryAction: backAction, menu: nil)
                 vcHandleFile.navigationItem.leftBarButtonItem = backButton
-                if Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share") {
+                if (Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share")) && dataMessages[indexPath.row]["credential"] as? String != "1" {
                     let shareAction = UIAction { _ in
                         let fileManager = FileManager.default
                         let tempURL = fileManager.temporaryDirectory.appendingPathComponent(urlFile.lastPathComponent)

+ 76 - 48
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -42,7 +42,12 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     @IBOutlet weak var heightTableMention: NSLayoutConstraint!
     @IBOutlet weak var contraintBottomMention: NSLayoutConstraint!
     public var dataPerson: [String: String?] = [:]
-    var dataMessages: [[String: Any?]] = []
+    var dataMessages: [[String: Any?]] = [] {
+        didSet {
+            groupMessagesByDate()
+        }
+    }
+    var messagesByDate: [String: [[String: Any?]]] = [:]
     var dataDates: [String] = []
     var users: [User] = []
     public var dataMessageForward: [[String: Any?]]?
@@ -162,6 +167,18 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         return CGFloat(fontSize)
     }
     
+    private func groupMessagesByDate() {
+        messagesByDate = Dictionary(
+            grouping: dataMessages.compactMap { (msg: [String: Any?]) -> [String: Any?]? in
+                guard let _ = msg["chat_date"] as? String else { return nil }
+                return msg
+            },
+            by: { (msg: [String: Any?]) -> String in
+                return msg["chat_date"] as! String
+            }
+        )
+    }
+    
     public override func viewDidDisappear(_ animated: Bool) {
         if self.isMovingFromParent {
             removeAllObjectBeforeDismissVC()
@@ -5494,11 +5511,17 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             }
             if !(dataMessages[indexPath!.row][TypeDataMessage.message_text]  as? String ?? "").isEmpty {
                 if (dataMessages[indexPath!.row]["f_pin"]  as? String ?? "") == idMe && ((dataMessages[indexPath!.row][TypeDataMessage.is_forwarded] as? Int) ?? 0) == 0 && (dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as? String ?? "") != "11" {
-                    let valueDate = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
-                    let nowDate = Date()
-                    let diffInSeconds = nowDate.timeIntervalSince(valueDate)
-                    if diffInSeconds <= 15 * 60 {
-                        children.insert(edit, at: children.count - 1)
+                    var textFile = dataMessages[indexPath!.row][TypeDataMessage.message_text] as? String ?? ""
+                    if !(dataMessages[indexPath!.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                        textFile = textFile.components(separatedBy: "|")[1]
+                    }
+                    if !textFile.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                        let valueDate = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
+                        let nowDate = Date()
+                        let diffInSeconds = nowDate.timeIntervalSince(valueDate)
+                        if diffInSeconds <= 15 * 60 {
+                            children.insert(edit, at: children.count - 1)
+                        }
                     }
                 }
                 if (dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as? String ?? "") != "11" && (dataMessages[indexPath!.row]["image_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["video_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["file_id"]  as? String ?? "").isEmpty && (dataMessages[indexPath!.row]["audio_id"]  as? String ?? "").isEmpty{
@@ -5585,7 +5608,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
         listMentionWithText.removeAll()
         listMentionInTextField.removeAll()
         let dataMessages = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
-        let oldText = dataMessages[indexPath.row][TypeDataMessage.message_text]  as? String ?? ""
+        var oldText = dataMessages[indexPath.row][TypeDataMessage.message_text]  as? String ?? ""
+        if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+            oldText = oldText.components(separatedBy: "|")[1]
+        }
         var oldTextForTextview = oldText
         let pattern = "@[\\w]+"
         do {
@@ -5689,6 +5715,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             buttonSendEdit.actionHandle(controlEvents: .touchUpInside,
              ForAction:{() -> Void in
                 var newText = self.editTextView.text ?? ""
+                if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                    let firstText = dataMessages[indexPath.row][TypeDataMessage.message_text] as? String ?? ""
+                    newText = firstText.components(separatedBy: "|")[0] + "|" + newText
+                }
                 if newText.contains("@") && self.listMentionInTextField.count > 0 {
                     var diff: Int = 0
                     for i in 0..<self.listMentionInTextField.count {
@@ -5721,28 +5751,38 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
                     }
                 }
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
-                    let lastEdited = Int64(Date().currentTimeMillis())
-                    let message = CoreMessage_TMessageBank.editMessage(message_id: dataMessages[indexPath.row][TypeDataMessage.message_id]  as? String ?? "", l_pin: dataMessages[indexPath.row][TypeDataMessage.l_pin]  as? String ?? "", message_scope_id: dataMessages[indexPath.row][TypeDataMessage.message_scope_id]  as? String ?? "", status: "1", message_text: newText, credential: dataMessages[indexPath.row][TypeDataMessage.credential]  as? String ?? "", attachment_flag: dataMessages[indexPath.row][TypeDataMessage.attachment_flag]  as? String ?? "", ex_blog_id: dataMessages[indexPath.row][TypeDataMessage.blog_id]  as? String ?? "", message_large_text: "", ex_format: "", image_id: dataMessages[indexPath.row][TypeDataMessage.image_id]  as? String ?? "", audio_id: dataMessages[indexPath.row][TypeDataMessage.audio_id]  as? String ?? "", video_id: dataMessages[indexPath.row][TypeDataMessage.video_id]  as? String ?? "", file_id: dataMessages[indexPath.row][TypeDataMessage.file_id]  as? String ?? "", thumb_id: dataMessages[indexPath.row][TypeDataMessage.thumb_id]  as? String ?? "", reff_id: dataMessages[indexPath.row][TypeDataMessage.reff_id]  as? String ?? "", read_receipts: dataMessages[indexPath.row][TypeDataMessage.read_receipts]  as? String ?? "", chat_id: dataMessages[indexPath.row][TypeDataMessage.chat_id]  as? String ?? "", is_call_center: dataMessages[indexPath.row][TypeDataMessage.is_call_center]  as? String ?? "", call_center_id: dataMessages[indexPath.row][TypeDataMessage.call_center_id]  as? String ?? "", opposite_pin: dataMessages[indexPath.row][TypeDataMessage.opposite_pin]  as? String ?? "", server_date: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", local_time_stamp: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", last_edit: lastEdited)
-                    Nexilis.addQueueMessage(message: message, isEditMessage: true)
-                    DispatchQueue.global().async {
-                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                            do {
-                                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
-                                    "message_text" : newText,
-                                    "last_edited" : lastEdited
-                                ], _where: "message_id = '\(dataMessages[indexPath.row]["message_id"]  as? String ?? "")'")
-                                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-                            } catch {
-                                rollback.pointee = true
-                                print("Access database error: \(error.localizedDescription)")
-                            }
-                        })
+                    if !(dataMessages[indexPath.row][TypeDataMessage.file_id] as? String ?? "").isEmpty {
+                        let firstText = dataMessages[indexPath.row][TypeDataMessage.message_text] as? String ?? ""
+                        if newText != firstText {
+                            excEdit()
+                        }
+                    } else {
+                        excEdit()
                     }
-                    let idx = self.dataMessages.firstIndex(where: { $0[TypeDataMessage.message_id] as? String == dataMessages[indexPath.row][TypeDataMessage.message_id] as? String})
-                    if idx != nil{
-                        self.dataMessages[idx!][TypeDataMessage.message_text] = newText
-                        self.dataMessages[idx!][TypeDataMessage.last_edit] = lastEdited
-                        self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                    func excEdit() {
+                        let lastEdited = Int64(Date().currentTimeMillis())
+                        let message = CoreMessage_TMessageBank.editMessage(message_id: dataMessages[indexPath.row][TypeDataMessage.message_id]  as? String ?? "", l_pin: dataMessages[indexPath.row][TypeDataMessage.l_pin]  as? String ?? "", message_scope_id: dataMessages[indexPath.row][TypeDataMessage.message_scope_id]  as? String ?? "", status: "1", message_text: newText, credential: dataMessages[indexPath.row][TypeDataMessage.credential]  as? String ?? "", attachment_flag: dataMessages[indexPath.row][TypeDataMessage.attachment_flag]  as? String ?? "", ex_blog_id: dataMessages[indexPath.row][TypeDataMessage.blog_id]  as? String ?? "", message_large_text: "", ex_format: "", image_id: dataMessages[indexPath.row][TypeDataMessage.image_id]  as? String ?? "", audio_id: dataMessages[indexPath.row][TypeDataMessage.audio_id]  as? String ?? "", video_id: dataMessages[indexPath.row][TypeDataMessage.video_id]  as? String ?? "", file_id: dataMessages[indexPath.row][TypeDataMessage.file_id]  as? String ?? "", thumb_id: dataMessages[indexPath.row][TypeDataMessage.thumb_id]  as? String ?? "", reff_id: dataMessages[indexPath.row][TypeDataMessage.reff_id]  as? String ?? "", read_receipts: dataMessages[indexPath.row][TypeDataMessage.read_receipts]  as? String ?? "", chat_id: dataMessages[indexPath.row][TypeDataMessage.chat_id]  as? String ?? "", is_call_center: dataMessages[indexPath.row][TypeDataMessage.is_call_center]  as? String ?? "", call_center_id: dataMessages[indexPath.row][TypeDataMessage.call_center_id]  as? String ?? "", opposite_pin: dataMessages[indexPath.row][TypeDataMessage.opposite_pin]  as? String ?? "", server_date: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", local_time_stamp: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", last_edit: lastEdited)
+                        Nexilis.addQueueMessage(message: message, isEditMessage: true)
+                        DispatchQueue.global().async {
+                            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                do {
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                                        "message_text" : newText,
+                                        "last_edited" : lastEdited
+                                    ], _where: "message_id = '\(dataMessages[indexPath.row]["message_id"]  as? String ?? "")'")
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                                } catch {
+                                    rollback.pointee = true
+                                    print("Access database error: \(error.localizedDescription)")
+                                }
+                            })
+                        }
+                        let idx = self.dataMessages.firstIndex(where: { $0[TypeDataMessage.message_id] as? String == dataMessages[indexPath.row][TypeDataMessage.message_id] as? String})
+                        if idx != nil{
+                            self.dataMessages[idx!][TypeDataMessage.message_text] = newText
+                            self.dataMessages[idx!][TypeDataMessage.last_edit] = lastEdited
+                            self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                        }
                     }
                 }
                 self.isEditingMessage = false
@@ -6791,7 +6831,8 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             return cellMention
         }
         let idMe = User.getMyPin() as String?
-        let dataMessages = dataMessages.filter({$0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
+        let dateKey = dataDates[indexPath.section]
+        let dataMessages = messagesByDate[dateKey]!
         let profileMessage = UIImageView()
         let cell = tableView.dequeueReusableCell(withIdentifier: "cellEditorPersonal", for: indexPath as IndexPath)
         cell.contentView.subviews.forEach({ $0.removeConstraints($0.constraints) })
@@ -7412,21 +7453,6 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             }
         }
         
-//        if dataMessages[indexPath.row][TypeDataMessage.last_edit] != nil && dataMessages[indexPath.row][TypeDataMessage.last_edit] as! Int64 != 0 {
-//            let editedText = UILabel()
-//            editedText.text = "Edited".localized()
-//            editedText.font = UIFont.systemFont(ofSize: 10 + offset(), weight: .medium)
-//            editedText.textColor = .lightGray
-//            cell.contentView.addSubview(editedText)
-//            editedText.translatesAutoresizingMaskIntoConstraints = false
-//            if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
-//                editedText.trailingAnchor.constraint(equalTo: timeMessage.leadingAnchor, constant: -2).isActive = true
-//            } else {
-//                editedText.leadingAnchor.constraint(equalTo: timeMessage.trailingAnchor, constant: 2).isActive = true
-//            }
-//            editedText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor).isActive = true
-//        }
-        
         let messageText = UITextView()
         messageText.isEditable = false
         messageText.isSelectable = true
@@ -9068,14 +9094,16 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
         if tableView == tableViewConfigFile {
             return 2
         }
-        let count = dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[section] }).count
-        return count
+        let dateKey = dataDates[section]
+        return messagesByDate[dateKey]?.count ?? 0
     }
     
     @objc func contentMessageTapped(_ sender: ObjectGesture) {
         let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
         let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
         let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+        let indexPath = sender.indexPath
+        let dataMessages = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
         func showMedia(data: Data? = nil, url: URL? = nil, type: Int = 0) {
             let image = UIImage(data: data ?? Data())
             let imageViewer = MediaViewerViewController()
@@ -9098,7 +9126,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             }
             let backButton = UIBarButtonItem(title: nil, image: UIImage(systemName: "chevron.backward"), primaryAction: backAction, menu: nil)
             imageViewer.navigationItem.leftBarButtonItem = backButton
-            if Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share") {
+            if (Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share")) && dataMessages[indexPath.row]["credential"] as? String != "1" {
                 let shareAction = UIAction { _ in
                     var activityViewController = UIActivityViewController(activityItems: [""], applicationActivities: nil)
                     if type == 1 {
@@ -9313,7 +9341,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                 }
                 let backButton = UIBarButtonItem(title: nil, image: UIImage(systemName: "chevron.backward"), primaryAction: backAction, menu: nil)
                 vcHandleFile.navigationItem.leftBarButtonItem = backButton
-                if Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share") {
+                if (Nexilis.checkingAccess(key: "secure_folder_share") || sender.specFile.contains("download") || sender.specFile.contains("share")) && dataMessages[indexPath.row]["credential"] as? String != "1" {
                     let shareAction = UIAction { _ in
                         let fileManager = FileManager.default
                         let tempURL = fileManager.temporaryDirectory.appendingPathComponent(urlFile.lastPathComponent)

+ 105 - 16
NexilisLite/NexilisLite/Source/View/Chat/EditorStarMessages.swift

@@ -13,6 +13,7 @@ import Photos
 import SwiftLinkPreview
 import nuSDKService
 import NotificationBannerSwift
+import SDWebImage
 
 public class EditorStarMessages: UIViewController, UITableViewDataSource, UITableViewDelegate, UIContextMenuInteractionDelegate, QLPreviewControllerDataSource, UITextViewDelegate {
     @IBOutlet var tableChatView: UITableView!
@@ -512,15 +513,16 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         timeMessage.font = UIFont.systemFont(ofSize: 10 + offset(), weight: .medium)
         timeMessage.textColor = .lightGray
         
-        let thumbChat = dataMessages[indexPath.row]["thumb_id"] as! String
-        let imageChat = dataMessages[indexPath.row]["image_id"] as! String
-        let videoChat = dataMessages[indexPath.row]["video_id"] as! String
-        let fileChat = dataMessages[indexPath.row]["file_id"] as! String
+        let thumbChat = (dataMessages[indexPath.row]["thumb_id"] as? String) ?? ""
+        let imageChat = (dataMessages[indexPath.row]["image_id"] as? String) ?? ""
+        let videoChat = (dataMessages[indexPath.row]["video_id"] as? String) ?? ""
+        let fileChat = (dataMessages[indexPath.row]["file_id"] as? String) ?? ""
+        let gifChat = (dataMessages[indexPath.row]["gif_id"] as? String) ?? ""
         
         let imageThumb = UIImageView()
         let containerViewFile = UIView()
         
-        if (!thumbChat.isEmpty) {
+        if (!thumbChat.isEmpty && dataMessages[indexPath.row]["lock"]  as? String ?? "" != "1" && dataMessages[indexPath.row]["lock"] as? String != "2") {
             topMarginText.constant = topMarginText.constant + 205
             
             containerMessage.addSubview(imageThumb)
@@ -539,28 +541,74 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
             let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
             if let dirPath = paths.first {
                 let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(thumbChat)
-                let image    = UIImage(contentsOfFile: thumbURL.path)
-                imageThumb.image = image
+                if FileManager.default.fileExists(atPath: thumbURL.path) {
+                    DispatchQueue.main.async {
+                        let image : UIImage? =  {
+                            if let img = Nexilis.imageCache.object(forKey: thumbChat as NSString) {
+                                return img
+                            }
+                            else if let img = UIImage(contentsOfFile: thumbURL.path)?.resize(target: CGSize(width: 500, height: 500)) {
+                                    Nexilis.imageCache.setObject(img, forKey: thumbChat as NSString)
+                                    return img
+                            }
+                            return nil
+                        }()
+                        imageThumb.image = image
+                    }
+                } else if FileEncryption.shared.isSecureExists(filename: thumbChat) {
+                    do {
+                        if var data = try FileEncryption.shared.readSecure(filename: thumbChat) {
+                            let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
+                            if dataDecrypt != nil {
+                                data = dataDecrypt!
+                            }
+                            DispatchQueue.main.async {
+                                let image : UIImage? =  {
+                                    if let img = Nexilis.imageCache.object(forKey: thumbChat as NSString) {
+                                        return img
+                                    }
+                                    else if let img = UIImage(data: data)?.resize(target: CGSize(width: 500, height: 500)) {
+                                        Nexilis.imageCache.setObject(img, forKey: thumbChat as NSString)
+                                        return img
+                                    }
+                                    return nil
+                                }()
+                                imageThumb.image = image
+                            }
+                        }
+                    } catch {
+                        
+                    }
+                } else {
+                    Download().startHTTP(forKey: thumbChat) { (name, progress) in
+                        guard progress == 100 else {
+                            return
+                        }
+                        tableView.reloadRows(at: [indexPath], with: .none)
+                    }
+                }
                 
-                let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(videoChat)
                 let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(imageChat)
-                if !FileManager.default.fileExists(atPath: imageURL.path) && !FileManager.default.fileExists(atPath: videoURL.path) && !FileEncryption.shared.isSecureExists(filename: imageURL.lastPathComponent) && !FileEncryption.shared.isSecureExists(filename: videoURL.lastPathComponent){
+                if !FileManager.default.fileExists(atPath: imageURL.path) && !FileEncryption.shared.isSecureExists(filename: imageURL.lastPathComponent) {
                     let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.light)
                     let blurEffectView = UIVisualEffectView(effect: blurEffect)
                     blurEffectView.frame = CGRect(x: 0, y: 0, width: imageThumb.frame.size.width, height: imageThumb.frame.size.height)
                     blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-                    let imageDownload = UIImageView(image: UIImage(systemName: "arrow.down.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50, weight: .bold, scale: .default)))
                     imageThumb.addSubview(blurEffectView)
-                    imageThumb.addSubview(imageDownload)
-                    imageDownload.tintColor = .black.withAlphaComponent(0.3)
-                    imageDownload.translatesAutoresizingMaskIntoConstraints = false
-                    imageDownload.centerXAnchor.constraint(equalTo: imageThumb.centerXAnchor).isActive = true
-                    imageDownload.centerYAnchor.constraint(equalTo: imageThumb.centerYAnchor).isActive = true
+                    if !imageChat.isEmpty {
+                        let imageDownload = UIImageView(image: UIImage(systemName: "arrow.down.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50, weight: .bold, scale: .default)))
+                        imageThumb.addSubview(blurEffectView)
+                        imageThumb.addSubview(imageDownload)
+                        imageDownload.tintColor = .black.withAlphaComponent(0.3)
+                        imageDownload.translatesAutoresizingMaskIntoConstraints = false
+                        imageDownload.centerXAnchor.constraint(equalTo: imageThumb.centerXAnchor).isActive = true
+                        imageDownload.centerYAnchor.constraint(equalTo: imageThumb.centerYAnchor).isActive = true
+                    }
                 }
                 
             }
             
-            if (videoChat != "") {
+            if (videoChat != "" && gifChat.isEmpty) {
                 let imagePlay = UIImageView(image: UIImage(systemName: "play.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .bold, scale: .default))?.imageWithInsets(insets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))?.withTintColor(.white))
                 imagePlay.circle()
                 imageThumb.addSubview(imagePlay)
@@ -568,6 +616,47 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                 imagePlay.translatesAutoresizingMaskIntoConstraints = false
                 imagePlay.centerXAnchor.constraint(equalTo: imageThumb.centerXAnchor).isActive = true
                 imagePlay.centerYAnchor.constraint(equalTo: imageThumb.centerYAnchor).isActive = true
+            } else if !gifChat.isEmpty {
+                let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
+                let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
+                let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+                if let dirPath = paths.first {
+                    let gifURL = URL(fileURLWithPath: dirPath).appendingPathComponent(gifChat)
+                    if !FileManager.default.fileExists(atPath: gifURL.path) && !FileEncryption.shared.isSecureExists(filename: gifChat) {
+                        Download().startHTTP(forKey: gifChat) { (name, progress) in
+                            guard progress == 100 else {
+                                return
+                            }
+                            tableView.reloadRows(at: [indexPath], with: .none)
+                        }
+                    } else {
+                        imageThumb.addSubview(imageGif)
+                        imageGif.translatesAutoresizingMaskIntoConstraints = false
+                        imageGif.anchor(top: imageThumb.topAnchor, left: imageThumb.leftAnchor, bottom: imageThumb.bottomAnchor, right: imageThumb.rightAnchor)
+                        if FileManager.default.fileExists(atPath: gifURL.path) {
+                            imageGif.image = SDAnimatedImage(contentsOfFile: gifURL.path)
+//                                imageGif.shouldCustomLoopCount = true
+//                                imageGif.animationRepeatCount = 4
+                        } else if FileEncryption.shared.isSecureExists(filename: gifChat){
+                            do {
+                                if var data = try FileEncryption.shared.readSecure(filename: gifChat) {
+                                    let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
+                                    if dataDecrypt != nil {
+                                        data = dataDecrypt!
+                                    }
+                                    if let imageData = SDAnimatedImage(data: data) {
+                                        imageGif.image = imageData
+//                                        imageGif.shouldCustomLoopCount = true
+//                                        imageGif.animationRepeatCount = 4
+                                    }
+                                }
+                            }
+                            catch {
+                                print("Error reading secure file")
+                            }
+                        }
+                    }
+                }
             }
             
             if (dataMessages[indexPath.row]["progress"] as! Double != 100.0 && dataMessages[indexPath.row]["f_pin"] as? String == idMe) {

+ 2 - 60
NexilisLite/NexilisLite/Source/View/Control/ChangeDeviceViewController.swift

@@ -310,36 +310,7 @@ public class ChangeDeviceViewController: UIViewController {
             }
             KeyManagerNexilis.generateKey()
             KeyManagerNexilis.saveMarker()
-            let dataTxn = Utils.getTxnLevel()
-            var policyLevel = "1,2"
-            if !dataTxn.isEmpty {
-                if let data = dataTxn.data(using: .utf8) {
-                    do {
-                        // Parse to generic JSON array
-                        if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
-                            for json in jsonArray {
-                                let min = json["min"] as? Double ?? 0
-                                let max = json["max"] as? Double ?? 0
-                                let policy = json["policy"] as? String ?? ""
-                                let amount = 0.0
-                                if max == -1 {
-                                    if amount >= min {
-                                        policyLevel = policy
-                                        break
-                                    }
-                                } else {
-                                    if amount >= min && amount <= max {
-                                        policyLevel = policy
-                                        break
-                                    }
-                                }
-                            }
-                        }
-                    } catch {
-                        print("Error converting string to JSONArray:", error)
-                    }
-                }
-            }
+            let policyLevel = Utils.getSignInLevel()
             var isBiometricOn = false
             if policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
                 isBiometricOn = true
@@ -484,36 +455,7 @@ public class ChangeDeviceViewController: UIViewController {
         }
         KeyManagerNexilis.generateKey()
         KeyManagerNexilis.saveMarker()
-        let dataTxn = Utils.getTxnLevel()
-        var policyLevel = "1,2"
-        if !dataTxn.isEmpty {
-            if let data = dataTxn.data(using: .utf8) {
-                do {
-                    // Parse to generic JSON array
-                    if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
-                        for json in jsonArray {
-                            let min = json["min"] as? Double ?? 0
-                            let max = json["max"] as? Double ?? 0
-                            let policy = json["policy"] as? String ?? ""
-                            let amount = 0.0
-                            if max == -1 {
-                                if amount >= min {
-                                    policyLevel = policy
-                                    break
-                                }
-                            } else {
-                                if amount >= min && amount <= max {
-                                    policyLevel = policy
-                                    break
-                                }
-                            }
-                        }
-                    }
-                } catch {
-                    print("Error converting string to JSONArray:", error)
-                }
-            }
-        }
+        let policyLevel = Utils.getSignInLevel()
         var isBiometricOn = false
         if policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
             isBiometricOn = true

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

@@ -309,36 +309,7 @@ public class SignUpSignIn: UIViewController {
             }
             KeyManagerNexilis.generateKey()
             KeyManagerNexilis.saveMarker()
-            let dataTxn = Utils.getTxnLevel()
-            var policyLevel = "1,2"
-            if !dataTxn.isEmpty {
-                if let data = dataTxn.data(using: .utf8) {
-                    do {
-                        // Parse to generic JSON array
-                        if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
-                            for json in jsonArray {
-                                let min = json["min"] as? Double ?? 0
-                                let max = json["max"] as? Double ?? 0
-                                let policy = json["policy"] as? String ?? ""
-                                let amount = 0.0
-                                if max == -1 {
-                                    if amount >= min {
-                                        policyLevel = policy
-                                        break
-                                    }
-                                } else {
-                                    if amount >= min && amount <= max {
-                                        policyLevel = policy
-                                        break
-                                    }
-                                }
-                            }
-                        }
-                    } catch {
-                        print("Error converting string to JSONArray:", error)
-                    }
-                }
-            }
+            let policyLevel = Utils.getSignInLevel()
             var isBiometricOn = false
             if policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
                 isBiometricOn = true
@@ -503,36 +474,7 @@ public class SignUpSignIn: UIViewController {
         }
         KeyManagerNexilis.generateKey()
         KeyManagerNexilis.saveMarker()
-        let dataTxn = Utils.getTxnLevel()
-        var policyLevel = "1,2"
-        if !dataTxn.isEmpty {
-            if let data = dataTxn.data(using: .utf8) {
-                do {
-                    // Parse to generic JSON array
-                    if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
-                        for json in jsonArray {
-                            let min = json["min"] as? Double ?? 0
-                            let max = json["max"] as? Double ?? 0
-                            let policy = json["policy"] as? String ?? ""
-                            let amount = 0.0
-                            if max == -1 {
-                                if amount >= min {
-                                    policyLevel = policy
-                                    break
-                                }
-                            } else {
-                                if amount >= min && amount <= max {
-                                    policyLevel = policy
-                                    break
-                                }
-                            }
-                        }
-                    }
-                } catch {
-                    print("Error converting string to JSONArray:", error)
-                }
-            }
-        }
+        let policyLevel = Utils.getSignInLevel()
         var isBiometricOn = false
         if policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_PWD_BIOFACE || policyLevel == MFAViewController.STEP_FIDO_BIOFINGER || policyLevel == MFAViewController.STEP_FIDO_BIOFACE {
             isBiometricOn = true