alqindiirsyam 6 сар өмнө
parent
commit
f156b83c41

BIN
.DS_Store


BIN
AppBuilder/.DS_Store


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

@@ -533,7 +533,7 @@
 				CODE_SIGN_ENTITLEMENTS = AppBuilder/AppBuilder.entitlements;
 				CODE_SIGN_ENTITLEMENTS = AppBuilder/AppBuilder.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				FRAMEWORK_SEARCH_PATHS = (
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
@@ -546,7 +546,7 @@
 					"$(inherited)",
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/Frameworks",
 				);
 				);
-				MARKETING_VERSION = 5.0.5;
+				MARKETING_VERSION = 5.0.6;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -569,7 +569,7 @@
 				CODE_SIGN_ENTITLEMENTS = AppBuilder/AppBuilder.entitlements;
 				CODE_SIGN_ENTITLEMENTS = AppBuilder/AppBuilder.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				FRAMEWORK_SEARCH_PATHS = (
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
@@ -582,7 +582,7 @@
 					"$(inherited)",
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/Frameworks",
 				);
 				);
-				MARKETING_VERSION = 5.0.5;
+				MARKETING_VERSION = 5.0.6;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -603,7 +603,7 @@
 				CODE_SIGN_ENTITLEMENTS = AppBuilderShare/AppBuilderShare.entitlements;
 				CODE_SIGN_ENTITLEMENTS = AppBuilderShare/AppBuilderShare.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu17;
 				GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -618,7 +618,7 @@
 					"@executable_path/../../Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.5;
+				MARKETING_VERSION = 5.0.6;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SKIP_INSTALL = YES;
@@ -641,7 +641,7 @@
 				CODE_SIGN_ENTITLEMENTS = AppBuilderShare/AppBuilderShare.entitlements;
 				CODE_SIGN_ENTITLEMENTS = AppBuilderShare/AppBuilderShare.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				DEVELOPMENT_TEAM = 6RLKHZJ57M;
 				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu17;
 				GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -656,7 +656,7 @@
 					"@executable_path/../../Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.5;
+				MARKETING_VERSION = 5.0.6;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SKIP_INSTALL = YES;

+ 3 - 6
AppBuilder/AppBuilder/AppDelegate.swift

@@ -29,12 +29,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         // Use this method to select a configuration to create the new scene with.
         // Use this method to select a configuration to create the new scene with.
         return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
         return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
     }
     }
-
-    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
-        Nexilis.destroyAll()
-        // Called when the user discards a scene session.
-        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
-        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
+    
+    func applicationWillTerminate(_ application: UIApplication) {
+        APIS.willTerminate()
     }
     }
     
     
     private func registerForPushNotifications() {
     private func registerForPushNotifications() {

BIN
NexilisLite/.DS_Store


BIN
NexilisLite/NexilisLite/.DS_Store


BIN
NexilisLite/NexilisLite/Resource/.DS_Store


BIN
NexilisLite/NexilisLite/Resource/Gifs/pb_typing_chat.gif


+ 7 - 6
NexilisLite/NexilisLite/Source/APIS.swift

@@ -1238,17 +1238,12 @@ public class APIS: NSObject {
     }
     }
     
     
     public static func enterBackground() {
     public static func enterBackground() {
-//        do {
-//            try API.switchCBI(cbiI: Callback(), bLight: true)
-//        } catch {
-//        }
-//        exit(0)
         UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
         UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
     }
     }
     
     
     public static func enterForeground() {
     public static func enterForeground() {
         do {
         do {
-            if !Nexilis.sAPIKey.isEmpty {
+            if !Nexilis.afterConnect {
                 var id = Utils.getConnectionID()
                 var id = Utils.getConnectionID()
                 if id.isEmpty {
                 if id.isEmpty {
                     let sDID = UIDevice.current.identifierForVendor?.uuidString ?? "UNK-DEVICE"
                     let sDID = UIDevice.current.identifierForVendor?.uuidString ?? "UNK-DEVICE"
@@ -1256,7 +1251,9 @@ public class APIS: NSObject {
                     Utils.setConnectionID(value: id)
                     Utils.setConnectionID(value: id)
                 }
                 }
                 try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
                 try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
+                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
             }
             }
+            Nexilis.afterConnect = false
         } catch {
         } catch {
         }
         }
         checkDataForShareExtension()
         checkDataForShareExtension()
@@ -1264,6 +1261,10 @@ public class APIS: NSObject {
         UNUserNotificationCenter.current().removeAllDeliveredNotifications()
         UNUserNotificationCenter.current().removeAllDeliveredNotifications()
     }
     }
     
     
+    public static func willTerminate() {
+        Nexilis.destroyAll()
+    }
+    
     private static func checkDataForShareExtension() {
     private static func checkDataForShareExtension() {
         DispatchQueue.global().async {
         DispatchQueue.global().async {
             if let userDefaults = UserDefaults(suiteName: "group.nexilis.share") {
             if let userDefaults = UserDefaults(suiteName: "group.nexilis.share") {

+ 11 - 9
NexilisLite/NexilisLite/Source/IncomingThread.swift

@@ -1299,17 +1299,19 @@ class IncomingThread {
         } else {
         } else {
             Nexilis.saveMessage(message: message, withStatus: false)
             Nexilis.saveMessage(message: message, withStatus: false)
         }
         }
-        UNUserNotificationCenter.current().getPendingNotificationRequests{ notificationsPending in
-            let identifier = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
-            let matchingNotifications = notificationsPending.filter { $0.identifier == identifier }
-            if matchingNotifications.isEmpty {
-                UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
+        DispatchQueue.main.async {
+            if APIS.checkAppStateisBackground() {
+                UNUserNotificationCenter.current().getPendingNotificationRequests{ notificationsPending in
                     let identifier = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
                     let identifier = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
-                    let matchingNotifications = notifications.filter { $0.request.identifier == identifier }
+                    let matchingNotifications = notificationsPending.filter { $0.identifier == identifier }
                     if matchingNotifications.isEmpty {
                     if matchingNotifications.isEmpty {
-                        DispatchQueue.main.async {
-                            if APIS.checkAppStateisBackground() {
-                                APIS.addNotificationNexilis(message)
+                        UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
+                            let identifier = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
+                            let matchingNotifications = notifications.filter { $0.request.identifier == identifier }
+                            if matchingNotifications.isEmpty && message.getBody(key : CoreMessage_TMessageKey.LAST_EDIT, default_value : "0") == "0" {
+                                DispatchQueue.main.async {
+                                    APIS.addNotificationNexilis(message)
+                                }
                             }
                             }
                         }
                         }
                     }
                     }

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

@@ -63,6 +63,7 @@ public class Nexilis: NSObject {
     
     
     public static var showButtonFB = false
     public static var showButtonFB = false
     public static var isShowForceSignIn = true
     public static var isShowForceSignIn = true
+    public static var afterConnect = true
     
     
     public static var imageCache = NSCache<NSString, UIImage>()
     public static var imageCache = NSCache<NSString, UIImage>()
     
     
@@ -1504,7 +1505,7 @@ public class Nexilis: NSObject {
                         //print(error)
                         //print(error)
                     }
                     }
                 }
                 }
-                if !withStatus && !fromAPNS && !messageExist {
+                if !withStatus && !fromAPNS && (!messageExist || last_edited != 0) {
                     DispatchQueue.main.async {
                     DispatchQueue.main.async {
                         if let delegate = Nexilis.shared.messageDelegate, Utils.getSetProfile() {
                         if let delegate = Nexilis.shared.messageDelegate, Utils.getSetProfile() {
                             message.mBodies[CoreMessage_TMessageKey.MESSAGE_TEXT] = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_TEXT, default_value : "").toNormalString()
                             message.mBodies[CoreMessage_TMessageKey.MESSAGE_TEXT] = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_TEXT, default_value : "").toNormalString()

+ 73 - 295
NexilisLite/NexilisLite/Source/View/Chat/ChatGPTBotView.swift

@@ -67,6 +67,7 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
     var lastY: CGFloat = 0
     var lastY: CGFloat = 0
     
     
     var allowTyping = true
     var allowTyping = true
+    var loadingResponse = false
     
     
     struct Payload: Encodable {
     struct Payload: Encodable {
         let use_video : String
         let use_video : String
@@ -113,6 +114,9 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
     public override func viewDidLoad() {
     public override func viewDidLoad() {
         super.viewDidLoad()
         super.viewDidLoad()
         navigationController?.navigationBar.topItem?.title = "GPT SmartBot"
         navigationController?.navigationBar.topItem?.title = "GPT SmartBot"
+        if Nexilis.fromMAB {
+            Nexilis.floatingButton.isHidden = true
+        }
         
         
         buttonSendChat.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
         buttonSendChat.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
         buttonSendChat.circle()
         buttonSendChat.circle()
@@ -292,13 +296,13 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                 return
                 return
             }
             }
         }
         }
-        var l_pin = dataPerson["f_pin"]!!
-        var message_scope_id = message_scope_id
-        var chat_id = chat_id
+        let l_pin = dataPerson["f_pin"]!!
+        let message_scope_id = message_scope_id
+        let chat_id = chat_id
         let message_text = message_text.trimmingCharacters(in: .whitespacesAndNewlines)
         let message_text = message_text.trimmingCharacters(in: .whitespacesAndNewlines)
         
         
         let idMe = User.getMyPin() as String?
         let idMe = User.getMyPin() as String?
-        var opposite_pin = idMe ?? ""
+        let opposite_pin = idMe ?? ""
         sendTyping(l_pin: l_pin, isTyping: true)
         sendTyping(l_pin: l_pin, isTyping: true)
         let message = CoreMessage_TMessageBank.sendMessage(l_pin: l_pin, message_scope_id: message_scope_id, status: status, message_text: message_text, credential: credential, attachment_flag: attachment_flag, ex_blog_id: ex_blog_id, message_large_text: message_large_text, ex_format: ex_format, image_id: image_id, audio_id: audio_id, video_id: video_id, file_id: file_id, thumb_id: thumb_id, reff_id: reff_id, read_receipts: read_receipts, chat_id: chat_id, is_call_center: is_call_center, call_center_id: call_center_id, opposite_pin: opposite_pin)
         let message = CoreMessage_TMessageBank.sendMessage(l_pin: l_pin, message_scope_id: message_scope_id, status: status, message_text: message_text, credential: credential, attachment_flag: attachment_flag, ex_blog_id: ex_blog_id, message_large_text: message_large_text, ex_format: ex_format, image_id: image_id, audio_id: audio_id, video_id: video_id, file_id: file_id, thumb_id: thumb_id, reff_id: reff_id, read_receipts: read_receipts, chat_id: chat_id, is_call_center: is_call_center, call_center_id: call_center_id, opposite_pin: opposite_pin)
         Nexilis.saveMessage(message: message)
         Nexilis.saveMessage(message: message)
@@ -330,13 +334,24 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
             tableChatView.insertSections(IndexSet(integer: dataDates.count - 1), with: .none)
             tableChatView.insertSections(IndexSet(integer: dataDates.count - 1), with: .none)
         }
         }
         row["chat_date"] = "Today".localized()
         row["chat_date"] = "Today".localized()
-        dataMessages.append(row)
+        if loadingResponse {
+            dataMessages.insert(row, at: dataMessages.count - 2)
+            tableChatView.insertRows(at: [IndexPath(row: dataMessages.filter({ $0["chat_date"] as! String == dataDates[dataDates.count - 1]}).count - 2, section: dataDates.count - 1)], with: .none)
+        } else {
+            row["is_loading"] = false
+            dataMessages.append(row)
+            tableChatView.insertRows(at: [IndexPath(row: dataMessages.filter({ $0["chat_date"] as! String == dataDates[dataDates.count - 1]}).count - 1, section: dataDates.count - 1)], with: .none)
+            row["is_loading"] = true
+            row["f_pin"] = dataPerson["f_pin"]!!
+            row["l_pin"] = idMe
+            dataMessages.append(row)
+            tableChatView.insertRows(at: [IndexPath(row: dataMessages.filter({ $0["chat_date"] as! String == dataDates[dataDates.count - 1]}).count - 1, section: dataDates.count - 1)], with: .none)
+        }
         var gptRow : [String: String] = [:]
         var gptRow : [String: String] = [:]
         gptRow["role"] = row["f_pin"] as! String == "-997" ? "assistant" : "user"
         gptRow["role"] = row["f_pin"] as! String == "-997" ? "assistant" : "user"
         gptRow["content"] = row["message_text"] as? String
         gptRow["content"] = row["message_text"] as? String
         chatGPTMessages.append(gptRow)
         chatGPTMessages.append(gptRow)
         request(mesage: row["message_text"] as! String)
         request(mesage: row["message_text"] as! String)
-        tableChatView.insertRows(at: [IndexPath(row: dataMessages.filter({ $0["chat_date"] as! String == dataDates[dataDates.count - 1]}).count - 1, section: dataDates.count - 1)], with: .none)
         if textFieldSend.text!.trimmingCharacters(in: .whitespacesAndNewlines) != "Send message".localized() && textFieldSend.textColor != UIColor.lightGray && constraintViewTextField.constant == 0 {
         if textFieldSend.text!.trimmingCharacters(in: .whitespacesAndNewlines) != "Send message".localized() && textFieldSend.textColor != UIColor.lightGray && constraintViewTextField.constant == 0 {
             textFieldSend.text = "Send message".localized()
             textFieldSend.text = "Send message".localized()
             textFieldSend.textColor = UIColor.lightGray
             textFieldSend.textColor = UIColor.lightGray
@@ -345,43 +360,22 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
             heightTextFieldSend.constant = 40
             heightTextFieldSend.constant = 40
         }
         }
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.tableChatView.scrollToBottom()
-            if self.markerCounter != nil {
-                let lastMarkerCounter = self.markerCounter
-                self.markerCounter = nil
-                self.tableChatView.beginUpdates()
-                let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
-                if indexMessage != nil {
-                    let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"] as! String)
-                    let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[indexMessage!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
-                    if row != nil && section != nil  {
-                        self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
-                    }
-                }
-                self.tableChatView.endUpdates()
-            }
-        }
-//        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-//            self.timerFakeProgress = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
-//                self.updateProgress(row as [AnyHashable : Any])
-//                if self.fakeProgMultip == self.maxFakeProgMultip {
-//                    self.timerFakeProgress?.invalidate()
-//                    self.fakeProgMultip = 0
-//                }
-//            }
-//        }
+        self.tableChatView.scrollToBottom()
     }
     }
     
     
     private func request(mesage: String) {
     private func request(mesage: String) {
+        if !loadingResponse {
+            loadingResponse = true
+        }
         DispatchQueue.global().async {
         DispatchQueue.global().async {
             do {
             do {
                 if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.requestGPTBot(message: mesage)) {
                 if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.requestGPTBot(message: mesage)) {
                     if response.isOk() {
                     if response.isOk() {
                         let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
                         let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
                         if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any?] {
                         if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any?] {
-                            print("HMM \(json)")
                             DispatchQueue.main.async {
                             DispatchQueue.main.async {
+                                self.dataMessages.removeAll(where: { $0["is_loading"] as? Bool == true })
+                                self.tableChatView.reloadData()
                                 var gptRow : [String: String] = [:]
                                 var gptRow : [String: String] = [:]
                                 gptRow["role"] = json["role"] as? String
                                 gptRow["role"] = json["role"] as? String
                                 gptRow["content"] = json["content"] as? String
                                 gptRow["content"] = json["content"] as? String
@@ -440,30 +434,12 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                                     }
                                     }
                                 })
                                 })
                                 let pin = "-997"
                                 let pin = "-997"
-                                var counter : Int? = nil
-                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                                    do {
-                                        if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select counter from MESSAGE_SUMMARY where l_pin = '\(pin)'"), cursor.next() {
-                                            counter = Int(cursor.int(forColumnIndex: 0))
-                                            counter! += 1
-                                            cursor.close()
-                                            //print("select db message summary")
-                                        }
-                                    } catch {
-                                        rollback.pointee = true
-                                        print("Access database error: \(error.localizedDescription)")
-                                    }
-                                })
-                                if counter == nil {
-                                    counter = 1
-                                    //print("set counter message summary")
-                                }
                                 Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                 Database.shared.database?.inTransaction({ (fmdb, rollback) in
                                     do {
                                     do {
                                         _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
                                         _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
                                             "l_pin" : pin,
                                             "l_pin" : pin,
                                             "message_id" : message_id,
                                             "message_id" : message_id,
-                                            "counter" : counter!
+                                            "counter" : 0
                                         ], replace: true)
                                         ], replace: true)
                                     } catch {
                                     } catch {
                                         rollback.pointee = true
                                         rollback.pointee = true
@@ -501,55 +477,9 @@ public class ChatGPTBotView: UIViewController, UIGestureRecognizerDelegate {
                                 self.counter += 1
                                 self.counter += 1
                                 self.dataMessages.append(row)
                                 self.dataMessages.append(row)
                                 self.tableChatView.insertRows(at: [IndexPath(row: self.dataMessages.filter({ $0["chat_date"] as! String == self.dataDates[self.dataDates.count - 1]}).count - 1, section: self.dataDates.count - 1)], with: .none)
                                 self.tableChatView.insertRows(at: [IndexPath(row: self.dataMessages.filter({ $0["chat_date"] as! String == self.dataDates[self.dataDates.count - 1]}).count - 1, section: self.dataDates.count - 1)], with: .none)
-                                if self.currentIndexpath?.row == (self.dataMessages.count - 2) {
-                                    if (self.viewIfLoaded?.window != nil) {
-                                        self.sendReadMessageStatus(chat_id: "", f_pin: row["f_pin"] as! String, message_scope_id: row["message_scope_id"] as! String, message_id: message_id)
-                                    }
-                                    self.tableChatView.scrollToBottom()
-                                    if ( self.currentIndexpath!.section <= self.dataDates.count - 1 && self.currentIndexpath!.row <= self.dataMessages.filter({ $0["chat_date"] as! String == self.dataDates[self.dataDates.count - 1]}).count - 1)  {
-                                        self.counter = 0
-                                        self.updateCounter(counter: self.counter)
-                                    }
-                                    let lastMarkerCounter = self.markerCounter
-                                    if self.markerCounter != nil {
-                                        self.markerCounter = nil
-                                    }
-                                    self.tableChatView.beginUpdates()
-                                    let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
-                                    if indexMessage != nil {
-                                        let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"] as! String)
-                                        let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[indexMessage!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
-                                        if row != nil && section != nil  {
-                                            self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
-                                        }
-                                    }
-                                    self.tableChatView.endUpdates()
-                                }
-                                else if self.currentIndexpath == nil {
-                                    self.counter = 0
-                                    self.updateCounter(counter: self.counter)
-                                    if (self.viewIfLoaded?.window != nil) {
-                                        self.sendReadMessageStatus(chat_id: "", f_pin: row["f_pin"] as! String, message_scope_id: row["message_scope_id"] as! String, message_id: message_id)
-                                    }
-                                }
-                                else if self.counter != 0 {
-                                    if !self.indicatorCounterBSTB.isDescendant(of: self.view) && self.buttonScrollToBottom.isDescendant(of: self.view) {
-                                        self.markerCounter = row["message_id"] as? String
-                                        self.addCounterAtButttonScrollToBottom()
-                                        self.tableChatView.beginUpdates()
-                                        let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == self.markerCounter })
-                                        if indexMessage != nil {
-                                            let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"] as! String)
-                                            let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[indexMessage!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
-                                            if row != nil && section != nil  {
-                                                self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
-                                            }
-                                        }
-                                        self.tableChatView.endUpdates()
-                                    } else if self.indicatorCounterBSTB.isDescendant(of: self.view) {
-                                        self.labelCounter.text = "\(self.counter)"
-                                    }
-                                }
+                                self.tableChatView.scrollToBottom()
+                                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                                self.loadingResponse = false
                             }
                             }
                         }
                         }
                     }
                     }
@@ -1844,15 +1774,11 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let idMe = User.getMyPin() as String?
         let idMe = User.getMyPin() as String?
         let dataMessages = dataMessages.filter({$0["chat_date"] as! String == dataDates[indexPath.section]})
         let dataMessages = dataMessages.filter({$0["chat_date"] as! String == dataDates[indexPath.section]})
-        let profileMessage = UIImageView()
         let cell = tableView.dequeueReusableCell(withIdentifier: "cellEditorPersonal", for: indexPath as IndexPath)
         let cell = tableView.dequeueReusableCell(withIdentifier: "cellEditorPersonal", for: indexPath as IndexPath)
         cell.contentView.subviews.forEach({ $0.removeFromSuperview() })
         cell.contentView.subviews.forEach({ $0.removeFromSuperview() })
         
         
-        let messageIdChat = (dataMessages[indexPath.row]["message_id"] as? String) ?? ""
-        
         cell.backgroundColor = .clear
         cell.backgroundColor = .clear
         cell.selectionStyle = .none
         cell.selectionStyle = .none
-        let nameSender = UILabel()
         
         
         let containerMessage = UIView()
         let containerMessage = UIView()
         cell.contentView.addSubview(containerMessage)
         cell.contentView.addSubview(containerMessage)
@@ -1983,147 +1909,55 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
             imageStared.tintColor = .systemYellow
             imageStared.tintColor = .systemYellow
         }
         }
         
         
-        if dataMessages[indexPath.row]["read_receipts"] as? String == "8" {
-            let imageAckView = UIImageView()
-            var imageAck = UIImage(named: "ack_icon_gray", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
-            if dataMessages[indexPath.row]["status"] as? String == "8" {
-                imageAck = UIImage(named: "ack_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
-            }
-            imageAckView.image = imageAck
-            cell.contentView.addSubview(imageAckView)
-            imageAckView.translatesAutoresizingMaskIntoConstraints = false
-            imageAckView.widthAnchor.constraint(equalToConstant: 30).isActive = true
-            imageAckView.heightAnchor.constraint(equalToConstant: 30).isActive = true
-            if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
-                imageAckView.topAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: 5).isActive = true
-                imageAckView.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 30).isActive = true
-            } else {
-                imageAckView.topAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: 5).isActive = true
-                imageAckView.leadingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -30).isActive = true
-                let tap = ObjectGesture(target: self, action: #selector(tapAck(_:)))
-                tap.indexPath = indexPath
-                imageAckView.addGestureRecognizer(tap)
-                imageAckView.isUserInteractionEnabled = true
-            }
-        }
-        
-        if (dataMessages[indexPath.row]["credential"] as? String) == "1" && (dataMessages[indexPath.row]["lock"] as? String) != "2" {
-            let imageCredentialView = UIImageView()
-            let imageCredential = UIImage(named: "confidential_icon", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
-            imageCredentialView.image = imageCredential
-            cell.contentView.addSubview(imageCredentialView)
-            imageCredentialView.translatesAutoresizingMaskIntoConstraints = false
-            imageCredentialView.widthAnchor.constraint(equalToConstant: 30).isActive = true
-            imageCredentialView.heightAnchor.constraint(equalToConstant: 30).isActive = true
-            if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
-                imageCredentialView.topAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: 5).isActive = true
-                imageCredentialView.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 30).isActive = true
-            } else {
-                imageCredentialView.topAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: 5).isActive = true
-                imageCredentialView.leadingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -30).isActive = true
-            }
-        }
-        
         let messageText = UILabel()
         let messageText = UILabel()
-        messageText.numberOfLines = 0
-        messageText.lineBreakMode = .byWordWrapping
-        containerMessage.addSubview(messageText)
-        messageText.translatesAutoresizingMaskIntoConstraints = false
-        let topMarginText = messageText.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 15)
-        topMarginText.isActive = true
-        messageText.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
-        messageText.font = .systemFont(ofSize: 12)
-        messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
-        if dataMessages[indexPath.row]["f_pin"] as? String == "-999" && (dataMessages[indexPath.row]["blog_id"] as? String) != nil && !(dataMessages[indexPath.row]["blog_id"] as! String).isEmpty && (dataMessages[indexPath.row]["message_text"] as! String).contains("Berikut QR Code dan detil booking Anda") {
-            messageText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: -115).isActive = true
-            let imageQR = UIImageView()
-            containerMessage.addSubview(imageQR)
-            imageQR.translatesAutoresizingMaskIntoConstraints = false
-            NSLayoutConstraint.activate([
-                imageQR.centerXAnchor.constraint(equalTo: containerMessage.centerXAnchor),
-                imageQR.topAnchor.constraint(equalTo: messageText.bottomAnchor),
-                imageQR.widthAnchor.constraint(equalToConstant: 100.0),
-                imageQR.heightAnchor.constraint(equalToConstant: 100.0)
-            ])
-            imageQR.image = generateQRCode(from: dataMessages[indexPath.row]["blog_id"] as! String)
-        } else {
+        let textChat = (dataMessages[indexPath.row]["message_text"] as? String) ?? ""
+        let isLoading = dataMessages[indexPath.row]["is_loading"] as? Bool ?? false
+        if !isLoading {
+            messageText.numberOfLines = 0
+            messageText.lineBreakMode = .byWordWrapping
+            containerMessage.addSubview(messageText)
+            messageText.translatesAutoresizingMaskIntoConstraints = false
+            let topMarginText = messageText.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 15)
+            topMarginText.isActive = true
+            messageText.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+            messageText.font = .systemFont(ofSize: 12)
+            messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
             messageText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: -15).isActive = true
             messageText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: -15).isActive = true
-        }
-        messageText.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
-        var textChat = (dataMessages[indexPath.row]["message_text"] as? String) ?? ""
-        if (dataMessages[indexPath.row]["lock"] != nil && (dataMessages[indexPath.row]["lock"])! as? String == "1") {
-            if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
-                textChat = "🚫 _"+"You were deleted this message".localized()+"_"
-            } else {
-                textChat = "🚫 _"+"This message was deleted".localized()+"_"
-            }
-        }
-        
-        if dataMessages[indexPath.row]["lock"] as? String == "2" {
-            textChat = "🚫 _"+"Message has expired".localized()+"_"
-        }
-        
-        let imageSticker = UIImageView()
-        if let attachmentFlag = dataMessages[indexPath.row]["attachment_flag"], let attachmentFlag = attachmentFlag as? String {
-            if attachmentFlag == "27" || attachmentFlag == "26" { // live streaming
-                let data = textChat
-                if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
-                    Database().database?.inTransaction({ fmdb, rollback in
-                        let title = json["title"] as? String ?? ""
-                        let description = json["description"] as? String ?? ""
-                        let start = json["time"] as? Int64 ?? 0
-                        let by = json["by"] as? String ?? ""
-                        let textLS = "Live Streaming".localized()
-                        var type = "*\(textLS)*"
-                        if attachmentFlag == "26" {
-                            let textSeminar = "Seminar".localized()
-                            type = "*\(textSeminar)*"
-                        }
-                        if let c = Database().getRecords(fmdb: fmdb, query: "select first_name || ' ' || last_name from BUDDY where f_pin = '\(by)'"), c.next() {
-                            let name = c.string(forColumnIndex: 0)!
-                            messageText.attributedText = "\(type) \nTitle: \(title) \nDescription: \(description) \nStart: \(Date(milliseconds: start).format(dateFormat: "dd/MM/yyyy HH:mm")) \nBroadcaster: \(name)".richText()
-                            c.close()
-                        } else {
-                            messageText.attributedText = ("\(type) \nTitle: \(title) \nDescription: \(description) \nStart: \(Date(milliseconds: start).format(dateFormat: "dd/MM/yyyy HH:mm"))").richText()
-                        }
-                    })
+            messageText.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
+            let textChat = (dataMessages[indexPath.row]["message_text"] as? String) ?? ""
+            messageText.attributedText = textChat.richText()
+        } else {
+            let gifTyping = UIImageView()
+            containerMessage.addSubview(gifTyping)
+            gifTyping.translatesAutoresizingMaskIntoConstraints = false
+            gifTyping.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor).isActive = true
+            gifTyping.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor).isActive = true
+            gifTyping.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor).isActive = true
+            gifTyping.topAnchor.constraint(equalTo: containerMessage.topAnchor).isActive = true
+            gifTyping.widthAnchor.constraint(equalToConstant: 60).isActive = true
+            gifTyping.heightAnchor.constraint(equalToConstant: 60).isActive = true
+            if let urlGif = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_typing_chat", withExtension: "gif") {
+                gifTyping.sd_setImage(with: urlGif) { (image, error, cacheType, imageURL) in
+                    if error == nil {
+                        gifTyping.animationImages = image?.images
+                        gifTyping.animationDuration = image?.duration ?? 0.0
+                        gifTyping.animationRepeatCount = 0
+                        gifTyping.startAnimating()
+                    }
                 }
                 }
-            }
-            else if attachmentFlag == "11" && (dataMessages[indexPath.row]["lock"] == nil || dataMessages[indexPath.row]["lock"] as! String != "1") && (dataMessages[indexPath.row]["lock"] as? String != "2") {
-                messageText.text = ""
-                topMarginText.constant = topMarginText.constant + 100
-                containerMessage.addSubview(imageSticker)
-                imageSticker.translatesAutoresizingMaskIntoConstraints = false
-                imageSticker.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 15).isActive = true
-                imageSticker.widthAnchor.constraint(equalToConstant: 80).isActive = true
-                imageSticker.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
-                imageSticker.bottomAnchor.constraint(equalTo: messageText.topAnchor, constant: -5).isActive = true
-                imageSticker.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
-                var imageStickerBundle = UIImage(named: (textChat.components(separatedBy: "/")[1]), in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
-                if imageStickerBundle == nil {
-                    imageStickerBundle = UIImage(named: (textChat.components(separatedBy: "/")[1]), in: Bundle.resourcesMediaBundle(for: Nexilis.self), with: nil)
+            } else if let urlGif = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_typing_chat", withExtension: "gif") {
+                gifTyping.sd_setImage(with: urlGif) { (image, error, cacheType, imageURL) in
+                    if error == nil {
+                        gifTyping.animationImages = image?.images
+                        gifTyping.animationDuration = image?.duration ?? 0.0
+                        gifTyping.animationRepeatCount = 0
+                        gifTyping.startAnimating()
+                    }
                 }
                 }
-                imageSticker.image = imageStickerBundle //resourcesMediaBundle
-                imageSticker.contentMode = .scaleAspectFit
-            }
-            else {
-                messageText.attributedText = textChat.richText()
             }
             }
-        } else {
-            messageText.attributedText = textChat.richText()
         }
         }
         
         
-        messageText.isUserInteractionEnabled = false
-        if !textChat.isEmpty {
-            if textChat.contains("■"){
-                textChat = textChat.components(separatedBy: "■")[0]
-                textChat = textChat.trimmingCharacters(in: .whitespacesAndNewlines)
-            }
-            let listTextEnter = textChat.split(separator: "\n")
-            let finalAtribute = textChat.richText()
-        }
-        
-        if !copySession && !deleteSession && messageText.isUserInteractionEnabled == false {
+        if !copySession && !deleteSession && !isLoading {
             let interaction = UIContextMenuInteraction(delegate: self)
             let interaction = UIContextMenuInteraction(delegate: self)
             containerMessage.addInteraction(interaction)
             containerMessage.addInteraction(interaction)
             containerMessage.isUserInteractionEnabled = true
             containerMessage.isUserInteractionEnabled = true
@@ -2146,9 +1980,6 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
             timeMessage.textColor = .lightGray
             timeMessage.textColor = .lightGray
             timeMessage.font = UIFont.systemFont(ofSize: 10, weight: .medium)
             timeMessage.font = UIFont.systemFont(ofSize: 10, weight: .medium)
         }
         }
-//        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureCellAction))
-//        panGestureRecognizer.delegate = self
-//        cellMessage.addGestureRecognizer(panGestureRecognizer)
         return cell
         return cell
     }
     }
     
     
@@ -2193,59 +2024,6 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
         }
         }
     }
     }
     
     
-//    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
-//        let velocity : CGPoint = gestureRecognizer.location(in: tableChatView)
-//        if velocity.x < 0 {
-//            return false
-//        }
-//        return abs(Float(velocity.x)) > abs(Float(velocity.y))
-//    }
-//
-//    @objc func panGestureCellAction(recognizer: UIPanGestureRecognizer)  {
-//        let translation = recognizer.translation(in: tableChatView)
-//        let x = recognizer.view?.frame.origin.x ?? 0
-//        if x >= -(recognizer.view?.frame.size.width ?? 0) * 0.05 {
-//            recognizer.view?.center = CGPoint(
-//                x: (recognizer.view?.center.x ?? 0) + translation.x,
-//                y: (recognizer.view?.center.y ?? 0))
-//            recognizer.setTranslation(CGPoint(x: 0, y: 0), in: view)
-//            if (recognizer.view?.frame.origin.x ?? 0) > UIScreen.main.bounds.size.width * 0.9 {
-//                UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut, animations: {
-//                    recognizer.view?.frame = CGRect(x: 0, y: recognizer.view?.frame.origin.y ?? 0, width: recognizer.view?.frame.size.width ?? 0, height: recognizer.view?.frame.size.height ?? 0)
-//                })
-//            }
-//        }
-//        if x <= -(recognizer.view?.frame.size.width ?? 0) * 0.05 {
-//            let idMe = User.getMyPin() as String?
-//            let indexPath = self.tableChatView.indexPath(for: recognizer.view! as! UITableViewCell)
-//            let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath!.section]})
-//            if (dataMessages[indexPath!.row]["f_pin"] as? String == idMe) {
-//                let messageInfoVC = MessageInfo()
-//                messageInfoVC.data = dataMessages[indexPath!.row]
-//                self.navigationController?.pushViewController(messageInfoVC, animated: true)
-//                return
-//            }
-//        }
-//        if x >= ((recognizer.view?.frame.size.width ?? 0) * 0.2) {
-//            if !hapticSwipeLeft {
-//                UINotificationFeedbackGenerator().notificationOccurred(.success)
-//            }
-//            hapticSwipeLeft = true
-//        } else if x < ((recognizer.view?.frame.size.width ?? 0) * 0.2) {
-//            hapticSwipeLeft = false
-//        }
-//        if recognizer.state == .ended {
-//            UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
-//                recognizer.view?.frame = CGRect(x: 0, y: recognizer.view?.frame.origin.y ?? 0, width: recognizer.view?.frame.size.width ?? 0, height: recognizer.view?.frame.size.height ?? 0)
-//            } completion: { (finished) in
-//                if x > ((recognizer.view?.frame.size.width ?? 0) * 0.2) {
-//                    self.hapticSwipeLeft = false
-//
-//                }
-//            }
-//        }
-//    }
-    
     public func numberOfSections(in tableView: UITableView) -> Int {
     public func numberOfSections(in tableView: UITableView) -> Int {
         dataDates.count
         dataDates.count
     }
     }

+ 33 - 46
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -112,6 +112,7 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
     var longitude = ""
     var longitude = ""
     var latitude = ""
     var latitude = ""
     var isBlackCancelButton = false
     var isBlackCancelButton = false
+    let buttonSendEdit = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
     
     
     public override func viewDidDisappear(_ animated: Bool) {
     public override func viewDidDisappear(_ animated: Bool) {
         if self.isMovingFromParent {
         if self.isMovingFromParent {
@@ -1878,32 +1879,21 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
         deleteLinkPreview()
         deleteLinkPreview()
         listMentionInTextField.removeAll()
         listMentionInTextField.removeAll()
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.tableChatView.scrollToBottom()
-            if self.markerCounter != nil {
-                let lastMarkerCounter = self.markerCounter
-                self.markerCounter = nil
-                self.tableChatView.beginUpdates()
-                let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
-                if indexMessage != nil {
-                    let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"]  as? String ?? "")
-                    let row = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == self.dataMessages[indexMessage!]["chat_date"]  as? String ?? ""}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
-                    if row != nil && section != nil  {
-                        self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
-                    }
+        self.tableChatView.scrollToBottom()
+        if self.markerCounter != nil {
+            let lastMarkerCounter = self.markerCounter
+            self.markerCounter = nil
+            self.tableChatView.beginUpdates()
+            let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
+            if indexMessage != nil {
+                let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"]  as? String ?? "")
+                let row = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == self.dataMessages[indexMessage!]["chat_date"]  as? String ?? ""}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
+                if row != nil && section != nil  {
+                    self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
                 }
                 }
-                self.tableChatView.endUpdates()
             }
             }
+            self.tableChatView.endUpdates()
         }
         }
-        //        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-        //            self.timerFakeProgress = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
-        //                self.updateProgress(row as [AnyHashable : Any])
-        //                if self.fakeProgMultip == self.maxFakeProgMultip {
-        //                    self.timerFakeProgress?.invalidate()
-        //                    self.fakeProgMultip = 0
-        //                }
-        //            }
-        //        }
     }
     }
     
     
     private func getCounter() {
     private func getCounter() {
@@ -2506,20 +2496,11 @@ extension EditorGroup: UITextViewDelegate {
                 }
                 }
             }
             }
         }
         }
-//        let cursorPosition = textView.caretRect(for: self.textFieldSend.selectedTextRange!.start).origin
-//        let currentLine = Int(cursorPosition.y / self.textFieldSend.font!.lineHeight)
-//        UIView.animate(withDuration: 0.3) {
-//            let numberOfLines = textView.textContainer.lineBreakMode == .byWordWrapping ? Int(textView.contentSize.height / textView.font!.lineHeight) - 1 : 1
-//            if currentLine == 0 && numberOfLines == 1 {
-//                self.heightTextFieldSend.constant = 40
-//            } else if self.heightTextFieldSend.constant < 95.0 && currentLine >= 4 {
-//                self.heightTextFieldSend.constant = 95.0
-//            } else if currentLine < 4 && numberOfLines < 5 {
-//                if (self.textFieldSend.text.count > 0 && self.heightTextFieldSend.constant != self.textFieldSend.contentSize.height) {
-//                    self.heightTextFieldSend.constant = self.textFieldSend.contentSize.height
-//                }
-//            }
-//        }
+        if self.isEditingMessage && textView == editTextView {
+            if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                buttonSendEdit.isEnabled = false
+            }
+        }
     }
     }
     
     
     public func textViewDidChange(_ textView: UITextView) {
     public func textViewDidChange(_ textView: UITextView) {
@@ -3243,7 +3224,12 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
                 }
                 }
                 if !(dataMessages[indexPath!.row][TypeDataMessage.message_text]  as? String ?? "").isEmpty {
                 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 {
                     if (dataMessages[indexPath!.row]["f_pin"]  as? String ?? "") == idMe && ((dataMessages[indexPath!.row][TypeDataMessage.is_forwarded] as? Int) ?? 0) == 0 {
-                        children.insert(edit, at: children.count - 1)
+                        let date = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
+                        let pastDate = date.addingTimeInterval(-10 * 60)
+                        let differenceInSeconds = date.timeIntervalSince(pastDate)
+                        if abs(differenceInSeconds) <= 15 * 60 {
+                            children.insert(edit, at: children.count - 1)
+                        }
                     }
                     }
                     isMore = true
                     isMore = true
                 }
                 }
@@ -3302,10 +3288,10 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             editTextView.text = oldText
             editTextView.text = oldText
             editTextView.becomeFirstResponder()
             editTextView.becomeFirstResponder()
             
             
-            let buttonSend = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
-            buttonSend.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
-            buttonSend.circle()
-            buttonSend.actionHandle(controlEvents: .touchUpInside,
+            buttonSendEdit.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
+            buttonSendEdit.circle()
+            buttonSendEdit.isEnabled = true
+            buttonSendEdit.actionHandle(controlEvents: .touchUpInside,
              ForAction:{() -> Void in
              ForAction:{() -> Void in
                 let newText = self.editTextView.text ?? ""
                 let newText = self.editTextView.text ?? ""
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
@@ -3334,10 +3320,10 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
                     }
                     }
                 }
                 }
              })
              })
-            buttonSend.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
-            view.addSubview(buttonSend)
-            buttonSend.anchor(right: view.rightAnchor, paddingRight: 15, width: 40, height: 40)
-            constraintBottomSendEditTV = buttonSend.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -15)
+            buttonSendEdit.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
+            view.addSubview(buttonSendEdit)
+            buttonSendEdit.anchor(right: view.rightAnchor, paddingRight: 15, width: 40, height: 40)
+            constraintBottomSendEditTV = buttonSendEdit.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -15)
             constraintBottomSendEditTV.isActive = true
             constraintBottomSendEditTV.isActive = true
             
             
             let viewMessage = UIView()
             let viewMessage = UIView()
@@ -4174,6 +4160,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
         let cellMessage = tableView.dequeueReusableCell(withIdentifier: "cellEditorGroup", for: indexPath as IndexPath)
         let cellMessage = tableView.dequeueReusableCell(withIdentifier: "cellEditorGroup", for: indexPath as IndexPath)
         cellMessage.backgroundColor = .clear
         cellMessage.backgroundColor = .clear
         cellMessage.selectionStyle = .none
         cellMessage.selectionStyle = .none
+        cellMessage.contentView.subviews.forEach({ $0.removeConstraints($0.constraints) })
         cellMessage.contentView.subviews.forEach({ $0.removeFromSuperview() })
         cellMessage.contentView.subviews.forEach({ $0.removeFromSuperview() })
         
         
         let profileMessage = UIImageView()
         let profileMessage = UIImageView()

+ 33 - 25
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -123,6 +123,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var longitude = ""
     var longitude = ""
     var latitude = ""
     var latitude = ""
     var isBlackCancelButton = false
     var isBlackCancelButton = false
+    let buttonSendEdit = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
     
     
     public override func viewDidDisappear(_ animated: Bool) {
     public override func viewDidDisappear(_ animated: Bool) {
         if self.isMovingFromParent {
         if self.isMovingFromParent {
@@ -1692,7 +1693,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                         let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
                         let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
                         if officer == idMe {
                         if officer == idMe {
                             self.timeoutCC.invalidate()
                             self.timeoutCC.invalidate()
-                        } else {
+                        } else if !fromVCAC {
                             if !self.showToast30s {
                             if !self.showToast30s {
                                 self.view.makeToast("Please reply within 30 seconds so the call center session doesn't end.".localized(), duration: 3)
                                 self.view.makeToast("Please reply within 30 seconds so the call center session doesn't end.".localized(), duration: 3)
                                 sendTyping(l_pin: fPinContacCenter, isTyping: true)
                                 sendTyping(l_pin: fPinContacCenter, isTyping: true)
@@ -2690,22 +2691,20 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         deleteReplyView()
         deleteReplyView()
         deleteLinkPreview()
         deleteLinkPreview()
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.tableChatView.scrollToBottom()
-            if self.markerCounter != nil {
-                let lastMarkerCounter = self.markerCounter
-                self.markerCounter = nil
-                self.tableChatView.beginUpdates()
-                let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
-                if indexMessage != nil {
-                    let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"]  as? String ?? "")
-                    let row = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == self.dataMessages[indexMessage!]["chat_date"]  as? String ?? ""}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
-                    if row != nil && section != nil  {
-                        self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
-                    }
+        self.tableChatView.scrollToBottom()
+        if self.markerCounter != nil {
+            let lastMarkerCounter = self.markerCounter
+            self.markerCounter = nil
+            self.tableChatView.beginUpdates()
+            let indexMessage = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == lastMarkerCounter })
+            if indexMessage != nil {
+                let section = self.dataDates.firstIndex(of: self.dataMessages[indexMessage!]["chat_date"]  as? String ?? "")
+                let row = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == self.dataMessages[indexMessage!]["chat_date"]  as? String ?? ""}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[indexMessage!]["message_id"] as? String })
+                if row != nil && section != nil  {
+                    self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
                 }
                 }
-                self.tableChatView.endUpdates()
             }
             }
+            self.tableChatView.endUpdates()
         }
         }
 //        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 //        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
 //            self.timerFakeProgress = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
 //            self.timerFakeProgress = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
@@ -3668,6 +3667,11 @@ extension EditorPersonal: UITextViewDelegate {
                 }
                 }
             }
             }
         }
         }
+        if self.isEditingMessage && textView == editTextView {
+            if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                buttonSendEdit.isEnabled = false
+            }
+        }
     }
     }
     
     
     public func textViewDidChange(_ textView: UITextView) {
     public func textViewDidChange(_ textView: UITextView) {
@@ -4306,7 +4310,12 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             }
             }
             if !(dataMessages[indexPath!.row][TypeDataMessage.message_text]  as? String ?? "").isEmpty {
             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 {
                 if (dataMessages[indexPath!.row]["f_pin"]  as? String ?? "") == idMe && ((dataMessages[indexPath!.row][TypeDataMessage.is_forwarded] as? Int) ?? 0) == 0 {
-                    children.insert(edit, at: children.count - 1)
+                    let date = Date(milliseconds: Int64(dataMessages[indexPath!.row][TypeDataMessage.server_date] as? String ?? "") ?? 0)
+                    let pastDate = date.addingTimeInterval(-10 * 60)
+                    let differenceInSeconds = date.timeIntervalSince(pastDate)
+                    if abs(differenceInSeconds) <= 15 * 60 {
+                        children.insert(edit, at: children.count - 1)
+                    }
                 }
                 }
                 isMore = true
                 isMore = true
             }
             }
@@ -4363,10 +4372,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             editTextView.text = oldText
             editTextView.text = oldText
             editTextView.becomeFirstResponder()
             editTextView.becomeFirstResponder()
             
             
-            let buttonSend = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
-            buttonSend.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
-            buttonSend.circle()
-            buttonSend.actionHandle(controlEvents: .touchUpInside,
+            buttonSendEdit.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
+            buttonSendEdit.circle()
+            buttonSendEdit.isEnabled = true
+            buttonSendEdit.actionHandle(controlEvents: .touchUpInside,
              ForAction:{() -> Void in
              ForAction:{() -> Void in
                 let newText = self.editTextView.text ?? ""
                 let newText = self.editTextView.text ?? ""
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
@@ -4395,10 +4404,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
                     }
                     }
                 }
                 }
              })
              })
-            buttonSend.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
-            view.addSubview(buttonSend)
-            buttonSend.anchor(right: view.rightAnchor, paddingRight: 15, width: 40, height: 40)
-            constraintBottomSendEditTV = buttonSend.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -15)
+            buttonSendEdit.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
+            view.addSubview(buttonSendEdit)
+            buttonSendEdit.anchor(right: view.rightAnchor, paddingRight: 15, width: 40, height: 40)
+            constraintBottomSendEditTV = buttonSendEdit.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -15)
             constraintBottomSendEditTV.isActive = true
             constraintBottomSendEditTV.isActive = true
             
             
             let viewMessage = UIView()
             let viewMessage = UIView()
@@ -5265,7 +5274,6 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                 containerMessage.addSubview(messageText)
                 containerMessage.addSubview(messageText)
                 messageText.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 5).isActive = true
                 messageText.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 5).isActive = true
                 messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
                 messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
-                messageText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: -5).isActive = true
                 messageText.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
                 messageText.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
                 if category_cc[0].id.contains("level0_") || dataMessages[indexPath.row]["attachment_flag"] != nil && dataMessages[indexPath.row]["attachment_flag"]  as? String ?? "" == "503" {
                 if category_cc[0].id.contains("level0_") || dataMessages[indexPath.row]["attachment_flag"] != nil && dataMessages[indexPath.row]["attachment_flag"]  as? String ?? "" == "503" {
                     messageText.text = "Welcome to".localized() + " " + dataPerson["name"]!! + " " + "Contact Center".localized()
                     messageText.text = "Welcome to".localized() + " " + dataPerson["name"]!! + " " + "Contact Center".localized()

+ 3 - 0
NexilisLite/NexilisLite/Source/View/Control/ConfigureFloatingButton.swift

@@ -120,6 +120,9 @@ public class ConfigureFloatingButton: UIViewController {
             Nexilis.floatingButton = FloatingButton()
             Nexilis.floatingButton = FloatingButton()
             let viewController = (UIApplication.shared.windows.first?.rootViewController)!
             let viewController = (UIApplication.shared.windows.first?.rootViewController)!
             Nexilis.addFB(viewController: viewController, fromMAB: Nexilis.fromMAB)
             Nexilis.addFB(viewController: viewController, fromMAB: Nexilis.fromMAB)
+            if Nexilis.fromMAB {
+                Nexilis.floatingButton.isHidden = true
+            }
         }
         }
         close()
         close()
     }
     }

+ 79 - 49
NexilisLite/NexilisLite/Source/View/Control/ProfileViewController.swift

@@ -598,10 +598,54 @@ public class ProfileViewController: UITableViewController, UITextFieldDelegate {
     }
     }
     
     
     func didTapProfile() {
     func didTapProfile() {
-        if let userImage = user?.thumb {
-            if !userImage.isEmpty {
-                let firstAlert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
-                firstAlert.addAction(UIAlertAction(title: "Change Profile Picture".localized(), style: .default, handler: { action in
+        if let me = User.getMyPin(), me == data || flag == Flag.me {
+            if let userImage = user?.thumb {
+                if !userImage.isEmpty {
+                    let firstAlert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
+                    firstAlert.addAction(UIAlertAction(title: "Change Profile Picture".localized(), style: .default, handler: { action in
+                        let alert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
+                        alert.addAction(UIAlertAction(title: "Take Photo".localized(), style: .default, handler: { action in
+                            self.imageVideoPicker.present(source: .imageCamera)
+                        }))
+                        alert.addAction(UIAlertAction(title: "Choose Photo".localized(), style: .default, handler: { action in
+                            self.imageVideoPicker.present(source: .imageAlbum)
+                        }))
+                        alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: { action in
+                            
+                        }))
+                        self.navigationController?.present(alert, animated: true)
+                    }))
+                    firstAlert.addAction(UIAlertAction(title: "Remove Profile Picture".localized(), style: .default, handler: { action in
+                        if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChangePersonImage(thumb_id: "")), response.isOk() {
+                            guard let me = User.getMyPin() else {
+                                return
+                            }
+                            Database.shared.database?.inTransaction({ fmdb, rollback in
+                                do {
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: ["image_id": ""], _where: "f_pin = '\(me)'")
+                                } catch {
+                                    rollback.pointee = true
+                                    print("Access database error: \(error.localizedDescription)")
+                                }
+                            })
+                            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateFifthTab"), object: nil, userInfo: nil)
+                            
+                            DispatchQueue.main.async { [self] in
+                                self.profile.image = UIImage(systemName: "person.circle.fill")!
+                                self.profile.backgroundColor = .white
+                                self.user?.thumb = ""
+                                let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                imageView.tintColor = .white
+                                publicBanner.dismiss()
+                                publicBanner = FloatingNotificationBanner(title: "Successfully removed profile picture".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
+                                publicBanner.show()
+                                self.dismissImage?(UIImage(systemName: "person.circle.fill")!, "")
+                            }
+                        }
+                    }))
+                    firstAlert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
+                    self.navigationController?.present(firstAlert, animated: true)
+                } else {
                     let alert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
                     let alert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
                     alert.addAction(UIAlertAction(title: "Take Photo".localized(), style: .default, handler: { action in
                     alert.addAction(UIAlertAction(title: "Take Photo".localized(), style: .default, handler: { action in
                         self.imageVideoPicker.present(source: .imageCamera)
                         self.imageVideoPicker.present(source: .imageCamera)
@@ -613,49 +657,37 @@ public class ProfileViewController: UITableViewController, UITextFieldDelegate {
                         
                         
                     }))
                     }))
                     self.navigationController?.present(alert, animated: true)
                     self.navigationController?.present(alert, animated: true)
-                }))
-                firstAlert.addAction(UIAlertAction(title: "Remove Profile Picture".localized(), style: .default, handler: { action in
-                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChangePersonImage(thumb_id: "")), response.isOk() {
-                        guard let me = User.getMyPin() else {
-                            return
-                        }
-                        Database.shared.database?.inTransaction({ fmdb, rollback in
-                            do {
-                                _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: ["image_id": ""], _where: "f_pin = '\(me)'")
-                            } catch {
-                                rollback.pointee = true
-                                print("Access database error: \(error.localizedDescription)")
-                            }
-                        })
-                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateFifthTab"), object: nil, userInfo: nil)
-                        
-                        DispatchQueue.main.async { [self] in
-                            self.profile.image = UIImage(systemName: "person.circle.fill")!
-                            self.profile.backgroundColor = .white
-                            self.user?.thumb = ""
-                            let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
-                            imageView.tintColor = .white
-                            publicBanner.dismiss()
-                            publicBanner = FloatingNotificationBanner(title: "Successfully removed profile picture".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
-                            publicBanner.show()
-                            self.dismissImage?(UIImage(systemName: "person.circle.fill")!, "")
-                        }
+                }
+            }
+        } else {
+            let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
+            let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
+            let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+            if let dirPath = paths.first {
+                let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(self.user!.thumb)
+                if FileManager.default.fileExists(atPath: imageURL.path) {
+                    let image    = UIImage(contentsOfFile: imageURL.path)
+                    let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: Nexilis.self))
+                    previewImageVC.image = image
+                    previewImageVC.isHiddenTextField = true
+                    previewImageVC.modalPresentationStyle = .custom
+                    previewImageVC.modalTransitionStyle  = .crossDissolve
+                    self.present(previewImageVC, animated: true, completion: nil)
+                } else if FileEncryption.shared.isSecureExists(filename: self.user!.thumb) {
+                    do {
+                        let data = try FileEncryption.shared.readSecure(filename: self.user!.thumb)
+                        let image = UIImage(data: data!)
+                        let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: Nexilis.self))
+                        previewImageVC.image = image
+                        previewImageVC.isHiddenTextField = true
+                        previewImageVC.modalPresentationStyle = .custom
+                        previewImageVC.modalTransitionStyle  = .crossDissolve
+                        self.present(previewImageVC, animated: true, completion: nil)
                     }
                     }
-                }))
-                firstAlert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
-                self.navigationController?.present(firstAlert, animated: true)
-            } else {
-                let alert = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
-                alert.addAction(UIAlertAction(title: "Take Photo".localized(), style: .default, handler: { action in
-                    self.imageVideoPicker.present(source: .imageCamera)
-                }))
-                alert.addAction(UIAlertAction(title: "Choose Photo".localized(), style: .default, handler: { action in
-                    self.imageVideoPicker.present(source: .imageAlbum)
-                }))
-                alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: { action in
-                    
-                }))
-                self.navigationController?.present(alert, animated: true)
+                    catch {
+                        print("Error reading secure file")
+                    }
+                }
             }
             }
         }
         }
     }
     }
@@ -790,9 +822,7 @@ public class ProfileViewController: UITableViewController, UITextFieldDelegate {
     }
     }
     
     
     @objc func profileTapped() {
     @objc func profileTapped() {
-        if let me = User.getMyPin(), me == data || flag == Flag.me {
-            didTapProfile()
-        }
+        didTapProfile()
     }
     }
     
     
     @objc func friendsTapped() {
     @objc func friendsTapped() {