Explorar o código

update fix bugs and release for 5.0.67

alqindiirsyam hai 6 días
pai
achega
1c04c49772

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

@@ -568,7 +568,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 5.0.66;
+				MARKETING_VERSION = 5.0.67;
 				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.66;
+				MARKETING_VERSION = 5.0.67;
 				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.66;
+				MARKETING_VERSION = 5.0.67;
 				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.66;
+				MARKETING_VERSION = 5.0.67;
 				OTHER_CFLAGS = "-fstack-protector-strong";
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 114 - 99
NexilisLite/NexilisLite/Source/APIS.swift

@@ -1724,6 +1724,18 @@ public class APIS: NSObject {
     static func ackAPN(id: String) {
         DispatchQueue.global().async {
 //            Nexilis.sendStateToServer(s: "send ack from apn")
+//            if API.nGetCLXConnState() == 0 {
+//                do {
+//                    let id = Utils.getConnectionID()
+//                    try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
+//                } catch {}
+//            }
+//            while API.nGetCLXConnState() == 0 {
+//                Thread.sleep(forTimeInterval: 0.5)
+//            }
+//            let _ = Nexilis.writeSync(message: CoreMessage_TMessageBank.getAckMessage(messageId: id), timeout: 30000)
+            
+            //HTTPS
             let parameter: [String : Any] = [
                 "pin": User.getMyPin() ?? "",
                 "message_id": id
@@ -1734,108 +1746,37 @@ public class APIS: NSObject {
     }
     
     private static func getMessageById(id: String, retry: Int = 0, completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
-        if API.nGetCLXConnState() == 0 {
-            do {
-                let id = Utils.getConnectionID()
-                try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
-            } catch {}
-        }
-        while API.nGetCLXConnState() == 0 {
-            Thread.sleep(forTimeInterval: 0.5)
-        }
-        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getMessageById(messageId: id), timeout: 30000) {
-            if response.isOk() {
-                let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
-                if let decodedData = Data(base64Encoded: data, options: .ignoreUnknownCharacters) {
-                    if let respData = String(data: decodedData, encoding: .utf8) {
-                        let message = TMessage(data: respData)
-                        if Utils.getSecureFolderOffline() == "0" && IncomingThread.dispatch == nil {
-                            if FileEncryption.shared.aesKey == nil {
-                                IncomingThread.dispatch = DispatchGroup()
-                                IncomingThread.dispatch?.enter()
-                                Nexilis.getFeatureAccess()
-                                IncomingThread.dispatch?.wait()
-                                IncomingThread.dispatch = nil
-                            }
-                        }
-//                                print("save from APIS")
-                        Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
-                        ackAPN(id: id)
-                        DispatchQueue.main.async {
-                            UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
-                        }
-                    }
-                }
-            } else {
-                let ret = retry + 1
-                if ret <= 5 {
-                    getMessageById(id: id, retry: ret, completionHandler: completionHandler)
-                } else {
-                    completionHandler(.failed)
-                }
-            }
-        } else {
-            let ret = retry + 1
-            if ret <= 5 {
-                getMessageById(id: id, retry: ret, completionHandler: completionHandler)
-            } else {
-                completionHandler(.failed)
-            }
-        }
-//        let parameter: [String : Any] = [
-//            "pin": User.getMyPin() ?? "",
-//            "message_id": id
-//        ]
-//        Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "pull_notification")!, parameter: parameter, isFormData: true) { data, response, error in
-//            if error != nil {
-//                let ret = retry + 1
-//                if ret <= 5 {
-//                    getMessageById(id: id, retry: ret, completionHandler: completionHandler)
-//                } else {
-//                    completionHandler(.failed)
-//                }
-//            } else if let data = data {
-//                do {
-//                    if let dataString = String(data: data, encoding: .utf8) {
-//                        if let jsonObj = try JSONSerialization.jsonObject(with: dataString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [String: Any] {
-//                            let dataObj = jsonObj["data"] as? String ?? ""
-//                            let message = TMessage(data: dataObj)
-//                            if Utils.getSecureFolderOffline() == "0" && IncomingThread.dispatch == nil {
-//                                if API.nGetCLXConnState() == 0 {
-//                                    do {
-//                                        let id = Utils.getConnectionID()
-//                                        try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
-//                                    } catch {}
-//                                }
-//                                if FileEncryption.shared.aesKey == nil {
-//                                    IncomingThread.dispatch = DispatchGroup()
-//                                    IncomingThread.dispatch?.enter()
-//                                    Nexilis.getFeatureAccess()
-//                                    IncomingThread.dispatch?.wait()
-//                                    IncomingThread.dispatch = nil
-//                                }
+//        if API.nGetCLXConnState() == 0 {
+//            do {
+//                let id = Utils.getConnectionID()
+//                try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
+//            } catch {}
+//        }
+//        while API.nGetCLXConnState() == 0 {
+//            Thread.sleep(forTimeInterval: 0.5)
+//        }
+//        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getMessageById(messageId: id), timeout: 30000) {
+//            if response.isOk() {
+//                let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
+//                if let decodedData = Data(base64Encoded: data, options: .ignoreUnknownCharacters) {
+//                    if let respData = String(data: decodedData, encoding: .utf8) {
+//                        let message = TMessage(data: respData)
+//                        if Utils.getSecureFolderOffline() == "0" && IncomingThread.dispatch == nil {
+//                            if FileEncryption.shared.aesKey == nil {
+//                                IncomingThread.dispatch = DispatchGroup()
+//                                IncomingThread.dispatch?.enter()
+//                                Nexilis.getFeatureAccess()
+//                                IncomingThread.dispatch?.wait()
+//                                IncomingThread.dispatch = nil
 //                            }
+//                        }
 ////                                print("save from APIS")
-//                            Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
-//                            ackAPN(id: id)
-//                            DispatchQueue.main.async {
-//                                UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
-//                            }
-//                        } else {
-//                            let ret = retry + 1
-//                            if ret <= 5 {
-//                                getMessageById(id: id, retry: ret, completionHandler: completionHandler)
-//                            } else {
-//                                completionHandler(.failed)
-//                            }
+//                        Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
+//                        ackAPN(id: id)
+//                        DispatchQueue.main.async {
+//                            UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
 //                        }
-//                    }
-//                } catch {
-//                    let ret = retry + 1
-//                    if ret <= 5 {
-//                        getMessageById(id: id, retry: ret, completionHandler: completionHandler)
-//                    } else {
-//                        completionHandler(.failed)
+//                        completionHandler(.newData)
 //                    }
 //                }
 //            } else {
@@ -1846,7 +1787,81 @@ public class APIS: NSObject {
 //                    completionHandler(.failed)
 //                }
 //            }
+//        } else {
+//            let ret = retry + 1
+//            if ret <= 5 {
+//                getMessageById(id: id, retry: ret, completionHandler: completionHandler)
+//            } else {
+//                completionHandler(.failed)
+//            }
 //        }
+        //HTTPS
+        let parameter: [String : Any] = [
+            "pin": User.getMyPin() ?? "",
+            "message_id": id
+        ]
+        Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "pull_notification")!, parameter: parameter, isFormData: true) { data, response, error in
+            if error != nil {
+                let ret = retry + 1
+                if ret <= 5 {
+                    getMessageById(id: id, retry: ret, completionHandler: completionHandler)
+                } else {
+                    completionHandler(.failed)
+                }
+            } else if let data = data {
+                do {
+                    if let dataString = String(data: data, encoding: .utf8) {
+                        if let jsonObj = try JSONSerialization.jsonObject(with: dataString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [String: Any] {
+                            let dataObj = jsonObj["data"] as? String ?? ""
+                            let message = TMessage(data: dataObj)
+                            if Utils.getSecureFolderOffline() == "0" && IncomingThread.dispatch == nil {
+                                if API.nGetCLXConnState() == 0 {
+                                    do {
+                                        let id = Utils.getConnectionID()
+                                        try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
+                                    } catch {}
+                                }
+                                if FileEncryption.shared.aesKey == nil {
+                                    IncomingThread.dispatch = DispatchGroup()
+                                    IncomingThread.dispatch?.enter()
+                                    Nexilis.getFeatureAccess()
+                                    IncomingThread.dispatch?.wait()
+                                    IncomingThread.dispatch = nil
+                                }
+                            }
+//                                print("save from APIS")
+                            Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
+                            ackAPN(id: id)
+                            DispatchQueue.main.async {
+                                UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
+                            }
+                            completionHandler(.newData)
+                        } else {
+                            let ret = retry + 1
+                            if ret <= 5 {
+                                getMessageById(id: id, retry: ret, completionHandler: completionHandler)
+                            } else {
+                                completionHandler(.failed)
+                            }
+                        }
+                    }
+                } catch {
+                    let ret = retry + 1
+                    if ret <= 5 {
+                        getMessageById(id: id, retry: ret, completionHandler: completionHandler)
+                    } else {
+                        completionHandler(.failed)
+                    }
+                }
+            } else {
+                let ret = retry + 1
+                if ret <= 5 {
+                    getMessageById(id: id, retry: ret, completionHandler: completionHandler)
+                } else {
+                    completionHandler(.failed)
+                }
+            }
+        }
     }
     
     public static func addNotificationNexilis(_ message: TMessage) {

+ 56 - 10
NexilisLite/NexilisLite/Source/Model/Chat.swift

@@ -204,15 +204,59 @@ public class Chat: Model {
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             do {
                 let query = """
-                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, m.thumb_id from MESSAGE m, BUDDY b where (m.l_pin = b.f_pin OR m.f_pin = b.f_pin) and m.attachment_flag = '3' and m.message_id = '\(message_id)' and m.is_call_center = 0
+                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date,
+                                   m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id,
+                                   b.first_name || ' ' || ifnull(b.last_name, '') as name,
+                                   b.image_id as profile, b.official_account,
+                                   m.status, m.credential, m.lock, m.thumb_id, m.audio_id, m.gif_id,
+                                   '' as group_id, '' as group_name, m.is_bot
+                            from MESSAGE m
+                            join BUDDY b on m.l_pin = b.f_pin
+                            where m.is_call_center = 0
+                              and m.message_id = '\(message_id)'
                             union
-                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'Bot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, m.thumb_id from MESSAGE m where m.f_pin = '-999' and m.message_id = '\(message_id)' and m.is_call_center = 0
+                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date,
+                                   m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id,
+                                   'Bot' as name, '' as profile, '' as official_account,
+                                   m.status, m.credential, m.lock, m.thumb_id, m.audio_id, m.gif_id,
+                                   '' as group_id, '' as group_name, m.is_bot
+                            from MESSAGE m
+                            where m.l_pin = '-999'
+                              and m.is_call_center = 0
+                              and m.message_id = '\(message_id)'
                             union
-                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'GPT SmartBot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, m.thumb_id from MESSAGE m where m.f_pin = '-997' and m.message_id = '\(message_id)' and m.is_call_center = 0
+                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date,
+                                   m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id,
+                                   'GPT SmartBot' as name, '' as profile, '' as official_account,
+                                   m.status, m.credential, m.lock, m.thumb_id, m.audio_id, m.gif_id,
+                                   '' as group_id, '' as group_name, m.is_bot
+                            from MESSAGE m
+                            where m.l_pin = '-997'
+                              and m.is_call_center = 0
+                              and m.message_id = '\(message_id)'
                             union
-                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, '\("Lounge".localized())' name, b.image_id profile, b.official, m.status, m.credential, m.lock, m.audio_id, m.gif_id, b.group_id, b.f_name group_name, m.thumb_id from MESSAGE m, GROUPZ b where m.l_pin = b.group_id and m.message_id = '\(message_id)' and m.is_call_center = 0
+                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date,
+                                   m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id,
+                                   '\("Lounge".localized())' as name,
+                                   g.image_id as profile, g.official,
+                                   m.status, m.credential, m.lock, m.thumb_id, m.audio_id, m.gif_id,
+                                   g.group_id, g.f_name as group_name, m.is_bot
+                            from MESSAGE m
+                            join GROUPZ g on m.l_pin = g.group_id
+                            where m.is_call_center = 0
+                              and m.message_id = '\(message_id)'
                             union
-                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.title, c.image_id profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, c.group_id, c.f_name group_name, m.thumb_id from MESSAGE m, DISCUSSION_FORUM b, GROUPZ c where b.group_id = c.group_id and m.l_pin = b.chat_id and m.message_id = '\(message_id)' and m.is_call_center = 0
+                            select m.f_pin, m.l_pin, m.message_id, m.message_text, m.server_date,
+                                   m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id,
+                                   d.title, g.image_id as profile, '' as official_account,
+                                   m.status, m.credential, m.lock, m.thumb_id, m.audio_id, m.gif_id,
+                                   g.group_id, g.f_name as group_name, m.is_bot
+                            from MESSAGE m
+                            join DISCUSSION_FORUM d on m.l_pin = d.chat_id
+                            join GROUPZ g on d.group_id = g.group_id
+                            where m.is_call_center = 0
+                              and m.message_id = '\(message_id)'
+
                             order by 6 desc
                             """
                 if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
@@ -234,11 +278,13 @@ public class Chat: Model {
                                         status: cursorData.string(forColumnIndex: 13) ?? "",
                                         credential: cursorData.string(forColumnIndex: 14) ?? "",
                                         lock: cursorData.string(forColumnIndex: 15) ?? "",
-                                        thumb: cursorData.string(forColumnIndex: 20) ?? "",
-                                        audio: cursorData.string(forColumnIndex: 16) ?? "",
-                                        gif: cursorData.string(forColumnIndex: 17) ?? "",
-                                        groupId: cursorData.string(forColumnIndex: 18) ?? "",
-                                        groupName: cursorData.string(forColumnIndex: 19) ?? "")
+                                        thumb: cursorData.string(forColumnIndex: 16) ?? "",
+                                        audio: cursorData.string(forColumnIndex: 17) ?? "",
+                                        gif: cursorData.string(forColumnIndex: 18) ?? "",
+                                        groupId: cursorData.string(forColumnIndex: 19) ?? "",
+                                        groupName: cursorData.string(forColumnIndex: 20) ?? "",
+                                        pinned: 0,
+                                        isBot: Int(cursorData.string(forColumnIndex: 21) ?? "0") ?? 0)
                         messages.append(chat)
                     }
                     cursorData.close()

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

@@ -19,7 +19,7 @@ import CryptoKit
 import WebKit
 
 public class Nexilis: NSObject {
-    public static var cpaasVersion = "5.0.66"
+    public static var cpaasVersion = "5.0.67"
     public static var sAPIKey = ""
     
     public static var ADDRESS = ""
@@ -1207,6 +1207,7 @@ public class Nexilis: NSObject {
         } catch {
             //print(error)
         }
+        isProcessWriteSync = false
         return nil
     }
     

+ 19 - 14
NexilisLite/NexilisLite/Source/OutgoingThread.swift

@@ -294,21 +294,26 @@ class OutgoingThread {
             }
         } else {
             if let response = Nexilis.writeSync(message: message) {
-                //print("sendChat", response.toLogString())
-                let messageId = response.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
-                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                    do {
-                        _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
-                            "status" : response.getBody(key: CoreMessage_TMessageKey.STATUS, default_value: "2")
-                        ], _where: "message_id = '\(messageId)'")
-                        self.delOutgoing(fmdb: fmdb, messageId: message.getStatus())
-                    } catch {
-                        rollback.pointee = true
-                        print("Access database error: \(error.localizedDescription)")
-                    }
-                })
+//                print("sendChatRESP", response.toLogString())
+                if !response.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID).isEmpty {
+                    let messageId = response.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                        do {
+                            _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                                "status" : response.getBody(key: CoreMessage_TMessageKey.STATUS, default_value: "2")
+                            ], _where: "message_id = '\(messageId)'")
+                            self.delOutgoing(fmdb: fmdb, messageId: message.getStatus())
+                        } catch {
+                            rollback.pointee = true
+                            print("Access database error: \(error.localizedDescription)")
+                        }
+                    })
+                } else {
+//                    print("retry sendChat")
+                    OutgoingThread.default.addQueue(message: message)
+                }
             } else {
-//                InquiryThread.default.addQueue(message: message)
+//                print("retry sendChat")
                 OutgoingThread.default.addQueue(message: message)
             }
         }

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

@@ -1645,6 +1645,30 @@ public final class Utils {
             completion(false, "Biometric authentication is not available")
         }
     }
+    
+    public static func authenticateWithBioOrPass(completion: @escaping (Bool, String?) -> Void) {
+        let context = LAContext()
+        var error: NSError?
+
+        if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
+            let reason = "Authenticate to continue"
+
+            context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, authenticationError in
+                DispatchQueue.main.async {
+                    if success {
+                        completion(true, nil)
+                    } else {
+                        let message = authenticationError?.localizedDescription ?? "Authentication failed"
+                        completion(false, message)
+                    }
+                }
+            }
+        } else {
+            // Device doesn’t support biometrics or passcode is not set
+            let message = error?.localizedDescription ?? "Authentication not available"
+            completion(false, message)
+        }
+    }
 }
 public extension UIImage {
     var jpeg: Data? { jpegData(compressionQuality: 1) }  // QUALITY min = 0 / max = 1

+ 66 - 2
NexilisLite/NexilisLite/Source/View/Chat/ChatGPTBotView.swift

@@ -275,6 +275,67 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
     }
     
     @objc func sendTapped() {
+        if self.chatGPTMessages.last?["confirmation"] as? String == "1" {
+            DispatchQueue.global().async {
+                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)
+                        }
+                    }
+                }
+                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 {
+                    isBiometricOn = true
+                }
+                if isBiometricOn {
+                    let semaphore = DispatchSemaphore(value: 0)
+
+                    Utils.authenticateWithBioOrPass { success, errorMessage in
+                        if success {
+                            result = true
+                        }
+                        semaphore.signal()
+                    }
+
+                    semaphore.wait()
+                } else {
+                    result = true
+                }
+
+                DispatchQueue.main.async { [self] in
+                    if !result {
+                        return
+                    }
+                    sendChat(message_text: textFieldSend.text!, viewController: self)
+                }
+            }
+            return
+        }
         sendChat(message_text: textFieldSend.text!, viewController: self)
     }
     
@@ -377,7 +438,11 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
             textFieldSend.text = "Send message".localized()
             textFieldSend.textColor = UIColor.lightGray
         } else if constraintViewTextField.constant != 0 {
-            textFieldSend.text = ""
+            if textFieldSend.text.lowercased().contains("@bsb") {
+                textFieldSend.text = "@bsb "
+            } else {
+                textFieldSend.text = ""
+            }
             heightTextFieldSend.constant = 40
         }
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
@@ -398,7 +463,6 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                                 self.dataMessages.removeAll(where: { $0["is_loading"] as? Bool == true })
                                 self.tableChatView.reloadData()
                                 self.chatGPTMessages.append(json)
-                                print("HOHO: \(json)")
                                 guard let me = User.getMyPin() else {
                                     return
                                 }

+ 0 - 1
NexilisLite/NexilisLite/Source/View/Chat/ChatWALikeVC.swift

@@ -191,7 +191,6 @@ public class ChatWALikeVC: UIViewController, UITableViewDataSource, UITableViewD
         searchController.searchBar.delegate = self
 
         navigationItem.searchController = searchController
-        navigationItem.hidesSearchBarWhenScrolling = false
         definesPresentationContext = true
         DispatchQueue.main.async {
             self.navigationController?.navigationBar.sizeToFit()

+ 21 - 3
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -7714,7 +7714,13 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
                 
                 self.containerPin.addSubview(textPin)
                 self.textPin.anchor(left: contIconPin.rightAnchor, right: self.containerPin.rightAnchor, paddingLeft: 10, paddingRight: 10, centerY: self.containerPin.centerYAnchor)
-                self.textPin.attributedText = (dataMessages[dataMessages.count - 1][TypeDataMessage.message_text] as? String ?? "").richText(fontSize: 14, group_id: self.dataGroup["group_id"]  as? String ?? "")
+                let chat = Chat.getMessageFromId(message_id: dataMessages[dataMessages.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                if chat.count > 0 {
+                    let text = Utils.previewMessageText(chat: chat[0])
+                    if let attributeText = text as? NSMutableAttributedString {
+                        self.textPin.attributedText = attributeText
+                    }
+                }
                 self.textPin.numberOfLines = 1
                 self.textPin.textColor = .white
             } else {
@@ -7758,7 +7764,13 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
                     same = true
                 }
                 if !same{
-                    animateLabelTextChange(label: self.textPin, newText: dataMessages[dataMessages.count - 1][TypeDataMessage.message_text] as? String ?? "")
+                    let chat = Chat.getMessageFromId(message_id: dataMessages[dataMessages.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                    if chat.count > 0 {
+                        let text = Utils.previewMessageText(chat: chat[0])
+                        if let attributeText = text as? NSMutableAttributedString {
+                            animateLabelTextChange(label: self.textPin, newText: attributeText.string)
+                        }
+                    }
                 }
             }
         } else if self.containerPin.isDescendant(of: self.view) {
@@ -7809,7 +7821,13 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
                     viewSign.clipsToBounds = true
                     self.signSelectedPin.addArrangedSubview(viewSign)
                 }
-                self.animateLabelTextChange(label: self.textPin, newText: dataMessagesPin[self.nextPinShowed][TypeDataMessage.message_text] as? String ?? "")
+                let chat = Chat.getMessageFromId(message_id: dataMessagesPin[dataMessagesPin.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                if chat.count > 0 {
+                    let text = Utils.previewMessageText(chat: chat[0])
+                    if let attributeText = text as? NSMutableAttributedString {
+                        self.animateLabelTextChange(label: self.textPin, newText: attributeText.string)
+                    }
+                }
             }
         }
     }

+ 21 - 3
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -9585,7 +9585,13 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                 
                 self.containerPin.addSubview(textPin)
                 self.textPin.anchor(left: contIconPin.rightAnchor, right: self.containerPin.rightAnchor, paddingLeft: 10, paddingRight: 10, centerY: self.containerPin.centerYAnchor)
-                self.textPin.attributedText = (dataMessages[dataMessages.count - 1][TypeDataMessage.message_text] as? String ?? "").richText(fontSize: 14)
+                let chat = Chat.getMessageFromId(message_id: dataMessages[dataMessages.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                if chat.count > 0 {
+                    let text = Utils.previewMessageText(chat: chat[0])
+                    if let attributeText = text as? NSMutableAttributedString {
+                        self.textPin.attributedText = attributeText
+                    }
+                }
                 self.textPin.numberOfLines = 1
                 self.textPin.textColor = .white
             } else {
@@ -9629,7 +9635,13 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                     same = true
                 }
                 if !same{
-                    animateLabelTextChange(label: self.textPin, newText: dataMessages[dataMessages.count - 1][TypeDataMessage.message_text] as? String ?? "")
+                    let chat = Chat.getMessageFromId(message_id: dataMessages[dataMessages.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                    if chat.count > 0 {
+                        let text = Utils.previewMessageText(chat: chat[0])
+                        if let attributeText = text as? NSMutableAttributedString {
+                            animateLabelTextChange(label: self.textPin, newText: attributeText.string)
+                        }
+                    }
                 }
             }
         } else if self.containerPin.isDescendant(of: self.view) {
@@ -9680,7 +9692,13 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                     viewSign.clipsToBounds = true
                     self.signSelectedPin.addArrangedSubview(viewSign)
                 }
-                self.animateLabelTextChange(label: self.textPin, newText: dataMessagesPin[self.nextPinShowed][TypeDataMessage.message_text] as? String ?? "")
+                let chat = Chat.getMessageFromId(message_id: dataMessagesPin[dataMessagesPin.count - 1][TypeDataMessage.message_id] as? String ?? "")
+                if chat.count > 0 {
+                    let text = Utils.previewMessageText(chat: chat[0])
+                    if let attributeText = text as? NSMutableAttributedString {
+                        self.animateLabelTextChange(label: self.textPin, newText: attributeText.string)
+                    }
+                }
             }
         }
     }