Quellcode durchsuchen

update fix bugs

alqindiirsyam vor 2 Jahren
Ursprung
Commit
e1097f97b4

+ 4 - 0
appbuilder-ios/AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -1006,6 +1006,10 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
             ])
             messageView.textColor = .gray
+            if data.messageText.contains("■") {
+                data.messageText = data.messageText.components(separatedBy: "■")[0]
+                data.messageText = data.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
+            }
             let text = Utils.previewMessageText(chat: data)
             let idMe = UserDefaults.standard.string(forKey: "me") as String?
             if let attributeText = text as? NSMutableAttributedString {

+ 47 - 46
appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift

@@ -58,57 +58,58 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
 
     override func viewDidLoad() {
         super.viewDidLoad()
-        if let response = Nexilis.writeSync(message: getPrefs(key: ""), timeout: 5000) {
-            if response.mBodies[CoreMessage_TMessageKey.ERRCOD] == "00" {
-                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?]] {
-                    UserDefaults.standard.removeObject(forKey: "app_builder_url_first_tab")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_url_third_tab")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_custom_tab")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_url_base")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_url_qms")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_icon_dock")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_icon_ss")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_background")
-                    UserDefaults.standard.removeObject(forKey: "app_builder_compressor")
-                    for j in json {
-                        if let firstTab = j["app_builder_url_first_tab"] as? String {
-                            PrefsUtil.setURLFirstTab(value: firstTab)
-                            ViewController.sURL = firstTab
-                        }
-                        if let thirdTab = j["app_builder_url_third_tab"] as? String {
-                            PrefsUtil.setURLThirdTab(value: thirdTab)
-                            ViewController.tab3 = thirdTab
-                        }
-                        if let customTab = j["app_builder_custom_tab"] as? String {
-                            PrefsUtil.setCustomTab(cust: customTab)
-                        }
-                        if let urlBase = j["app_builder_url_base"] as? String {
-                            PrefsUtil.setURLBase(value: urlBase)
-                        }
-                        if let urlQMS = j["app_builder_url_qms"] as? String {
-                            PrefsUtil.setURLQMS(value: urlQMS)
-                        }
-                        if let iconDock = j["app_builder_icon_dock"] as? String {
-                            PrefsUtil.setIconDock(value: iconDock)
-                        }
-                        if let iconSS = j["app_builder_icon_ss"] as? String {
-                            PrefsUtil.setIconSS(value: iconSS)
-                        }
-                        if let background = j["app_builder_background"] as? String {
-                            PrefsUtil.setBackground(value: background)
-                        }
-                        if let url_privacy_policy = j["app_builder_url_privacy_policy"] as? String {
-                            PrefsUtil.setURLPrivacyPolicy(value: url_privacy_policy)
-                        }
-                        if let enable_privacy_policy = j["app_builder_enable_privacy_policy"] as? String {
-                            PrefsUtil.setEnablePrivacyPolicy(value: enable_privacy_policy == "1" ? true : false)
+        DispatchQueue.main.async { [self] in
+            if let response = Nexilis.writeSync(message: getPrefs(key: ""), timeout: 5000) {
+                if response.mBodies[CoreMessage_TMessageKey.ERRCOD] == "00" {
+                    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?]] {
+                        UserDefaults.standard.removeObject(forKey: "app_builder_url_first_tab")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_url_third_tab")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_custom_tab")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_url_base")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_url_qms")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_icon_dock")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_icon_ss")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_background")
+                        UserDefaults.standard.removeObject(forKey: "app_builder_compressor")
+                        for j in json {
+                            if let firstTab = j["app_builder_url_first_tab"] as? String {
+                                PrefsUtil.setURLFirstTab(value: firstTab)
+                                ViewController.sURL = firstTab
+                            }
+                            if let thirdTab = j["app_builder_url_third_tab"] as? String {
+                                PrefsUtil.setURLThirdTab(value: thirdTab)
+                                ViewController.tab3 = thirdTab
+                            }
+                            if let customTab = j["app_builder_custom_tab"] as? String {
+                                PrefsUtil.setCustomTab(cust: customTab)
+                            }
+                            if let urlBase = j["app_builder_url_base"] as? String {
+                                PrefsUtil.setURLBase(value: urlBase)
+                            }
+                            if let urlQMS = j["app_builder_url_qms"] as? String {
+                                PrefsUtil.setURLQMS(value: urlQMS)
+                            }
+                            if let iconDock = j["app_builder_icon_dock"] as? String {
+                                PrefsUtil.setIconDock(value: iconDock)
+                            }
+                            if let iconSS = j["app_builder_icon_ss"] as? String {
+                                PrefsUtil.setIconSS(value: iconSS)
+                            }
+                            if let background = j["app_builder_background"] as? String {
+                                PrefsUtil.setBackground(value: background)
+                            }
+                            if let url_privacy_policy = j["app_builder_url_privacy_policy"] as? String {
+                                PrefsUtil.setURLPrivacyPolicy(value: url_privacy_policy)
+                            }
+                            if let enable_privacy_policy = j["app_builder_enable_privacy_policy"] as? String {
+                                PrefsUtil.setEnablePrivacyPolicy(value: enable_privacy_policy == "1" ? true : false)
+                            }
                         }
                     }
                 }
             }
         }
-        
         let topBorder = CALayer()
         topBorder.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColor
         topBorder.frame = CGRect(x: 0, y: 0, width: tabBar.frame.size.width, height: 1)

+ 67 - 65
appbuilder-ios/DigiXLite/DigiXLite/Source/DigiX.swift

@@ -146,81 +146,83 @@ public class DigiX: NSObject {
             DigiX.dispatch = nil
             
 //            DigiX.initiateAudio()
-            if(!id.isEmpty && (UserDefaults.standard.string(forKey: "me") == nil)){
-                if let response = DigiX.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000){
-                    id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
-                    let enable_signup = (response.getBody(key: CoreMessage_TMessageKey.IS_ENABLED_ANONYMOUS, default_value: "0")) == "1"
-                    Utils.setForceAnonymous(value: enable_signup)
-                    if(!id.isEmpty) {
-                        DigiX.changeUser(f_pin: id)
-                        UserDefaults.standard.setValue(id, forKey: "me")
+            DispatchQueue.main.async {
+                if(!id.isEmpty && (UserDefaults.standard.string(forKey: "me") == nil)){
+                    if let response = DigiX.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000){
+                        id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
+                        let enable_signup = (response.getBody(key: CoreMessage_TMessageKey.IS_ENABLED_ANONYMOUS, default_value: "0")) == "1"
+                        Utils.setForceAnonymous(value: enable_signup)
+                        if(!id.isEmpty) {
+                            DigiX.changeUser(f_pin: id)
+                            UserDefaults.standard.setValue(id, forKey: "me")
+                        }
                     }
                 }
-            }
 
-            if UserDefaults.standard.string(forKey: "apiKey") == nil {
-                UserDefaults.standard.setValue(apiKey, forKey: "apiKey")
-            }
-            
-            if let me = UserDefaults.standard.string(forKey: "me") {
-                if Utils.getForceAnonymous() || (!Utils.getForceAnonymous() && Utils.getSetProfile()) {
-                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                        if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT * FROM BUDDY where f_pin = '\(me)' ") {
-                            if !cursorData.next() {
-                                _ = DigiX.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: me))
+                if UserDefaults.standard.string(forKey: "apiKey") == nil {
+                    UserDefaults.standard.setValue(apiKey, forKey: "apiKey")
+                }
+                
+                if let me = UserDefaults.standard.string(forKey: "me") {
+                    if Utils.getForceAnonymous() || (!Utils.getForceAnonymous() && Utils.getSetProfile()) {
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT * FROM BUDDY where f_pin = '\(me)' ") {
+                                if !cursorData.next() {
+                                    _ = DigiX.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: me))
+                                }
+                                cursorData.close()
                             }
-                            cursorData.close()
-                        }
-                    })
-                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                        if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT image_id FROM GROUPZ where group_type = 1 AND official = 1"), cursorData.next() {
-                            do {
-                                let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
-                                let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
-                                if !FileManager().fileExists(atPath: file.path) {
-                                    Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
+                        })
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT image_id FROM GROUPZ where group_type = 1 AND official = 1"), cursorData.next() {
+                                do {
+                                    let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
+                                    let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
+                                    if !FileManager().fileExists(atPath: file.path) {
+                                        Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
+                                    }
+                                } catch {}
+                                cursorData.close()
+                            }
+                        })
+                    }
+                    getServiceBank()
+                    getPullWorkingArea()
+                    getPullGroupNoMember()
+                    delegate.onSuccess(userId: me)
+                    getPullDefaultCC()
+                    if showButton {
+                        DispatchQueue.main.async {
+                            var viewController = UIApplication.shared.windows.first?.rootViewController
+                            var notNull = false
+                            while !notNull {
+                                viewController = UIApplication.shared.windows.first?.rootViewController
+                                if viewController != nil {
+                                    notNull = true
                                 }
-                            } catch {}
-                            cursorData.close()
-                        }
-                    })
-                }
-                getServiceBank()
-                getPullWorkingArea()
-                getPullGroupNoMember()
-                delegate.onSuccess(userId: me)
-                getPullDefaultCC()
-                if showButton {
-                    DispatchQueue.main.async {
-                        var viewController = UIApplication.shared.windows.first?.rootViewController
-                        var notNull = false
-                        while !notNull {
-                            viewController = UIApplication.shared.windows.first?.rootViewController
-                            if viewController != nil {
-                                notNull = true
                             }
-                        }
-                        let fb = FloatingButton()
-                        if fromMAB {
-                            var vc = viewController
-                            if viewController is UINavigationController {
-                                vc = (viewController as! UINavigationController).rootViewController
+                            let fb = FloatingButton()
+                            if fromMAB {
+                                var vc = viewController
+                                if viewController is UINavigationController {
+                                    vc = (viewController as! UINavigationController).rootViewController
+                                }
+                                vc?.view.addSubview(fb)
+                                fb.mySettingDelegate = vc as? any SettingMABDelegate
+                            } else {
+                                viewController?.view.addSubview(fb)
                             }
-                            vc?.view.addSubview(fb)
-                            fb.mySettingDelegate = vc as? any SettingMABDelegate
-                        } else {
-                            viewController?.view.addSubview(fb)
                         }
                     }
                 }
-            }
-            DigiX.destroyAll()
-            OutgoingThread.default.run()
-            
-            InquiryThread.default.run()
-            
-            if UIFont.systemFont(ofSize: 12).familyName == ".AppleSystemUIFont" {
-                UIFont.libOverrideInitialize()
+                DigiX.destroyAll()
+                OutgoingThread.default.run()
+                
+                InquiryThread.default.run()
+                
+                if UIFont.systemFont(ofSize: 12).familyName == ".AppleSystemUIFont" {
+                    UIFont.libOverrideInitialize()
+                }
             }
             //print(("MANIA \(UIFont.systemFont(ofSize: 12)) <> \(UIFont.italicSystemFont(ofSize: 12)) <> \(UIFont.boldSystemFont(ofSize: 12))")
         }

+ 23 - 11
appbuilder-ios/DigiXLite/DigiXLite/Source/Extension.swift

@@ -646,7 +646,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeBold.count {
                 if lastFirstRange == -1 {
-                    if (rangeBold[i].startIndex == 0 || checkCharBefore(char: textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeBold[i].endIndex + 1, to: rangeBold[i].endIndex + 1)
+                    if (rangeBold[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeBold[i].startIndex
                         continueCheckingBold = true
                     } else {
@@ -688,7 +690,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeItalic.count {
                 if lastFirstRange == -1 {
-                    if (rangeItalic[i].startIndex == 0 || checkCharBefore(char: textAfterbold.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1)
+                    if (rangeItalic[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeItalic[i].startIndex
                         continueCheckingItalic = true
                     } else {
@@ -698,8 +702,8 @@ extension String {
                 if !continueCheckingItalic {
                     continue
                 }
-                if rangeItalic[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1))[0]
+                if rangeItalic[i].endIndex != (textAfterbold.count-1) {
+                    let char: Character = Array(textAfterbold.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -707,7 +711,7 @@ extension String {
                 let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveItalicSign)).countEmojiCharacter()
                 let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveItalicSign), to: rangeItalic[i].endIndex - (2*countRemoveItalicSign)).countEmojiCharacter()
                 totalEmoji = countEmoji + countEmojiBefore
-                finalText.addAttribute(.font, value: font.italic, range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, length: (rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange))
+                finalText.addAttribute(.font, value: UIFont.italicSystemFont(ofSize: 12), range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, length: (rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange))
                 if !isEditing{
                     finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveItalicSign), length: 1))
                     finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: rangeItalic[i].endIndex + totalEmoji - (2*countRemoveItalicSign) - 1, length: 1))
@@ -730,7 +734,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeUnderline.count {
                 if lastFirstRange == -1 {
-                    if (rangeUnderline[i].startIndex == 0 || checkCharBefore(char: textAfterItalic.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1)
+                    if (rangeUnderline[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeUnderline[i].startIndex
                         continueCheckingUnderline = true
                     } else {
@@ -740,8 +746,8 @@ extension String {
                 if !continueCheckingUnderline {
                     continue
                 }
-                if rangeUnderline[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1))[0]
+                if rangeUnderline[i].endIndex != (textAfterItalic.count-1) {
+                    let char: Character = Array(textAfterItalic.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -772,7 +778,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeStrikethrough.count {
                 if lastFirstRange == -1 {
-                    if (rangeStrikethrough[i].startIndex == 0 || checkCharBefore(char: textAfterUnderline.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1)
+                    if (rangeStrikethrough[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeStrikethrough[i].startIndex
                         continueCheckingStrikethrough = true
                     } else {
@@ -782,8 +790,8 @@ extension String {
                 if !continueCheckingStrikethrough {
                     continue
                 }
-                if rangeStrikethrough[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1))[0]
+                if rangeStrikethrough[i].endIndex != (textAfterUnderline.count-1) {
+                    let char: Character = Array(textAfterUnderline.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -862,6 +870,10 @@ extension String {
         return char == " " || char == "\n"
     }
     
+    func checkCharRich(char: String) -> Bool {
+        return char == "*" || char == "_" || char == "^" || char == "~"
+    }
+    
     func checkStartWithLink() -> Bool {
         return self.starts(with: "https://") || self.starts(with: "http://") || self.starts(with: "www.")
         //|| self.starts(with: "*https://") || self.starts(with: "*http://") || self.starts(with: "*www.") || self.starts(with: "_https://") || self.starts(with: "_http://") || self.starts(with: "_www.") || self.starts(with: "^https://") || self.starts(with: "^http://") || self.starts(with: "^www.") || self.starts(with: "~https://") || self.starts(with: "~http://") || self.starts(with: "~www.")

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/Model/Chat.swift

@@ -13,7 +13,7 @@ public class Chat: Model {
     public let pin: String
     public let messageId: String
     public let counter: String
-    public let messageText: String
+    public var messageText: String
     public let serverDate: String
     public let image: String
     public let video: String

+ 27 - 21
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorGroup.swift

@@ -88,7 +88,7 @@ public class EditorGroup: UIViewController {
     var timerLongPressLink: Timer?
     var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var listViewOnSection: [UIView] = []
     var fakeProgMultip = 0
@@ -2197,6 +2197,12 @@ extension EditorGroup: UITextViewDelegate {
 }
 
 extension EditorGroup: UIContextMenuInteractionDelegate {
+    public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
+        if showMenuContext {
+            showMenuContext = false
+            interaction.view!.removeInteraction(interaction)
+        }
+    }
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
         if textFieldSend.isFirstResponder {
             textFieldSend.resignFirstResponder()
@@ -3517,18 +3523,19 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
             let listTextEnter = textChat!.split(separator: "\n")
             for j in 0...listTextEnter.count - 1 {
                 let listText = listTextEnter[j].split(separator: " ")
-                for i in 0...listText.count - 1 {
-                    if listText[i].lowercased().checkStartWithLink() {
-                        let rangeTapLink = (textChat! as NSString).range(of: String(listText[i]))
-                        // Add tap gesture recognizer to the range of text
-                        let attributedString = textChat!.richText(group_id: self.dataGroup["group_id"] as! String)
-                        attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
-                        messageText.attributedText = attributedString
-                        if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !isHistoryCC && !removed {
-                            messageText.isUserInteractionEnabled = true
-                            let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressLink(_:)))
-                            longPress.minimumPressDuration = 0.1
-                            containerMessage.addGestureRecognizer(longPress)
+                if listText.count > 0 {
+                    for i in 0...listText.count - 1 {
+                        if listText[i].lowercased().checkStartWithLink() {
+                            let attributedString = textChat!.richText(group_id: self.dataGroup["group_id"] as! String)
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
+                            attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
+                            messageText.attributedText = attributedString
+                            if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !isHistoryCC && !removed {
+                                messageText.isUserInteractionEnabled = true
+                                let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressLink(_:)))
+                                longPress.minimumPressDuration = 0.1
+                                containerMessage.addGestureRecognizer(longPress)
+                            }
                         }
                     }
                 }
@@ -3923,7 +3930,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -3950,7 +3957,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -4606,7 +4613,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -4623,9 +4630,9 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -4634,15 +4641,12 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
-                        self.timerCheckLink?.invalidate()
                     })
                 }
             } else {
@@ -4687,12 +4691,14 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     

+ 34 - 23
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorPersonal.swift

@@ -98,7 +98,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var timerLongPressLink: Timer?
     var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var listViewOnSection: [UIView] = []
     var fromVCAC = false
@@ -3392,8 +3392,8 @@ extension EditorPersonal: UITextViewDelegate {
 //EUC
 extension EditorPersonal: UIContextMenuInteractionDelegate {
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
-        if isLinkCopied {
-            isLinkCopied = false
+        if showMenuContext {
+            showMenuContext = false
             interaction.view!.removeInteraction(interaction)
         }
     }
@@ -4898,18 +4898,19 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
             let listTextEnter = textChat.split(separator: "\n")
             for j in 0...listTextEnter.count - 1 {
                 let listText = listTextEnter[j].split(separator: " ")
-                for i in 0...listText.count - 1 {
-                    if listText[i].lowercased().checkStartWithLink() {
-                        let rangeTapLink = (textChat as NSString).range(of: String(listText[i]))
-                        // Add tap gesture recognizer to the range of text
-                        let attributedString = textChat.richText()
-                        attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
-                        messageText.attributedText = attributedString
-                        if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !self.removed {
-                            messageText.isUserInteractionEnabled = true
-                            let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressLink(_:)))
-                            longPress.minimumPressDuration = 0.1
-                            containerMessage.addGestureRecognizer(longPress)
+                if listText.count > 0 {
+                    for i in 0...listText.count - 1 {
+                        if listText[i].lowercased().checkStartWithLink() {
+                            let attributedString = textChat.richText()
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
+                            attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
+                            messageText.attributedText = attributedString
+                            if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !self.removed {
+                                messageText.isUserInteractionEnabled = true
+                                let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressLink(_:)))
+                                longPress.minimumPressDuration = 0.1
+                                containerMessage.addGestureRecognizer(longPress)
+                            }
                         }
                     }
                 }
@@ -4980,7 +4981,16 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                     let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
                     if let dirPath = paths.first {
                         let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(listImages[i].thumbId)
-                        let image    = UIImage(contentsOfFile: thumbURL.path)?.resize(target: CGSize(width: 500, height: 500))
+                        let image : UIImage? =  {
+                            if let img = DigiX.imageCache.object(forKey: listImages[i].thumbId as NSString) {
+                                return img
+                            }
+                            else if let img = UIImage(contentsOfFile: thumbURL.path)?.resize(target: CGSize(width: 500, height: 500)) {
+                                DigiX.imageCache.setObject(img, forKey: listImages[i].thumbId as NSString)
+                                return img
+                            }
+                            return nil
+                        }()
 //                        let image = UIGraphicsRenderer.renderImageAt(url: thumbURL as NSURL, size: CGSize(width: 250, height: 250))
                         listImageThumb[i].image = image
 
@@ -5305,7 +5315,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -5332,7 +5342,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -6048,7 +6058,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -6065,9 +6075,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -6076,11 +6086,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
@@ -6128,12 +6136,14 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     
@@ -6540,3 +6550,4 @@ public class ImageGrouping {
         self.dataTopic = dataTopic
     }
 }
+

+ 16 - 10
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorStarMessages.swift

@@ -19,7 +19,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
     var previewItem = NSURL()
     var fromNotification = false
     var timerCheckLink: Timer?
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var lastTouchPoint: CGPoint = .zero
 
@@ -438,9 +438,8 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                 if listText.count > 0 {
                     for i in 0...listText.count - 1 {
                         if listText[i].lowercased().checkStartWithLink() {
-                            let rangeTapLink = (textChat! as NSString).range(of: String(listText[i]))
-                            // Add tap gesture recognizer to the range of text
                             let attributedString = textChat!.richText()
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
                             attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
                             messageText.attributedText = attributedString
                             messageText.isUserInteractionEnabled = true
@@ -690,7 +689,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -717,7 +716,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -843,7 +842,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -860,9 +859,9 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -871,11 +870,9 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
@@ -923,12 +920,14 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     
@@ -1294,6 +1293,13 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         return data
     }
     
+    public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
+        if showMenuContext {
+            showMenuContext = false
+            interaction.view!.removeInteraction(interaction)
+        }
+    }
+    
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
         let indexPath = self.tableChatView.indexPathForRow(at: interaction.view!.convert(location, to: self.tableChatView))
         let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath!.section]})

+ 4 - 0
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/ContactChatViewController.swift

@@ -979,6 +979,10 @@ extension ContactChatViewController {
                     messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
                 ])
                 messageView.textColor = .gray
+                if data.messageText.contains("■") {
+                    data.messageText = data.messageText.components(separatedBy: "■")[0]
+                    data.messageText = data.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
+                }
                 let text = Utils.previewMessageText(chat: data)
                 let idMe = UserDefaults.standard.string(forKey: "me") as String?
                 if let attributeText = text as? NSMutableAttributedString {

+ 23 - 11
appbuilder-ios/NexilisLite/NexilisLite/Source/Extension.swift

@@ -646,7 +646,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeBold.count {
                 if lastFirstRange == -1 {
-                    if (rangeBold[i].startIndex == 0 || checkCharBefore(char: textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeBold[i].endIndex + 1, to: rangeBold[i].endIndex + 1)
+                    if (rangeBold[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeBold[i].startIndex
                         continueCheckingBold = true
                     } else {
@@ -688,7 +690,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeItalic.count {
                 if lastFirstRange == -1 {
-                    if (rangeItalic[i].startIndex == 0 || checkCharBefore(char: textAfterbold.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1)
+                    if (rangeItalic[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeItalic[i].startIndex
                         continueCheckingItalic = true
                     } else {
@@ -698,8 +702,8 @@ extension String {
                 if !continueCheckingItalic {
                     continue
                 }
-                if rangeItalic[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1))[0]
+                if rangeItalic[i].endIndex != (textAfterbold.count-1) {
+                    let char: Character = Array(textAfterbold.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -707,7 +711,7 @@ extension String {
                 let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveItalicSign)).countEmojiCharacter()
                 let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveItalicSign), to: rangeItalic[i].endIndex - (2*countRemoveItalicSign)).countEmojiCharacter()
                 totalEmoji = countEmoji + countEmojiBefore
-                finalText.addAttribute(.font, value: font.italic, range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, length: (rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange))
+                finalText.addAttribute(.font, value: UIFont.italicSystemFont(ofSize: 12), range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, length: (rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange))
                 if !isEditing{
                     finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveItalicSign), length: 1))
                     finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: rangeItalic[i].endIndex + totalEmoji - (2*countRemoveItalicSign) - 1, length: 1))
@@ -730,7 +734,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeUnderline.count {
                 if lastFirstRange == -1 {
-                    if (rangeUnderline[i].startIndex == 0 || checkCharBefore(char: textAfterItalic.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1)
+                    if (rangeUnderline[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeUnderline[i].startIndex
                         continueCheckingUnderline = true
                     } else {
@@ -740,8 +746,8 @@ extension String {
                 if !continueCheckingUnderline {
                     continue
                 }
-                if rangeUnderline[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1))[0]
+                if rangeUnderline[i].endIndex != (textAfterItalic.count-1) {
+                    let char: Character = Array(textAfterItalic.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -772,7 +778,9 @@ extension String {
             var totalEmoji = 0
             for i in 0..<rangeStrikethrough.count {
                 if lastFirstRange == -1 {
-                    if (rangeStrikethrough[i].startIndex == 0 || checkCharBefore(char: textAfterUnderline.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1))) {
+                    let stringCharStart = textUTF8.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1)
+                    let stringCharEnd = textUTF8.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1)
+                    if (rangeStrikethrough[i].startIndex == 0 || checkCharBefore(char: stringCharStart) || (checkCharRich(char: stringCharStart) && stringCharStart == stringCharEnd)) {
                         lastFirstRange = rangeStrikethrough[i].startIndex
                         continueCheckingStrikethrough = true
                     } else {
@@ -782,8 +790,8 @@ extension String {
                 if !continueCheckingStrikethrough {
                     continue
                 }
-                if rangeStrikethrough[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1))[0]
+                if rangeStrikethrough[i].endIndex != (textAfterUnderline.count-1) {
+                    let char: Character = Array(textAfterUnderline.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1))[0]
                     if char.isLetter || char.isNumber {
                         continue
                     }
@@ -862,6 +870,10 @@ extension String {
         return char == " " || char == "\n"
     }
     
+    func checkCharRich(char: String) -> Bool {
+        return char == "*" || char == "_" || char == "^" || char == "~"
+    }
+    
     func checkStartWithLink() -> Bool {
         return self.starts(with: "https://") || self.starts(with: "http://") || self.starts(with: "www.")
         //|| self.starts(with: "*https://") || self.starts(with: "*http://") || self.starts(with: "*www.") || self.starts(with: "_https://") || self.starts(with: "_http://") || self.starts(with: "_www.") || self.starts(with: "^https://") || self.starts(with: "^http://") || self.starts(with: "^www.") || self.starts(with: "~https://") || self.starts(with: "~http://") || self.starts(with: "~www.")

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/Model/Chat.swift

@@ -13,7 +13,7 @@ public class Chat: Model {
     public let pin: String
     public let messageId: String
     public let counter: String
-    public let messageText: String
+    public var messageText: String
     public let serverDate: String
     public let image: String
     public let video: String

+ 59 - 57
appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -146,70 +146,72 @@ public class Nexilis: NSObject {
             Nexilis.dispatch = nil
             
 //            Nexilis.initiateAudio()
-            if(!id.isEmpty && (UserDefaults.standard.string(forKey: "me") == nil)){
-                if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000){
-                    id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
-                    let enable_signup = (response.getBody(key: CoreMessage_TMessageKey.IS_ENABLED_ANONYMOUS, default_value: "0")) == "1"
-                    Utils.setForceAnonymous(value: enable_signup)
-                    if(!id.isEmpty) {
-                        Nexilis.changeUser(f_pin: id)
-                        UserDefaults.standard.setValue(id, forKey: "me")
+            DispatchQueue.main.async {
+                if(!id.isEmpty && (UserDefaults.standard.string(forKey: "me") == nil)){
+                    if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000){
+                        id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
+                        let enable_signup = (response.getBody(key: CoreMessage_TMessageKey.IS_ENABLED_ANONYMOUS, default_value: "0")) == "1"
+                        Utils.setForceAnonymous(value: enable_signup)
+                        if(!id.isEmpty) {
+                            Nexilis.changeUser(f_pin: id)
+                            UserDefaults.standard.setValue(id, forKey: "me")
+                        }
                     }
                 }
-            }
 
-            if UserDefaults.standard.string(forKey: "apiKey") == nil {
-                UserDefaults.standard.setValue(apiKey, forKey: "apiKey")
-            }
-            
-            if let me = UserDefaults.standard.string(forKey: "me") {
-                if Utils.getForceAnonymous() || (!Utils.getForceAnonymous() && Utils.getSetProfile()) {
-                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                        if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT * FROM BUDDY where f_pin = '\(me)' ") {
-                            if !cursorData.next() {
-                                _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: me))
+                if UserDefaults.standard.string(forKey: "apiKey") == nil {
+                    UserDefaults.standard.setValue(apiKey, forKey: "apiKey")
+                }
+                
+                if let me = UserDefaults.standard.string(forKey: "me") {
+                    if Utils.getForceAnonymous() || (!Utils.getForceAnonymous() && Utils.getSetProfile()) {
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT * FROM BUDDY where f_pin = '\(me)' ") {
+                                if !cursorData.next() {
+                                    _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: me))
+                                }
+                                cursorData.close()
                             }
-                            cursorData.close()
-                        }
-                    })
-                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                        if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT image_id FROM GROUPZ where group_type = 1 AND official = 1"), cursorData.next() {
-                            do {
-                                let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
-                                let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
-                                if !FileManager().fileExists(atPath: file.path) {
-                                    Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
+                        })
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT image_id FROM GROUPZ where group_type = 1 AND official = 1"), cursorData.next() {
+                                do {
+                                    let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
+                                    let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
+                                    if !FileManager().fileExists(atPath: file.path) {
+                                        Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
+                                    }
+                                } catch {}
+                                cursorData.close()
+                            }
+                        })
+                    }
+                    getServiceBank()
+                    getPullWorkingArea()
+                    getPullGroupNoMember()
+                    delegate.onSuccess(userId: me)
+                    getPullDefaultCC()
+                    if showButton {
+                        DispatchQueue.main.async {
+                            var viewController = UIApplication.shared.windows.first?.rootViewController
+                            var notNull = false
+                            while !notNull {
+                                viewController = UIApplication.shared.windows.first?.rootViewController
+                                if viewController != nil {
+                                    notNull = true
                                 }
-                            } catch {}
-                            cursorData.close()
-                        }
-                    })
-                }
-                getServiceBank()
-                getPullWorkingArea()
-                getPullGroupNoMember()
-                delegate.onSuccess(userId: me)
-                getPullDefaultCC()
-                if showButton {
-                    DispatchQueue.main.async {
-                        var viewController = UIApplication.shared.windows.first?.rootViewController
-                        var notNull = false
-                        while !notNull {
-                            viewController = UIApplication.shared.windows.first?.rootViewController
-                            if viewController != nil {
-                                notNull = true
                             }
-                        }
-                        let fb = FloatingButton()
-                        if fromMAB {
-                            var vc = viewController
-                            if viewController is UINavigationController {
-                                vc = (viewController as! UINavigationController).rootViewController
+                            let fb = FloatingButton()
+                            if fromMAB {
+                                var vc = viewController
+                                if viewController is UINavigationController {
+                                    vc = (viewController as! UINavigationController).rootViewController
+                                }
+                                vc?.view.addSubview(fb)
+                                fb.mySettingDelegate = vc as? any SettingMABDelegate
+                            } else {
+                                viewController?.view.addSubview(fb)
                             }
-                            vc?.view.addSubview(fb)
-                            fb.mySettingDelegate = vc as? any SettingMABDelegate
-                        } else {
-                            viewController?.view.addSubview(fb)
                         }
                     }
                 }

+ 16 - 12
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -88,7 +88,7 @@ public class EditorGroup: UIViewController {
     var timerLongPressLink: Timer?
     var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var listViewOnSection: [UIView] = []
     var fakeProgMultip = 0
@@ -2197,6 +2197,12 @@ extension EditorGroup: UITextViewDelegate {
 }
 
 extension EditorGroup: UIContextMenuInteractionDelegate {
+    public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
+        if showMenuContext {
+            showMenuContext = false
+            interaction.view!.removeInteraction(interaction)
+        }
+    }
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
         if textFieldSend.isFirstResponder {
             textFieldSend.resignFirstResponder()
@@ -3520,9 +3526,8 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                 if listText.count > 0 {
                     for i in 0...listText.count - 1 {
                         if listText[i].lowercased().checkStartWithLink() {
-                            let rangeTapLink = (textChat! as NSString).range(of: String(listText[i]))
-                            // Add tap gesture recognizer to the range of text
                             let attributedString = textChat!.richText(group_id: self.dataGroup["group_id"] as! String)
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
                             attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
                             messageText.attributedText = attributedString
                             if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !isHistoryCC && !removed {
@@ -3919,13 +3924,13 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
             }
             if !text.isEmpty {
                 func showLink() {
-                    if !dataURL.isEmpty, let data = try! JSONSerialization.jsonObject(with: dataURL.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
+                    if let data = try! JSONSerialization.jsonObject(with: dataURL.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
                         let title = data["title"] as! String
                         let description = data["description"] as! String
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -3952,7 +3957,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -4608,7 +4613,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -4625,9 +4630,9 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -4636,15 +4641,12 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
-                        self.timerCheckLink?.invalidate()
                     })
                 }
             } else {
@@ -4689,12 +4691,14 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     

+ 11 - 12
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -98,7 +98,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var timerLongPressLink: Timer?
     var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var listViewOnSection: [UIView] = []
     var fromVCAC = false
@@ -3392,8 +3392,8 @@ extension EditorPersonal: UITextViewDelegate {
 //EUC
 extension EditorPersonal: UIContextMenuInteractionDelegate {
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
-        if isLinkCopied {
-            isLinkCopied = false
+        if showMenuContext {
+            showMenuContext = false
             interaction.view!.removeInteraction(interaction)
         }
     }
@@ -4901,9 +4901,8 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                 if listText.count > 0 {
                     for i in 0...listText.count - 1 {
                         if listText[i].lowercased().checkStartWithLink() {
-                            let rangeTapLink = (textChat as NSString).range(of: String(listText[i]))
-                            // Add tap gesture recognizer to the range of text
                             let attributedString = textChat.richText()
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
                             attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
                             messageText.attributedText = attributedString
                             if messageText.isUserInteractionEnabled == false && !copySession && !forwardSession && !deleteSession && !self.removed {
@@ -5316,7 +5315,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -5343,7 +5342,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -6059,7 +6058,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -6076,9 +6075,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -6087,11 +6086,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
@@ -6139,12 +6136,14 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     

+ 16 - 10
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorStarMessages.swift

@@ -19,7 +19,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
     var previewItem = NSURL()
     var fromNotification = false
     var timerCheckLink: Timer?
-    var isLinkCopied = false
+    var showMenuContext = false
     var touchedSubview = UIView()
     var lastTouchPoint: CGPoint = .zero
 
@@ -438,9 +438,8 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                 if listText.count > 0 {
                     for i in 0...listText.count - 1 {
                         if listText[i].lowercased().checkStartWithLink() {
-                            let rangeTapLink = (textChat! as NSString).range(of: String(listText[i]))
-                            // Add tap gesture recognizer to the range of text
                             let attributedString = textChat!.richText()
+                            let rangeTapLink = (attributedString.string as NSString).range(of: String(listText[i]))
                             attributedString.addAttributes([.foregroundColor: UIColor.blue, .underlineStyle: NSUnderlineStyle.single.rawValue], range: rangeTapLink)
                             messageText.attributedText = attributedString
                             messageText.isUserInteractionEnabled = true
@@ -690,7 +689,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                         let imageUrl = data["imageUrl"] as? String
                         let link = data["link"] as! String
                         
-                        topMarginText.constant = topMarginText.constant + 80
+                        topMarginText.constant = topMarginText.constant + 85
                         
                         containerMessage.addSubview(containerLinkMessage)
                         containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -717,7 +716,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                             } else {
                                 imagePreview.loadImageAsync(with: imageUrl)
                             }
-                            imagePreview.contentMode = .scaleAspectFit
+                            imagePreview.contentMode = .scaleToFill
                         }
                         
                         let titlePreview = UILabel()
@@ -843,7 +842,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                     impactHeavy.impactOccurred()
                     interaction.perform(selector, with: self.view)
-                    self.isLinkCopied = true
+                    self.showMenuContext = true
                 })
             }
         }
@@ -860,9 +859,9 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         if let text = label.text, let range = getWordRange(at: touchPointLabel, in: label) {
             let word = String(text[range])
             if word.starts(with: "www.") || word.starts(with: "https://") || word.starts(with: "http://") {
-                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended{
+                if gestureRecognizer.state == .cancelled || gestureRecognizer.state == .ended {
                     timerCheckLink?.invalidate()
-                    if !isLinkCopied {
+                    if label.isHighlighted {
                         var stringURl = word
                         if stringURl.starts(with: "www.") {
                             stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
@@ -871,11 +870,9 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                         UIApplication.shared.open(url)
                         label.attributedText = removeHighlightedText(for: text, in: range, label: label)
                     }
-                    isLinkCopied = false
                 } else if gestureRecognizer.state == .began {
                     label.attributedText = highlightedText(for: text, in: range, label: label)
                     timerCheckLink = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: {_ in
-                        self.isLinkCopied = true
                         UIPasteboard.general.string = word
                         self.showToast(message: "Link Copied".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
                         label.attributedText = self.removeHighlightedText(for: text, in: range, label: label)
@@ -923,12 +920,14 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
     func highlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.lightGray.withAlphaComponent(0.5), range: NSRange(range, in: text))
+        label.isHighlighted = true
         return mutableAttributedString
     }
     
     func removeHighlightedText(for text: String, in range: Range<String.Index>, label: UILabel) -> NSAttributedString {
         let mutableAttributedString = label.attributedText!.mutableCopy() as! NSMutableAttributedString
         mutableAttributedString.removeAttribute(.backgroundColor, range: NSRange(range, in: text))
+        label.isHighlighted = false
         return mutableAttributedString
     }
     
@@ -1294,6 +1293,13 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         return data
     }
     
+    public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
+        if showMenuContext {
+            showMenuContext = false
+            interaction.view!.removeInteraction(interaction)
+        }
+    }
+    
     public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
         let indexPath = self.tableChatView.indexPathForRow(at: interaction.view!.convert(location, to: self.tableChatView))
         let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath!.section]})

+ 4 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift

@@ -979,6 +979,10 @@ extension ContactChatViewController {
                     messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
                 ])
                 messageView.textColor = .gray
+                if data.messageText.contains("■") {
+                    data.messageText = data.messageText.components(separatedBy: "■")[0]
+                    data.messageText = data.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
+                }
                 let text = Utils.previewMessageText(chat: data)
                 let idMe = UserDefaults.standard.string(forKey: "me") as String?
                 if let attributeText = text as? NSMutableAttributedString {