Răsfoiți Sursa

add resend when failed send message

alqindiirsyam 1 an în urmă
părinte
comite
38ac490e67

+ 1 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings

@@ -320,3 +320,4 @@
 "images" = "gambar";
 "Forward All" = "Teruskan Semua";
 "Delete All" = "Hapus Semua";
+"Resend" = "Kirim Ulang";

+ 2 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift

@@ -142,14 +142,14 @@ public class CoreMessage_TMessageBank {
         return tmessage
     }
     
-    public static func sendMessage(l_pin: String, message_scope_id: String, status: String, message_text: String, credential: String, attachment_flag: String, ex_blog_id: String, message_large_text: String, ex_format: String, image_id: String, audio_id: String, video_id: String, file_id: String, thumb_id: String, reff_id: String, read_receipts: String, chat_id: String, is_call_center: String, call_center_id: String, opposite_pin: String) -> TMessage {
+    public static func sendMessage(message_id: String = "", l_pin: String, message_scope_id: String, status: String, message_text: String, credential: String, attachment_flag: String, ex_blog_id: String, message_large_text: String, ex_format: String, image_id: String, audio_id: String, video_id: String, file_id: String, thumb_id: String, reff_id: String, read_receipts: String, chat_id: String, is_call_center: String, call_center_id: String, opposite_pin: String) -> TMessage {
         let me = UserDefaults.standard.string(forKey: "me")!
         let tmessage = TMessage()
         tmessage.mCode = CoreMessage_TMessageCode.SEND_CHAT
         tmessage.mStatus = me + CoreMessage_TMessageUtil.getTID()
         tmessage.mPIN = me
         tmessage.mL_PIN = l_pin
-        tmessage.mBodies[CoreMessage_TMessageKey.MESSAGE_ID] = me + CoreMessage_TMessageUtil.getTID()
+        tmessage.mBodies[CoreMessage_TMessageKey.MESSAGE_ID] = message_id.isEmpty ? me + CoreMessage_TMessageUtil.getTID() : message_id
         tmessage.mBodies[CoreMessage_TMessageKey.F_PIN] = me
         tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
         tmessage.mBodies[CoreMessage_TMessageKey.SERVER_DATE] = String(Date().currentTimeMillis())

+ 9 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/InquiryThread.swift

@@ -90,6 +90,7 @@ class InquiryThread {
         isWait = wait
         if !isWait {
             connection.signal()
+            semaphore.signal()
         }
     }
     
@@ -113,8 +114,9 @@ class InquiryThread {
                 if self.isWait {
                     //print("CONNECTION INQUIRY.wait")
                     self.connection.wait()
+                } else {
+                    self.process(message: self.getQueue())
                 }
-                self.process(message: self.getQueue())
             }
         }
     }
@@ -131,6 +133,11 @@ class InquiryThread {
     private func mobileInquiry(message: TMessage) {
         Nexilis.saveMessage(message: message)
         //print("save message sendChat")
-        _ = Nexilis.write(message: CoreMessage_TMessageBank.getMobileInquiry(message_id: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)))
+        if !self.isWait {
+            //print("inquiry write", message.toLogString())
+            _ = Nexilis.write(message: CoreMessage_TMessageBank.getMobileInquiry(message_id: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)))
+        } else {
+            queue.append(message)
+        }
     }
 }

+ 33 - 25
appbuilder-ios/NexilisLite/NexilisLite/Source/OutgoingThread.swift

@@ -90,6 +90,7 @@ class OutgoingThread {
         isWait = wait
         if !isWait {
             connection.signal()
+            semaphore.signal()
         }
     }
     
@@ -111,14 +112,19 @@ class OutgoingThread {
                 if self.isWait {
                     //print("CONNECTION.wait")
                     self.connection.wait()
+                } else {
+                    self.process(message: self.getQueue())
                 }
-                self.process(message: self.getQueue())
             }
         }
     }
     
     private func process(message: TMessage) {
         //print("outgoing process", message.toLogString())
+        if self.isWait {
+            queue.append(message)
+            return
+        }
         if message.getCode() == CoreMessage_TMessageCode.SEND_CHAT {
             sendChat(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.DELETE_CTEXT {
@@ -271,32 +277,34 @@ class OutgoingThread {
                 delegate.onUpload(name: fileName, progress: 100)
             }
         } else {
-            let timeRetry = maxRetryUploadTime[message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)]!
-            if timeRetry != 0 {
-                if (timeRetry + Int(maxRetryTime)!) <= Date().currentTimeMillis() {
-                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                        _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
-                            "status" : "0"
-                        ], _where: "message_id = '\(message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))'")
-                        _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
-                            "status" : "0"
-                        ], _where: "message_id = '\(message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))'")
-                        self.delOutgoing(fmdb: fmdb, messageId: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
-                    })
-                    var dataMessage: [AnyHashable : Any] = [:]
-                    dataMessage["message_id"] = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
-                    dataMessage["status"] = "0"
-                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.failedSendMessage), object: nil, userInfo: dataMessage)
-                    maxRetryUpload.removeValue(forKey: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
-                    maxRetryUploadTime.removeValue(forKey: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
-                    if let delegate = Nexilis.shared.messageDelegate {
-                        delegate.onUpload(name: fileName, progress: 100)
+            DispatchQueue.global().asyncAfter(deadline: .now() + 5, execute: { [self] in
+                let timeRetry = maxRetryUploadTime[message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)] ?? 0
+                if timeRetry != 0 {
+                    if (timeRetry + Int(maxRetryTime)!) <= Date().currentTimeMillis() {
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                                "status" : "0"
+                            ], _where: "message_id = '\(message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))'")
+                            _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
+                                "status" : "0"
+                            ], _where: "message_id = '\(message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))'")
+                            self.delOutgoing(fmdb: fmdb, messageId: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
+                        })
+                        var dataMessage: [AnyHashable : Any] = [:]
+                        dataMessage["message_id"] = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+                        dataMessage["status"] = "0"
+                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.failedSendMessage), object: nil, userInfo: dataMessage)
+                        maxRetryUpload.removeValue(forKey: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
+                        maxRetryUploadTime.removeValue(forKey: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID))
+                        if let delegate = Nexilis.shared.messageDelegate {
+                            delegate.onUpload(name: fileName, progress: 100)
+                        }
+                        return
                     }
-                    return
                 }
-            }
-            //print("retry sukses")
-            sendChat(message: message)
+                //print("retry sukses")
+                sendChat(message: message)
+            })
         }
     }
     

+ 111 - 30
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -465,7 +465,7 @@ public class EditorGroup: UIViewController {
     
     private func getData() {
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
-            var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id FROM MESSAGE where chat_id='' AND l_pin='\(dataGroup["group_id"] as! String)' order by server_date asc"
+            var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, is_call_center, call_center_id, opposite_pin FROM MESSAGE where chat_id='' AND l_pin='\(dataGroup["group_id"] as! String)' order by server_date asc"
             if isHistoryCC {
                 query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared FROM MESSAGE where call_center_id='\(complaintId)' order by server_date asc"
             } else if (dataTopic["chat_id"] as! String != "") {
@@ -495,6 +495,9 @@ public class EditorGroup: UIViewController {
                     row["is_stared"] = cursorData.string(forColumnIndex: 17)
                     row["blog_id"] = cursorData.string(forColumnIndex: 18)
                     row["isSelected"] = false
+                    row[TypeDataMessage.is_call_center] = cursorData.string(forColumnIndex: 19)
+                    row[TypeDataMessage.call_center_id] = cursorData.string(forColumnIndex: 20)
+                    row[TypeDataMessage.opposite_pin] = cursorData.string(forColumnIndex: 21)
                     let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
                     let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
                     let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
@@ -1460,6 +1463,9 @@ public class EditorGroup: UIViewController {
         row["lock"] = "0"
         row["is_stared"] = "0"
         row["isSelected"] = false
+        row[TypeDataMessage.is_call_center] = is_call_center
+        row[TypeDataMessage.call_center_id] = call_center_id
+        row[TypeDataMessage.opposite_pin] = opposite_pin
         if !dataDates.contains("Today".localized()){
             dataDates.append("Today".localized())
             tableChatView.insertSections(IndexSet(integer: dataDates.count - 1), with: .fade)
@@ -2434,11 +2440,70 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             }
         })
         
+        let resend = UIAction(title: "Resend".localized(), image: UIImage(systemName: "arrow.clockwise"), handler: {(_) in
+            let messageId = dataMessages[indexPath!.row][TypeDataMessage.message_id] as! String
+            let status = dataMessages[indexPath!.row][TypeDataMessage.status] as! String
+            
+            var idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String ?? "" == messageId })
+            if let idxMessageIdParent = self.groupImages.firstIndex(where: { $0.value.contains(where: { $0.messageId == messageId }) }) {
+                if let idxInImages = self.groupImages[idxMessageIdParent].value.firstIndex(where: { $0.messageId == messageId }) {
+                    self.groupImages[idxMessageIdParent].value[idxInImages].status = "1"
+                    self.groupImages[idxMessageIdParent].value[idxInImages].dataMessage[TypeDataMessage.status] = "1"
+                }
+                idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == self.groupImages[idxMessageIdParent].key })
+            }
+            
+            if (idx != nil) {
+                do {
+                    self.dataMessages[idx!][TypeDataMessage.status] = "1"
+                    self.dataMessages[idx!][TypeDataMessage.progress] = 0.0
+                    let section = self.dataDates.firstIndex(of: self.dataMessages[idx!]["chat_date"] as! String)
+                    let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[idx!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[idx!]["message_id"] as? String })
+                    if row != nil && section != nil  {
+                        self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
+                    }
+                } catch {
+                }
+            }
+            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                    "status" : "1"
+                ], _where: "message_id = '\(messageId)'")
+                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
+                    "status" : "1"
+                ], _where: "message_id = '\(messageId)'")
+            })
+            let message = CoreMessage_TMessageBank.sendMessage(message_id: messageId,
+                                                               l_pin: dataMessages[indexPath!.row][TypeDataMessage.l_pin] as! String,
+                                                               message_scope_id: dataMessages[indexPath!.row][TypeDataMessage.l_pin] as! String,
+                                                               status: "1",
+                                                               message_text: dataMessages[indexPath!.row][TypeDataMessage.message_text] as! String,
+                                                               credential: dataMessages[indexPath!.row][TypeDataMessage.credential] as! String,
+                                                               attachment_flag: dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as! String,
+                                                               ex_blog_id: dataMessages[indexPath!.row][TypeDataMessage.blog_id] as! String,
+                                                               message_large_text: "",
+                                                               ex_format: "",
+                                                               image_id: dataMessages[indexPath!.row][TypeDataMessage.image_id] as! String,
+                                                               audio_id: dataMessages[indexPath!.row][TypeDataMessage.audio_id] as! String,
+                                                               video_id: dataMessages[indexPath!.row][TypeDataMessage.video_id] as! String,
+                                                               file_id: dataMessages[indexPath!.row][TypeDataMessage.file_id] as! String,
+                                                               thumb_id: dataMessages[indexPath!.row][TypeDataMessage.thumb_id] as! String,
+                                                               reff_id: dataMessages[indexPath!.row][TypeDataMessage.reff_id] as! String,
+                                                               read_receipts: dataMessages[indexPath!.row][TypeDataMessage.read_receipts] as! String,
+                                                               chat_id: dataMessages[indexPath!.row][TypeDataMessage.chat_id] as! String,
+                                                               is_call_center: dataMessages[indexPath!.row][TypeDataMessage.is_call_center] as! String,
+                                                               call_center_id: dataMessages[indexPath!.row][TypeDataMessage.call_center_id] as! String,
+                                                               opposite_pin: dataMessages[indexPath!.row][TypeDataMessage.opposite_pin] as! String)
+            Nexilis.addQueueMessage(message: message)
+        })
+        
         var children: [UIMenuElement] = [star, reply, forward, copy, delete]
 //        let copyOption = self.copyOption(indexPath: indexPath!)
         let idMe = UserDefaults.standard.string(forKey: "me") as String?
         
-        if (dataMessages[indexPath!.row]["lock"] != nil && dataMessages[indexPath!.row]["lock"] as! String == "1") {
+        if dataMessages[indexPath!.row]["status"] as! String == "0" {
+            children = [resend, delete]
+        } else if (dataMessages[indexPath!.row]["lock"] != nil && dataMessages[indexPath!.row]["lock"] as! String == "1") {
             children = [delete]
         } else if (groupImages[dataMessages[indexPath!.row]["message_id"] as! String] != nil) {
             forward.title = "Forward All".localized()
@@ -2736,7 +2801,8 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
             let dataFilterFpin = dataMessages.filter({ $0["f_pin"] as? String != idMe})
             let dataFilterLock = dataMessages.filter({ $0["lock"] as? String == "1"})
             let statusDataRead = dataMessages.filter({ Int($0["status"] as! String)! >= 4})
-            if dataFilterFpin.count == 0 && dataFilterLock.count == 0 && statusDataRead.count == 0 {
+            let statusFailed = dataMessages.filter({ Int($0["status"] as! String)! == 0})
+            if dataFilterFpin.count == 0 && dataFilterLock.count == 0 && statusDataRead.count == 0 && statusFailed.count == 0 {
                 if let action = self.actionDelete(for: "everyone", title: "Delete".localized() + " \(countSelected) " + "For Everyone".localized(), dataMessages: dataMessages) {
                     alertController.addAction(action)
                 }
@@ -2863,33 +2929,40 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
                         }
                         self.groupImages.removeValue(forKey: groupingImages[0].messageId)
                     } else {
-                        if let groupingImages = groupImages[dataMessages[i]["message_id"] as! String] {
-                            for i in 0..<groupingImages.count {
-                                self.deleteMessage(l_pin: dataGroup["group_id"] as! String, message_id: groupingImages[i].messageId, scope: "4", type: "2", chat: dataTopic["chat_id"] as! String)
-                                let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[i].messageId})
-                                if idx != nil {
-                                    self.dataMessages[idx!]["lock"] = "1"
-                                    self.dataMessages[idx!]["attachment_flag"] = "0"
-                                    self.dataMessages[idx!]["reff_id"] = ""
-                                }
-                            }
-                            if let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[0].messageId}) {
-                                var dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
-                                dataMessageInGrouping.remove(at: 0)
-                                self.dataMessages.insert(contentsOf: dataMessageInGrouping, at: idx+1)
-                                self.groupImages.removeValue(forKey: groupingImages[0].messageId)
-                            }
+                        if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                            let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                            imageView.tintColor = .white
+                            let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                            banner.show()
                         } else {
-                            self.deleteMessage(l_pin: dataGroup["group_id"] as! String, message_id: dataMessages[i]["message_id"] as! String, scope: "4", type: "1", chat: dataTopic["chat_id"] as! String)
-                            let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == dataMessages[i]["message_id"] as? String})
-                            if idx != nil {
-                                self.dataMessages.remove(at: idx!)
-                                if (idx == self.dataMessages.count - 1) {
-                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                            if let groupingImages = groupImages[dataMessages[i]["message_id"] as! String] {
+                                for i in 0..<groupingImages.count {
+                                    self.deleteMessage(l_pin: dataGroup["group_id"] as! String, message_id: groupingImages[i].messageId, scope: "4", type: "2", chat: dataTopic["chat_id"] as! String)
+                                    let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[i].messageId})
+                                    if idx != nil {
+                                        self.dataMessages[idx!]["lock"] = "1"
+                                        self.dataMessages[idx!]["attachment_flag"] = "0"
+                                        self.dataMessages[idx!]["reff_id"] = ""
+                                    }
                                 }
-                                for i in 0..<dataDates.count {
-                                    if self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[i] }).count == 0 {
-                                        dataDates.remove(at: i)
+                                if let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[0].messageId}) {
+                                    var dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
+                                    dataMessageInGrouping.remove(at: 0)
+                                    self.dataMessages.insert(contentsOf: dataMessageInGrouping, at: idx+1)
+                                    self.groupImages.removeValue(forKey: groupingImages[0].messageId)
+                                }
+                            } else {
+                                self.deleteMessage(l_pin: dataGroup["group_id"] as! String, message_id: dataMessages[i]["message_id"] as! String, scope: "4", type: "1", chat: dataTopic["chat_id"] as! String)
+                                let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == dataMessages[i]["message_id"] as? String})
+                                if idx != nil {
+                                    self.dataMessages.remove(at: idx!)
+                                    if (idx == self.dataMessages.count - 1) {
+                                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                                    }
+                                    for i in 0..<dataDates.count {
+                                        if self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[i] }).count == 0 {
+                                            dataDates.remove(at: i)
+                                        }
                                     }
                                 }
                             }
@@ -3340,7 +3413,11 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                 statusMessage.widthAnchor.constraint(equalToConstant: 15).isActive = true
                 statusMessage.heightAnchor.constraint(equalToConstant: 15).isActive = true
                 let status = getRealStatus(messageId: dataMessages[indexPath.row]["message_id"] as! String)
-                if (status == "1" || status == "2" ) {
+                if status == "0" {
+                    statusMessage.image = UIImage(systemName: "xmark.circle")!.withTintColor(UIColor.red, renderingMode: .alwaysOriginal)
+                } else if status == "1" {
+                    statusMessage.image = UIImage(systemName: "clock.arrow.circlepath")!.withTintColor(UIColor.lightGray, renderingMode: .alwaysOriginal)
+                } else if status == "2" {
                     statusMessage.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
                 } else if (status == "3") {
                     statusMessage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
@@ -3740,7 +3817,11 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         let statusInImage = UIImageView()
                         containerTimeStatus.addSubview(statusInImage)
                         statusInImage.anchor(right: containerTimeStatus.rightAnchor, centerY: containerTimeStatus.centerYAnchor, width: 15, height: 15)
-                        if listImages[i].status == "1" || listImages[i].status == "2"  {
+                        if listImages[i].status == "0" {
+                            statusMessage.image = UIImage(systemName: "xmark.circle")!.withTintColor(UIColor.red, renderingMode: .alwaysOriginal)
+                        } else if listImages[i].status == "1" {
+                            statusMessage.image = UIImage(systemName: "clock.arrow.circlepath")!.withTintColor(UIColor.lightGray, renderingMode: .alwaysOriginal)
+                        } else if listImages[i].status == "2"  {
                             statusInImage.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)
                         } else if listImages[i].status == "3" {
                             statusInImage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)

+ 126 - 22
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -804,7 +804,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     private func addDataMessage() {
         multipleOffsetUp += 1
         let queryCount = "SELECT COUNT(*) FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0"
-        let query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20*\(multipleOffsetUp-1) ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
+        let query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20*\(multipleOffsetUp-1) ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
                 var tempData: [[String: Any?]] = []
@@ -830,6 +830,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                     row["is_stared"] = cursorData.string(forColumnIndex: 17)
                     row["blog_id"] = cursorData.string(forColumnIndex: 18)
                     row["credential"] = cursorData.string(forColumnIndex: 19)
+                    row[TypeDataMessage.is_call_center] = cursorData.string(forColumnIndex: 20)
+                    row[TypeDataMessage.call_center_id] = cursorData.string(forColumnIndex: 21)
+                    row[TypeDataMessage.opposite_pin] = cursorData.string(forColumnIndex: 22)
                     if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS WHERE message_id='\(row["message_id"] as! String)'") {
                         while cursorStatus.next() {
                             row["status"] = cursorStatus.string(forColumnIndex: 0)
@@ -927,7 +930,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     private func getData() {
 //        let queryCount = "SELECT COUNT(*) FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0"
 //        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20 ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
-        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc"
+        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc"
         if isContactCenter {
             if complaintId.isEmpty {
                 query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND message_scope_id = '5' AND broadcast_flag = 0 AND is_call_center = 1 order by server_date asc"
@@ -985,6 +988,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                     row["is_stared"] = cursorData.string(forColumnIndex: 17)
                     row["blog_id"] = cursorData.string(forColumnIndex: 18)
                     row["credential"] = cursorData.string(forColumnIndex: 19)
+                    row[TypeDataMessage.is_call_center] = cursorData.string(forColumnIndex: 20)
+                    row[TypeDataMessage.call_center_id] = cursorData.string(forColumnIndex: 21)
+                    row[TypeDataMessage.opposite_pin] = cursorData.string(forColumnIndex: 22)
                     if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS WHERE message_id='\(row["message_id"] as! String)'") {
                         while cursorStatus.next() {
                             row["status"] = cursorStatus.string(forColumnIndex: 0)
@@ -2343,6 +2349,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         row["lock"] = "0"
         row["is_stared"] = "0"
         row["isSelected"] = false
+        row[TypeDataMessage.is_call_center] = is_call_center
+        row[TypeDataMessage.call_center_id] = call_center_id
+        row[TypeDataMessage.opposite_pin] = opposite_pin
         if !dataDates.contains("Today".localized()) {
             dataDates.append("Today".localized())
             tableChatView.insertSections(IndexSet(integer: dataDates.count - 1), with: .none)
@@ -3577,10 +3586,69 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             }
         })
         
+        let resend = UIAction(title: "Resend".localized(), image: UIImage(systemName: "arrow.clockwise"), handler: {(_) in
+            let messageId = dataMessages[indexPath!.row][TypeDataMessage.message_id] as! String
+            let status = dataMessages[indexPath!.row][TypeDataMessage.status] as! String
+            
+            var idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String ?? "" == messageId })
+            if let idxMessageIdParent = self.groupImages.firstIndex(where: { $0.value.contains(where: { $0.messageId == messageId }) }) {
+                if let idxInImages = self.groupImages[idxMessageIdParent].value.firstIndex(where: { $0.messageId == messageId }) {
+                    self.groupImages[idxMessageIdParent].value[idxInImages].status = "1"
+                    self.groupImages[idxMessageIdParent].value[idxInImages].dataMessage[TypeDataMessage.status] = "1"
+                }
+                idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == self.groupImages[idxMessageIdParent].key })
+            }
+            
+            if (idx != nil) {
+                do {
+                    self.dataMessages[idx!][TypeDataMessage.status] = "1"
+                    self.dataMessages[idx!][TypeDataMessage.progress] = 0.0
+                    let section = self.dataDates.firstIndex(of: self.dataMessages[idx!]["chat_date"] as! String)
+                    let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[idx!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[idx!]["message_id"] as? String })
+                    if row != nil && section != nil  {
+                        self.tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
+                    }
+                } catch {
+                }
+            }
+            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
+                    "status" : "1"
+                ], _where: "message_id = '\(messageId)'")
+                _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
+                    "status" : "1"
+                ], _where: "message_id = '\(messageId)'")
+            })
+            let message = CoreMessage_TMessageBank.sendMessage(message_id: messageId,
+                                                               l_pin: dataMessages[indexPath!.row][TypeDataMessage.l_pin] as! String,
+                                                               message_scope_id: dataMessages[indexPath!.row][TypeDataMessage.l_pin] as! String,
+                                                               status: "1",
+                                                               message_text: dataMessages[indexPath!.row][TypeDataMessage.message_text] as! String,
+                                                               credential: dataMessages[indexPath!.row][TypeDataMessage.credential] as! String,
+                                                               attachment_flag: dataMessages[indexPath!.row][TypeDataMessage.attachment_flag] as! String,
+                                                               ex_blog_id: dataMessages[indexPath!.row][TypeDataMessage.blog_id] as! String,
+                                                               message_large_text: "",
+                                                               ex_format: "",
+                                                               image_id: dataMessages[indexPath!.row][TypeDataMessage.image_id] as! String,
+                                                               audio_id: dataMessages[indexPath!.row][TypeDataMessage.audio_id] as! String,
+                                                               video_id: dataMessages[indexPath!.row][TypeDataMessage.video_id] as! String,
+                                                               file_id: dataMessages[indexPath!.row][TypeDataMessage.file_id] as! String,
+                                                               thumb_id: dataMessages[indexPath!.row][TypeDataMessage.thumb_id] as! String,
+                                                               reff_id: dataMessages[indexPath!.row][TypeDataMessage.reff_id] as! String,
+                                                               read_receipts: dataMessages[indexPath!.row][TypeDataMessage.read_receipts] as! String,
+                                                               chat_id: dataMessages[indexPath!.row][TypeDataMessage.chat_id] as! String,
+                                                               is_call_center: dataMessages[indexPath!.row][TypeDataMessage.is_call_center] as! String,
+                                                               call_center_id: dataMessages[indexPath!.row][TypeDataMessage.call_center_id] as! String,
+                                                               opposite_pin: dataMessages[indexPath!.row][TypeDataMessage.opposite_pin] as! String)
+            Nexilis.addQueueMessage(message: message)
+        })
+        
         var children: [UIMenuElement] = [star, reply, forward, copy, delete]
 //        let copyOption = self.copyOption(indexPath: indexPath!)
         let idMe = UserDefaults.standard.string(forKey: "me") as String?
-        if isContactCenter {
+        if dataMessages[indexPath!.row]["status"] as! String == "0" {
+            children = [resend, delete]
+        } else if isContactCenter {
             if (groupImages[dataMessages[indexPath!.row]["message_id"] as! String] != nil) {
                 children = [reply, copy]
             }
@@ -3901,7 +3969,8 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             let dataFilterFpin = dataMessages.filter({ $0["l_pin"] as? String == idMe})
             let dataFilterLock = dataMessages.filter({ $0["lock"] as? String == "1" || $0["lock"] as? String == "2" })
             let statusDataRead = dataMessages.filter({ Int($0["status"] as! String)! >= 4})
-            if dataFilterFpin.count == 0 && dataFilterLock.count == 0 && statusDataRead.count == 0 {
+            let statusFailed = dataMessages.filter({ Int($0["status"] as! String)! == 0})
+            if dataFilterFpin.count == 0 && dataFilterLock.count == 0 && statusDataRead.count == 0 && statusFailed.count == 0 {
                 if let action = self.actionDelete(for: "everyone", title: "Delete".localized() + " \(countSelected) " + "For Everyone".localized(), dataMessages: dataMessages) {
                     alertController.addAction(action)
                 }
@@ -4056,30 +4125,37 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
                         }
                     }
                 } else {
-                    if let groupingImages = groupImages[dataMessages[i]["message_id"] as! String] {
-                        for i in 0..<groupingImages.count {
-                            self.deleteMessage(l_pin: groupingImages[i].lPin, message_id: groupingImages[i].messageId, scope: "3", type: "2", chat: "")
-                            let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[i].messageId})
+                    if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                        banner.show()
+                    } else {
+                        if let groupingImages = groupImages[dataMessages[i]["message_id"] as! String] {
+                            for i in 0..<groupingImages.count {
+                                self.deleteMessage(l_pin: groupingImages[i].lPin, message_id: groupingImages[i].messageId, scope: "3", type: "2", chat: "")
+                                let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[i].messageId})
+                                if idx != nil {
+                                    self.dataMessages[idx!]["lock"] = "1"
+                                    self.dataMessages[idx!]["attachment_flag"] = "0"
+                                    self.dataMessages[idx!]["reff_id"] = ""
+                                }
+                            }
+                            if let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[0].messageId}) {
+                                var dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
+                                dataMessageInGrouping.remove(at: 0)
+                                self.dataMessages.insert(contentsOf: dataMessageInGrouping, at: idx+1)
+                                self.groupImages.removeValue(forKey: groupingImages[0].messageId)
+                            }
+                        } else {
+                            self.deleteMessage(l_pin: dataMessages[i]["l_pin"] as! String, message_id: dataMessages[i]["message_id"] as! String, scope: "3", type: "2", chat: "")
+                            let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == dataMessages[i]["message_id"] as? String})
                             if idx != nil {
                                 self.dataMessages[idx!]["lock"] = "1"
                                 self.dataMessages[idx!]["attachment_flag"] = "0"
                                 self.dataMessages[idx!]["reff_id"] = ""
                             }
                         }
-                        if let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == groupingImages[0].messageId}) {
-                            var dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
-                            dataMessageInGrouping.remove(at: 0)
-                            self.dataMessages.insert(contentsOf: dataMessageInGrouping, at: idx+1)
-                            self.groupImages.removeValue(forKey: groupingImages[0].messageId)
-                        }
-                    } else {
-                        self.deleteMessage(l_pin: dataMessages[i]["l_pin"] as! String, message_id: dataMessages[i]["message_id"] as! String, scope: "3", type: "2", chat: "")
-                        let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == dataMessages[i]["message_id"] as? String})
-                        if idx != nil {
-                            self.dataMessages[idx!]["lock"] = "1"
-                            self.dataMessages[idx!]["attachment_flag"] = "0"
-                            self.dataMessages[idx!]["reff_id"] = ""
-                        }
                     }
                 }
                 if self.listTimerCredential[dataMessages[i]["message_id"] as! String] != nil {
@@ -6630,3 +6706,31 @@ public class ImageGrouping {
         self.dataTopic = dataTopic
     }
 }
+
+public class TypeDataMessage {
+    public static let message_id = "message_id"
+    public static let f_pin = "f_pin"
+    public static let l_pin = "l_pin"
+    public static let message_scope_id = "message_scope_id"
+    public static let server_date = "server_date"
+    public static let status = "status"
+    public static let message_text = "message_text"
+    public static let audio_id = "audio_id"
+    public static let video_id = "video_id"
+    public static let image_id = "image_id"
+    public static let thumb_id = "thumb_id"
+    public static let read_receipts = "read_receipts"
+    public static let chat_id = "chat_id"
+    public static let file_id = "file_id"
+    public static let attachment_flag = "attachment_flag"
+    public static let reff_id = "reff_id"
+    public static let lock = "lock"
+    public static let is_stared = "is_stared"
+    public static let blog_id = "blog_id"
+    public static let credential = "credential"
+    public static let progress = "progress"
+    public static let chat_date = "chat_date"
+    public static let is_call_center = "is_call_center"
+    public static let call_center_id = "call_center_id"
+    public static let opposite_pin = "opposite_pin"
+}