瀏覽代碼

update link preview

alqindiirsyam 2 年之前
父節點
當前提交
748ead5eb5

+ 47 - 11
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorGroup.swift

@@ -3910,17 +3910,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                 }
             }
             if !text.isEmpty {
-                var dataURL = ""
-                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
-                        if let data = cursor.string(forColumnIndex: 0) {
-                            dataURL = data
-                        }
-                        cursor.close()
-                    }
-                })
-                
-                if !dataURL.isEmpty {
+                func showLink() {
                     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
@@ -4008,6 +3998,52 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         }
                     }
                 }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
             }
         }
         

+ 47 - 11
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorPersonal.swift

@@ -5292,17 +5292,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                 }
             }
             if !text.isEmpty {
-                var dataURL = ""
-                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
-                        if let data = cursor.string(forColumnIndex: 0) {
-                            dataURL = data
-                        }
-                        cursor.close()
-                    }
-                })
-                
-                if !dataURL.isEmpty {
+                func showLink() {
                     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
@@ -5390,6 +5380,52 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         }
                     }
                 }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
             }
         }
         

+ 159 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorStarMessages.swift

@@ -10,6 +10,7 @@ import AVKit
 import AVFoundation
 import QuickLook
 import Photos
+import SwiftLinkPreview
 
 public class EditorStarMessages: UIViewController, UITableViewDataSource, UITableViewDelegate, UIContextMenuInteractionDelegate, QLPreviewControllerDataSource {
     @IBOutlet var tableChatView: UITableView!
@@ -378,6 +379,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                 textChat = "🚫 _"+"This message was deleted".localized()+"_"
             }
         }
+        let imageSticker = UIImageView()
         if let attachmentFlag = dataMessages[indexPath.row]["attachment_flag"], let attachmentFlag = attachmentFlag as? String {
             if attachmentFlag == "27" || attachmentFlag == "26", let data = textChat { // live streaming
                 if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
@@ -402,7 +404,6 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
             } else if attachmentFlag == "11" {
                 messageText.text = ""
                 topMarginText.constant = topMarginText.constant + 100
-                let imageSticker = UIImageView()
                 containerMessage.addSubview(imageSticker)
                 imageSticker.translatesAutoresizingMaskIntoConstraints = false
                 imageSticker.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 27.0).isActive = true
@@ -637,9 +638,166 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
             objectTap.indexPath = indexPath
         }
         
+        let containerLinkMessage = UIView()
+        if thumbChat.isEmpty && fileChat.isEmpty && !textChat!.isEmpty {
+            var text = ""
+            let listTextSplitBreak = textChat!.components(separatedBy: "\n")
+            let indexFirstLinkSplitBreak = listTextSplitBreak.firstIndex(where: { $0.contains("www.") || $0.contains("http://") || $0.contains("https://") })
+            if indexFirstLinkSplitBreak != nil {
+                let listTextSplitSpace = listTextSplitBreak[indexFirstLinkSplitBreak!].components(separatedBy: " ")
+                let indexFirstLinkSplitSpace = listTextSplitSpace.firstIndex(where: { ($0.starts(with: "www.") && $0.components(separatedBy: ".").count > 2) || ($0.starts(with: "http://") && $0.components(separatedBy: ".").count > 1) || ($0.starts(with: "https://") && $0.components(separatedBy: ".").count > 1) })
+                if indexFirstLinkSplitSpace != nil {
+                    text = listTextSplitSpace[indexFirstLinkSplitSpace!]
+                }
+            }
+            if !text.isEmpty {
+                func showLink() {
+                    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
+                        
+                        containerMessage.addSubview(containerLinkMessage)
+                        containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
+                        containerLinkMessage.leadingAnchor.constraint(equalTo:containerMessage.leadingAnchor, constant: 15).isActive = true
+                        if dataMessages[indexPath.row]["attachment_flag"] as? String == "11" {
+                            containerLinkMessage.bottomAnchor.constraint(equalTo: imageSticker.topAnchor, constant: -5).isActive = true
+                        } else {
+                            containerLinkMessage.bottomAnchor.constraint(equalTo: messageText.topAnchor, constant: -5).isActive = true
+                        }
+                        containerLinkMessage.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
+                        containerLinkMessage.heightAnchor.constraint(equalToConstant: 80.0).isActive = true
+                        containerLinkMessage.backgroundColor = .gray.withAlphaComponent(0.2)
+                        
+                        let imagePreview = UIImageView()
+                        if imageUrl != nil {
+                            containerLinkMessage.addSubview(imagePreview)
+                            imagePreview.translatesAutoresizingMaskIntoConstraints = false
+                            imagePreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor).isActive = true
+                            imagePreview.bottomAnchor.constraint(equalTo: containerLinkMessage.bottomAnchor).isActive = true
+                            imagePreview.topAnchor.constraint(equalTo: containerLinkMessage.topAnchor).isActive = true
+                            imagePreview.widthAnchor.constraint(equalToConstant: 80.0).isActive = true
+                            if !imageUrl!.starts(with: "https://") {
+                                imagePreview.loadImageAsync(with: "https://www.google.be" + imageUrl!)
+                            } else {
+                                imagePreview.loadImageAsync(with: imageUrl)
+                            }
+                            imagePreview.contentMode = .scaleAspectFit
+                        }
+                        
+                        let titlePreview = UILabel()
+                        containerLinkMessage.addSubview(titlePreview)
+                        titlePreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            titlePreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            titlePreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        titlePreview.topAnchor.constraint(equalTo: containerLinkMessage.topAnchor, constant: 25.0).isActive = true
+                        titlePreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        titlePreview.text = title
+                        titlePreview.font = UIFont.systemFont(ofSize: 14.0, weight: .bold)
+                        titlePreview.textColor = .black
+                        
+                        let descPreview = UILabel()
+                        containerLinkMessage.addSubview(descPreview)
+                        descPreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            descPreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            descPreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        descPreview.topAnchor.constraint(equalTo: titlePreview.bottomAnchor).isActive = true
+                        descPreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        descPreview.text = description
+                        descPreview.font = UIFont.systemFont(ofSize: 12.0)
+                        descPreview.textColor = .gray
+                        descPreview.numberOfLines = 1
+                        
+                        let linkPreview = UILabel()
+                        containerLinkMessage.addSubview(linkPreview)
+                        linkPreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            linkPreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            linkPreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        linkPreview.topAnchor.constraint(equalTo: descPreview.bottomAnchor, constant: 8.0).isActive = true
+                        linkPreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        linkPreview.text = link
+                        linkPreview.font = UIFont.systemFont(ofSize: 10.0)
+                        linkPreview.textColor = .gray
+                        linkPreview.numberOfLines = 1
+                        
+                        let objectTap = ObjectGesture(target: self, action: #selector(tapMessageText(_:)))
+                        objectTap.message_id = text
+                        containerLinkMessage.addGestureRecognizer(objectTap)
+                    }
+                }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
+            }
+        }
+        
         return cellMessage
     }
     
+    @objc func tapMessageText(_ sender: ObjectGesture) {
+        var stringURl = sender.message_id.lowercased()
+        if stringURl.starts(with: "www.") {
+            stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
+        }
+        guard let url = URL(string: stringURl) else { return }
+        UIApplication.shared.open(url)
+    }
+    
     func getData() {
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             if let cursorData = Database.shared.getRecords(fmdb: fmdb, 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 is_stared=1 order by server_date asc") {

+ 47 - 11
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -3920,17 +3920,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                 }
             }
             if !text.isEmpty {
-                var dataURL = ""
-                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
-                        if let data = cursor.string(forColumnIndex: 0) {
-                            dataURL = data
-                        }
-                        cursor.close()
-                    }
-                })
-                
-                if !dataURL.isEmpty {
+                func showLink() {
                     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
@@ -4018,6 +4008,52 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                         }
                     }
                 }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
             }
         }
         

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

@@ -5311,17 +5311,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                 }
             }
             if !text.isEmpty {
-                var dataURL = ""
-                Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
-                        if let data = cursor.string(forColumnIndex: 0) {
-                            dataURL = data
-                        }
-                        cursor.close()
-                    }
-                })
-                
-                if !dataURL.isEmpty {
+                func showLink() {
                     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
@@ -5409,6 +5399,52 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                         }
                     }
                 }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
             }
         }
         

+ 159 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorStarMessages.swift

@@ -10,6 +10,7 @@ import AVKit
 import AVFoundation
 import QuickLook
 import Photos
+import SwiftLinkPreview
 
 public class EditorStarMessages: UIViewController, UITableViewDataSource, UITableViewDelegate, UIContextMenuInteractionDelegate, QLPreviewControllerDataSource {
     @IBOutlet var tableChatView: UITableView!
@@ -378,6 +379,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                 textChat = "🚫 _"+"This message was deleted".localized()+"_"
             }
         }
+        let imageSticker = UIImageView()
         if let attachmentFlag = dataMessages[indexPath.row]["attachment_flag"], let attachmentFlag = attachmentFlag as? String {
             if attachmentFlag == "27" || attachmentFlag == "26", let data = textChat { // live streaming
                 if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
@@ -402,7 +404,6 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
             } else if attachmentFlag == "11" {
                 messageText.text = ""
                 topMarginText.constant = topMarginText.constant + 100
-                let imageSticker = UIImageView()
                 containerMessage.addSubview(imageSticker)
                 imageSticker.translatesAutoresizingMaskIntoConstraints = false
                 imageSticker.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 27.0).isActive = true
@@ -637,9 +638,166 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
             objectTap.indexPath = indexPath
         }
         
+        let containerLinkMessage = UIView()
+        if thumbChat.isEmpty && fileChat.isEmpty && !textChat!.isEmpty {
+            var text = ""
+            let listTextSplitBreak = textChat!.components(separatedBy: "\n")
+            let indexFirstLinkSplitBreak = listTextSplitBreak.firstIndex(where: { $0.contains("www.") || $0.contains("http://") || $0.contains("https://") })
+            if indexFirstLinkSplitBreak != nil {
+                let listTextSplitSpace = listTextSplitBreak[indexFirstLinkSplitBreak!].components(separatedBy: " ")
+                let indexFirstLinkSplitSpace = listTextSplitSpace.firstIndex(where: { ($0.starts(with: "www.") && $0.components(separatedBy: ".").count > 2) || ($0.starts(with: "http://") && $0.components(separatedBy: ".").count > 1) || ($0.starts(with: "https://") && $0.components(separatedBy: ".").count > 1) })
+                if indexFirstLinkSplitSpace != nil {
+                    text = listTextSplitSpace[indexFirstLinkSplitSpace!]
+                }
+            }
+            if !text.isEmpty {
+                func showLink() {
+                    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
+                        
+                        containerMessage.addSubview(containerLinkMessage)
+                        containerLinkMessage.translatesAutoresizingMaskIntoConstraints = false
+                        containerLinkMessage.leadingAnchor.constraint(equalTo:containerMessage.leadingAnchor, constant: 15).isActive = true
+                        if dataMessages[indexPath.row]["attachment_flag"] as? String == "11" {
+                            containerLinkMessage.bottomAnchor.constraint(equalTo: imageSticker.topAnchor, constant: -5).isActive = true
+                        } else {
+                            containerLinkMessage.bottomAnchor.constraint(equalTo: messageText.topAnchor, constant: -5).isActive = true
+                        }
+                        containerLinkMessage.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
+                        containerLinkMessage.heightAnchor.constraint(equalToConstant: 80.0).isActive = true
+                        containerLinkMessage.backgroundColor = .gray.withAlphaComponent(0.2)
+                        
+                        let imagePreview = UIImageView()
+                        if imageUrl != nil {
+                            containerLinkMessage.addSubview(imagePreview)
+                            imagePreview.translatesAutoresizingMaskIntoConstraints = false
+                            imagePreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor).isActive = true
+                            imagePreview.bottomAnchor.constraint(equalTo: containerLinkMessage.bottomAnchor).isActive = true
+                            imagePreview.topAnchor.constraint(equalTo: containerLinkMessage.topAnchor).isActive = true
+                            imagePreview.widthAnchor.constraint(equalToConstant: 80.0).isActive = true
+                            if !imageUrl!.starts(with: "https://") {
+                                imagePreview.loadImageAsync(with: "https://www.google.be" + imageUrl!)
+                            } else {
+                                imagePreview.loadImageAsync(with: imageUrl)
+                            }
+                            imagePreview.contentMode = .scaleAspectFit
+                        }
+                        
+                        let titlePreview = UILabel()
+                        containerLinkMessage.addSubview(titlePreview)
+                        titlePreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            titlePreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            titlePreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        titlePreview.topAnchor.constraint(equalTo: containerLinkMessage.topAnchor, constant: 25.0).isActive = true
+                        titlePreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        titlePreview.text = title
+                        titlePreview.font = UIFont.systemFont(ofSize: 14.0, weight: .bold)
+                        titlePreview.textColor = .black
+                        
+                        let descPreview = UILabel()
+                        containerLinkMessage.addSubview(descPreview)
+                        descPreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            descPreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            descPreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        descPreview.topAnchor.constraint(equalTo: titlePreview.bottomAnchor).isActive = true
+                        descPreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        descPreview.text = description
+                        descPreview.font = UIFont.systemFont(ofSize: 12.0)
+                        descPreview.textColor = .gray
+                        descPreview.numberOfLines = 1
+                        
+                        let linkPreview = UILabel()
+                        containerLinkMessage.addSubview(linkPreview)
+                        linkPreview.translatesAutoresizingMaskIntoConstraints = false
+                        if imageUrl != nil {
+                            linkPreview.leadingAnchor.constraint(equalTo: imagePreview.trailingAnchor, constant: 5.0).isActive = true
+                        } else {
+                            linkPreview.leadingAnchor.constraint(equalTo: containerLinkMessage.leadingAnchor, constant: 5.0).isActive = true
+                        }
+                        linkPreview.topAnchor.constraint(equalTo: descPreview.bottomAnchor, constant: 8.0).isActive = true
+                        linkPreview.trailingAnchor.constraint(equalTo: containerLinkMessage.trailingAnchor, constant: -80.0).isActive = true
+                        linkPreview.text = link
+                        linkPreview.font = UIFont.systemFont(ofSize: 10.0)
+                        linkPreview.textColor = .gray
+                        linkPreview.numberOfLines = 1
+                        
+                        let objectTap = ObjectGesture(target: self, action: #selector(tapMessageText(_:)))
+                        objectTap.message_id = text
+                        containerLinkMessage.addGestureRecognizer(objectTap)
+                    }
+                }
+                var dataURL = ""
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select data_link from LINK_PREVIEW where link='\(text)'"), cursor.next() {
+                        if let data = cursor.string(forColumnIndex: 0) {
+                            dataURL = data
+                        }
+                        cursor.close()
+                    }
+                })
+                if dataURL.isEmpty {
+                    let slp = SwiftLinkPreview(session: URLSession.shared,
+                                   workQueue: SwiftLinkPreview.defaultWorkQueue,
+                                   responseQueue: DispatchQueue.main,
+                                       cache: DisabledCache.instance)
+                    let preview = slp.preview(text,
+                                              onSuccess: { result in
+                        let title = result.title ?? "No Title"
+                        let description = text.contains("google.com") ? "" : result.description
+                        let imageUrl = result.image
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            do {
+                                var dataJson: [String: Any] = [:]
+                                dataJson["title"] = title
+                                dataJson["description"] = description
+                                dataJson["imageUrl"] = imageUrl
+                                dataJson["link"] = text
+                                guard let json = String(data: try! JSONSerialization.data(withJSONObject: dataJson, options: []), encoding: String.Encoding.utf8) else {
+                                    return
+                                }
+                                _ = try Database.shared.insertRecord(fmdb: fmdb, table: "LINK_PREVIEW", cvalues: [
+                                    "id" : "\(Date().currentTimeMillis().toHex())",
+                                    "link" : text,
+                                    "data_link" : json,
+                                    "retry": 0
+                                ], replace: true)
+                                showLink()
+                            } catch {
+                                rollback.pointee = true
+                                //print(error)
+                            }
+                        })
+                    }, onError: { error in
+                    })
+                } else {
+                    showLink()
+                }
+            }
+        }
+        
         return cellMessage
     }
     
+    @objc func tapMessageText(_ sender: ObjectGesture) {
+        var stringURl = sender.message_id.lowercased()
+        if stringURl.starts(with: "www.") {
+            stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
+        }
+        guard let url = URL(string: stringURl) else { return }
+        UIApplication.shared.open(url)
+    }
+    
     func getData() {
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             if let cursorData = Database.shared.getRecords(fmdb: fmdb, 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 is_stared=1 order by server_date asc") {