Просмотр исходного кода

update podfile, podspec and update nusdkservices

alqindiirsyam 6 месяцев назад
Родитель
Сommit
d3101c3fc0

BIN
AppBuilder/.DS_Store


+ 33 - 35
AppBuilder/AppBuilder.xcodeproj/project.pbxproj

@@ -30,7 +30,7 @@
 		CD9D59E12BEE1D30008014B4 /* disini_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D62BEE1D30008014B4 /* disini_icon.png */; };
 		CD9D59E22BEE1D30008014B4 /* kmi_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D72BEE1D30008014B4 /* kmi_icon.png */; };
 		CD9D59E32BEE1D30008014B4 /* nu_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D82BEE1D30008014B4 /* nu_icon.png */; };
-		D6B1C354D062B60F7CAABAED /* Pods_AppBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E273714C9F2C0AFEADA842F /* Pods_AppBuilder.framework */; };
+		D1E579A46512EF4E61108DA3 /* Pods_AppBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -77,9 +77,8 @@
 		2401CEA2275490E600B323BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		2401CEA5275490E600B323BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		2401CEA7275490E600B323BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		4CBBF6A59F76BC3D5DA5B92B /* Pods-AppBuilder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.debug.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.debug.xcconfig"; sourceTree = "<group>"; };
-		65A3907E764F550D0F7DD37D /* Pods-AppBuilder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.release.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.release.xcconfig"; sourceTree = "<group>"; };
-		9E273714C9F2C0AFEADA842F /* Pods_AppBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.release.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.release.xcconfig"; sourceTree = "<group>"; };
+		9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.debug.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.debug.xcconfig"; sourceTree = "<group>"; };
 		A413B18627EACB20006D16EB /* PrefsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsUtil.swift; sourceTree = "<group>"; };
 		A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstTabViewController.swift; sourceTree = "<group>"; };
 		A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondTabViewController.swift; sourceTree = "<group>"; };
@@ -97,10 +96,11 @@
 		CD9D59D72BEE1D30008014B4 /* kmi_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = kmi_icon.png; sourceTree = "<group>"; };
 		CD9D59D82BEE1D30008014B4 /* nu_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = nu_icon.png; sourceTree = "<group>"; };
 		CDE27BA42D53641D006298BD /* AppBuilder.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AppBuilder.entitlements; sourceTree = "<group>"; };
+		D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
-		CD08A1692D5EEDA5005B4EAC /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
+		CDE50D8B2D62E0B00094C30D /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
 			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
 			membershipExceptions = (
 				Info.plist,
@@ -110,7 +110,7 @@
 /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
 
 /* Begin PBXFileSystemSynchronizedRootGroup section */
-		CD08A15F2D5EEDA5005B4EAC /* AppBuilderShare */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CD08A1692D5EEDA5005B4EAC /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AppBuilderShare; sourceTree = "<group>"; };
+		CDE50D872D62E08C0094C30D /* AppBuilderShare */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CDE50D8B2D62E0B00094C30D /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = AppBuilderShare; sourceTree = "<group>"; };
 /* End PBXFileSystemSynchronizedRootGroup section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -118,7 +118,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D6B1C354D062B60F7CAABAED /* Pods_AppBuilder.framework in Frameworks */,
+				D1E579A46512EF4E61108DA3 /* Pods_AppBuilder.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -136,8 +136,8 @@
 			isa = PBXGroup;
 			children = (
 				2401CE98275490DB00B323BB /* AppBuilder */,
-				CD08A15F2D5EEDA5005B4EAC /* AppBuilderShare */,
-				D5D9E949851220D48FDB3E78 /* Frameworks */,
+				CDE50D872D62E08C0094C30D /* AppBuilderShare */,
+				D555D5E529C625D02EB38D49 /* Frameworks */,
 				6E32BCCF4DE50EE1A90E8AAE /* Pods */,
 				2401CE97275490DB00B323BB /* Products */,
 			);
@@ -186,16 +186,16 @@
 		6E32BCCF4DE50EE1A90E8AAE /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				4CBBF6A59F76BC3D5DA5B92B /* Pods-AppBuilder.debug.xcconfig */,
-				65A3907E764F550D0F7DD37D /* Pods-AppBuilder.release.xcconfig */,
+				9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */,
+				971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */,
 			);
 			path = Pods;
 			sourceTree = "<group>";
 		};
-		D5D9E949851220D48FDB3E78 /* Frameworks */ = {
+		D555D5E529C625D02EB38D49 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				9E273714C9F2C0AFEADA842F /* Pods_AppBuilder.framework */,
+				D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -207,13 +207,13 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 2401CEC0275490E600B323BB /* Build configuration list for PBXNativeTarget "AppBuilder" */;
 			buildPhases = (
-				BF5B1FC69F69170CAEF49C91 /* [CP] Check Pods Manifest.lock */,
+				0FC96EABAB7E2B838F504E03 /* [CP] Check Pods Manifest.lock */,
 				2401CE92275490DB00B323BB /* Sources */,
 				2401CE93275490DB00B323BB /* Frameworks */,
 				2401CE94275490DB00B323BB /* Resources */,
 				247E0A722796969200430E5F /* Embed Frameworks */,
 				CDEE3DD129B06E1E00B420E5 /* Embed Foundation Extensions */,
-				07F1B34C1BB97DF342E2A084 /* [CP] Embed Pods Frameworks */,
+				25AEE8905FF82EB55B58854D /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -238,11 +238,9 @@
 			dependencies = (
 			);
 			fileSystemSynchronizedGroups = (
-				CD08A15F2D5EEDA5005B4EAC /* AppBuilderShare */,
+				CDE50D872D62E08C0094C30D /* AppBuilderShare */,
 			);
 			name = AppBuilderShare;
-			packageProductDependencies = (
-			);
 			productName = AppBuilderShare;
 			productReference = CD08A15E2D5EEDA5005B4EAC /* AppBuilderShare.appex */;
 			productType = "com.apple.product-type.app-extension";
@@ -315,43 +313,43 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		07F1B34C1BB97DF342E2A084 /* [CP] Embed Pods Frameworks */ = {
+		0FC96EABAB7E2B838F504E03 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			name = "[CP] Embed Pods Frameworks";
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-AppBuilder-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks.sh\"\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
-		BF5B1FC69F69170CAEF49C91 /* [CP] Check Pods Manifest.lock */ = {
+		25AEE8905FF82EB55B58854D /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
+			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
-			);
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-AppBuilder-checkManifestLockResult.txt",
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
@@ -527,7 +525,7 @@
 		};
 		2401CEC1275490E600B323BB /* Debug */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = 4CBBF6A59F76BC3D5DA5B92B /* Pods-AppBuilder.debug.xcconfig */;
+			baseConfigurationReference = 9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
@@ -563,7 +561,7 @@
 		};
 		2401CEC2275490E600B323BB /* Release */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = 65A3907E764F550D0F7DD37D /* Pods-AppBuilder.release.xcconfig */;
+			baseConfigurationReference = 971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;

+ 8 - 34
AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -125,7 +125,8 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
                 } else {
                     switch(selectedTag) {
                     case UNREAD_TAG :
-                        fillteredData = self.chats.filter { $0.counter != "0" }
+                        let deepCopyChats = self.chats.map{ $0.copy() }
+                        fillteredData = deepCopyChats.filter { $0.counter != "0" }
                         break
                     case PHOTOS_TAG, VIDEOS_TAG, GIFS_TAG :
                         fillteredData = Chat.getData(isImage: selectedTag == PHOTOS_TAG, isVideo: selectedTag == VIDEOS_TAG, isGIF: selectedTag == GIFS_TAG)
@@ -548,6 +549,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
             }
         })
         getData()
+        APIS.setDataForShareExtension()
     }
     
     override func viewWillAppear(_ animated: Bool) {
@@ -790,35 +792,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
     }
     
     @objc func onStatusChat(notification: NSNotification) {
-        DispatchQueue.main.async { [self] in
-            let data:[AnyHashable : Any] = notification.userInfo!
-            if let dataMessage = data["message"] as? TMessage {
-                var idMessage = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
-                if dataMessage.mBodies["message_id"] != nil {
-                    idMessage = dataMessage.getBody(key: "message_id")
-                    if idMessage.contains("'") {
-                        idMessage = idMessage.replacingOccurrences(of: "'", with: "")
-                    }
-                }
-                if idMessage.contains(",") {
-                    let listString = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID).components(separatedBy: ",")
-                    idMessage = listString[listString.count - 1]
-                }
-                let indexChat = chats.firstIndex(where: { $0.messageId == idMessage })
-                if indexChat != nil {
-                    if dataMessage.getBody(key: CoreMessage_TMessageKey.DELETE_MESSAGE_FLAG) == "1" {
-                        chats[indexChat!].lock = "1"
-                    }
-                    if segment.selectedSegmentIndex == 0 {
-                        tableView.beginUpdates()
-                        tableView.reloadRows(at: [IndexPath(row: indexChat!, section: 0)], with: .none)
-                        tableView.endUpdates()
-                    } else {
-                        tableView.reloadData()
-                    }
-                }
-            }
-        }
+        reloadAllData()
     }
     
     @objc func segmentChanged(sender: Any) {
@@ -899,7 +873,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
                             parentChat.counter = "\(Int(counterParent)! + Int(singleChat.counter)!)"
                         }
                         if let parentExist = chatParentInPreviousChats, parentExist.isSelected {
-                            if let indexParent = previousChat.firstIndex(where: { $0.isParent && $0.groupId == singleChat.groupId }){
+                            if let indexParent = tempChats.firstIndex(where: { $0.isParent && $0.groupId == singleChat.groupId }){
                                 tempChats.insert(singleChat, at: indexParent + self.chatGroupMaps[singleChat.groupId]!.count)
                             }
                         }
@@ -1125,7 +1099,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
     
     func expandCollapseChats(tableView: UITableView, indexPath: IndexPath) {
         let data: Chat
-        if isFiltering {
+        if isFiltering || selectedTag == UNREAD_TAG {
             data = fillteredData[indexPath.row] as! Chat
         } else {
             data = chats[indexPath.row]
@@ -1134,7 +1108,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
         if data.isSelected {
             for dataSubChat in self.chatGroupMaps[data.groupId]! {
                 if var indexParent = chats.firstIndex(where: { $0.isParent && $0.groupId == data.groupId }) {
-                    if isFiltering {
+                    if isFiltering || selectedTag == UNREAD_TAG {
                         fillteredData.insert(dataSubChat, at: indexParent + 1)
                         indexParent+=1
                     } else {
@@ -1145,7 +1119,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 
             }
         } else {
-            if isFiltering {
+            if isFiltering || selectedTag == UNREAD_TAG {
                 if var changedFillteredData = fillteredData as? [Chat] {
                     changedFillteredData.removeAll(where: { $0.isParent == false && $0.groupId == data.groupId })
                     self.fillteredData = changedFillteredData

+ 1 - 0
AppBuilder/Podfile

@@ -4,4 +4,5 @@ platform :ios, '14.0'
 target 'AppBuilder' do
   use_frameworks!
   pod 'NexilisLite', :path => '../NexilisLite'
+  pod 'NotificationBannerSwift', :git => 'https://github.com/Daltron/NotificationBanner.git', :tag => '4.0.0'
 end

+ 5 - 5
NexilisLite/NexilisLite.podspec

@@ -24,15 +24,15 @@ Pod::Spec.new do |spec|
   spec.resource_bundles = { 'NexilisLite' => ['NexilisLite/Resource/**/*']}
   spec.swift_version = '5.5.1'
   spec.dependency 'FMDB', '~> 2.7.12'
-  spec.dependency 'nuSDKService', '~> 4.0.4'
-  spec.dependency 'NotificationBannerSwift', '~> 3.1.0'
-  spec.dependency 'Alamofire', '~> 5.10.1'
+  spec.dependency 'nuSDKService', '~> 4.0.5'
+  spec.dependency 'NotificationBannerSwift'
+  spec.dependency 'Alamofire', '~> 5.10.2'
   spec.dependency 'SDWebImage', '~> 5.20.0'
   spec.dependency 'Toast-Swift', '~> 5.1.1'
   spec.dependency 'ZIPFoundation', '~> 0.9.19'
   spec.dependency 'SwiftLinkPreview', '~> 3.4.0'
-  spec.dependency 'KeychainAccess'
-  spec.dependency 'Popover'
+  spec.dependency 'KeychainAccess', '~> 4.2.2'
+  spec.dependency 'Popover', '~> 1.3.0'
 # spec.static_framework = true
 # spec.dependency 'iOS-WebP'
 #  spec.vendored_frameworks = 'nuSDKService.framework'

+ 8 - 9
NexilisLite/NexilisLite/Source/APIS.swift

@@ -1249,7 +1249,6 @@ public class APIS: NSObject {
     public static func enterForeground() {
         do {
             if !Nexilis.sAPIKey.isEmpty {
-                print("MASUK initConnection enterForeground")
                 var id = Utils.getConnectionID()
                 if id.isEmpty {
                     let sDID = UIDevice.current.identifierForVendor?.uuidString ?? "UNK-DEVICE"
@@ -1378,8 +1377,8 @@ public class APIS: NSObject {
                 Database.shared.database?.inTransaction({ (fmdb, rollback) in
                     var dataShared: [[String: Any]] = []
                     if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_pin id, image_id image, first_name || ' ' || ifnull(last_name, '') name FROM BUDDY WHERE f_pin != '\(User.getMyPin() ?? "")' AND f_pin != '-997' AND official_account != '1'") {
-                        var dataTemp: [String: Any] = [:]
                         while cursor.next() {
+                            var dataTemp: [String: Any] = [:]
                             for columnIndex in 0..<cursor.columnCount {
                                 if let columnName = cursor.columnName(for: columnIndex) {
                                     if let value = cursor.object(forColumn: columnName) {
@@ -1404,18 +1403,17 @@ public class APIS: NSObject {
                                         } else {
                                             dataTemp[columnName] = value
                                         }
+                                        dataTemp["type"] = 0
                                     }
                                 }
-                                dataTemp["type"] = 0
                             }
+                            dataShared.append(dataTemp)
                         }
-                        dataShared.append(dataTemp)
                         cursor.close()
                     }
                     if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT group_id id, image_id image, f_name name FROM GROUPZ WHERE official != 1") {
-                        var dataTemp: [String: Any] = [:]
-                        var dataTempTopic: [String: Any] = [:]
                         while cursor.next() {
+                            var dataTemp: [String: Any] = [:]
                             for columnIndex in 0..<cursor.columnCount {
                                 if let columnName = cursor.columnName(for: columnIndex) {
                                     if let value = cursor.object(forColumn: columnName) {
@@ -1442,9 +1440,9 @@ public class APIS: NSObject {
                                         } else {
                                             dataTemp[columnName] = value
                                         }
+                                        dataTemp["type"] = 1
                                     }
                                 }
-                                dataTemp["type"] = 1
                             }
                             dataShared.append(dataTemp)
                             let group_id = cursor.string(forColumnIndex: 0) ?? ""
@@ -1452,6 +1450,7 @@ public class APIS: NSObject {
                             let name_group = cursor.string(forColumnIndex: 2) ?? ""
                             if let cursorTopic = Database.shared.getRecords(fmdb: fmdb, query: "SELECT chat_id id, thumb image, title name FROM DISCUSSION_FORUM WHERE group_id = '\(group_id)'") {
                                 while cursorTopic.next() {
+                                    var dataTempTopic: [String: Any] = [:]
                                     for columnIndex in 0..<cursorTopic.columnCount {
                                         if let columnName = cursorTopic.columnName(for: columnIndex) {
                                             if let value = cursorTopic.object(forColumn: columnName) {
@@ -1478,13 +1477,13 @@ public class APIS: NSObject {
                                                 } else {
                                                     dataTempTopic[columnName] = value
                                                 }
+                                                dataTempTopic["type"] = 1
                                             }
                                         }
-                                        dataTempTopic["type"] = 1
                                     }
                                     dataShared.append(dataTempTopic)
-                                    cursorTopic.close()
                                 }
+                                cursorTopic.close()
                             }
                         }
                         cursor.close()

+ 78 - 314
NexilisLite/NexilisLite/Source/Extension.swift

@@ -725,341 +725,105 @@ extension String {
         return String(self[startIndex ..< endIndex])
     }
     
-    func countEmojiCharacter() -> Int {
+    public func richText(
+        isEditing: Bool = false,
+        isSearching: Bool = false,
+        textSearch: String = "",
+        group_id: String = "",
+        listMentionInTextField: [User] = []
+    ) -> NSMutableAttributedString {
         
-        func isEmoji(s:NSString) -> Bool {
-            
-            let high:Int = Int(s.character(at: 0))
-            if 0xD800 <= high && high <= 0xDBFF {
-                let low:Int = Int(s.character(at: 1))
-                let codepoint: Int = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
-                return (0x1D000 <= codepoint && codepoint <= 0x1F9FF)
-            }
-            else {
-                return (0x2100 <= high && high <= 0x27BF)
-            }
-        }
-        
-        let nsString = self as NSString
-        var length = 0
-        
-        nsString.enumerateSubstrings(in: NSMakeRange(0, nsString.length), options: NSString.EnumerationOptions.byComposedCharacterSequences) { (subString, substringRange, enclosingRange, stop) -> Void in
-            
-            if isEmoji(s: subString! as NSString) {
-                length+=1
-            }
-        }
-        
-        return length
-    }
-    
-    public func richText(isEditing: Bool = false, isSearching: Bool = false, textSearch: String = "", group_id: String = "", listMentionInTextField: [User] = []) -> NSMutableAttributedString {
         let font = UIFont.systemFont(ofSize: 12)
         let boldFont = UIFont.boldSystemFont(ofSize: 12)
         let italicFont = UIFont.italicSystemFont(ofSize: 12)
         let boldItalicFont = UIFont.systemFont(ofSize: 12, weight: .semibold)
-        let textUTF8 = String(self.utf8)
-        let finalText = NSMutableAttributedString(string: textUTF8, attributes: [NSAttributedString.Key.font: font])
-        let boldSign: Character = "*"
-        let italicSign: Character = "_"
-        let underlineSign: Character = "^"
-        let strikethroughSign: Character = "~"
-        let italicGreySign: Character = "$"
-        var locationBold: [NSRange] = []
         
-        //Bold
-        let rangeBold = getRangeOfWordWithSign(sentence: textUTF8, sign: boldSign)
-        if rangeBold.count > 0 {
-            var lastFirstRange = -1
-            var countRemoveBoldSign = 0
-            var continueCheckingBold = false
-            var totalEmoji = 0
-            for i in 0..<rangeBold.count {
-                if rangeBold[i].startIndex > lastFirstRange {
-                    let charStart: Character = rangeBold[i].startIndex != 0 ? Array(textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1))[0] : Array("0")[0]
-                    if (rangeBold[i].startIndex == 0 || (!charStart.isLetter && !charStart.isNumber)) {
-                        lastFirstRange = rangeBold[i].startIndex
-                        continueCheckingBold = true
-                    } else {
-                        continueCheckingBold = false
-                    }
-                }
-                if !continueCheckingBold {
-                    continue
-                }
-                if rangeBold[i].endIndex != (textUTF8.count-1) {
-                    let char: Character = Array(textUTF8.substring(from: rangeBold[i].endIndex + 1, to: rangeBold[i].endIndex + 1))[0]
-                    if char.isLetter || char.isNumber {
-                        continue
-                    }
-                }
-                let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveBoldSign)).countEmojiCharacter()
-                let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveBoldSign), to: rangeBold[i].endIndex - (2*countRemoveBoldSign)).countEmojiCharacter()
-                totalEmoji = countEmoji + countEmojiBefore
-                locationBold.append(NSRange(location: lastFirstRange - (2*countRemoveBoldSign) + countEmojiBefore, length: (rangeBold[i].endIndex + countEmoji + 1) - lastFirstRange))
-                finalText.addAttribute(.font, value: boldFont, range: NSRange(location: lastFirstRange - (2*countRemoveBoldSign) + countEmojiBefore, length: (rangeBold[i].endIndex + countEmoji + 1) - lastFirstRange))
-                if !isEditing{
-                    finalText.mutableString.replaceOccurrences(of: "\(boldSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveBoldSign), length: 1))
-                    finalText.mutableString.replaceOccurrences(of: "\(boldSign)", with: "", options: .literal, range: NSRange(location: rangeBold[i].endIndex + totalEmoji - (2*countRemoveBoldSign) - 1, length: 1))
-                    countRemoveBoldSign += 1
-                } else {
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + countEmojiBefore, length: 1))
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeBold[i].endIndex + totalEmoji, length: 1))
-                }
-                lastFirstRange = rangeBold[i].endIndex
-                continueCheckingBold = false
-            }
-        }
+        let textUTF8 = self
+        let finalText = NSMutableAttributedString(string: textUTF8, attributes: [.font: font])
         
-        //Italic
-        let textAfterbold = finalText.string
-        let rangeItalic = getRangeOfWordWithSign(sentence: textAfterbold, sign: italicSign)
-        if rangeItalic.count > 0 {
-            var lastFirstRange = -1
-            var countRemoveItalicSign = 0
-            var continueCheckingItalic = false
-            var totalEmoji = 0
-            for i in 0..<rangeItalic.count {
-                if rangeItalic[i].startIndex > lastFirstRange {
-                    let charStart: Character = rangeItalic[i].startIndex != 0 ? Array(textAfterbold.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1))[0] : Array("0")[0]
-                    if (rangeItalic[i].startIndex == 0 || (!charStart.isLetter && !charStart.isNumber)) {
-                        lastFirstRange = rangeItalic[i].startIndex
-                        continueCheckingItalic = true
-                    } else {
-                        continueCheckingItalic = false
-                    }
-                }
-                if !continueCheckingItalic {
-                    continue
-                }
-                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
-                    }
-                }
-                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
-                if isIntInRangeList((rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange - lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, rangeList: locationBold) {
-                    finalText.addAttribute(.font, value: boldItalicFont, range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign) + countEmojiBefore, length: (rangeItalic[i].endIndex + countEmoji + 1) - lastFirstRange))
-                } else {
-                    finalText.addAttribute(.font, value: italicFont, 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))
-                    countRemoveItalicSign += 1
-                } else {
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + countEmojiBefore, length: 1))
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeItalic[i].endIndex + totalEmoji, length: 1))
-                }
-                lastFirstRange = rangeItalic[i].endIndex
-                continueCheckingItalic = false
-            }
-        }
-        
-        //Underline
-        let textAfterItalic = finalText.string
-        let rangeUnderline = getRangeOfWordWithSign(sentence: textAfterItalic, sign: underlineSign)
-        if rangeUnderline.count > 0 {
-            var lastFirstRange = -1
-            var countRemoveUnderlineSign = 0
-            var continueCheckingUnderline = false
-            var totalEmoji = 0
-            for i in 0..<rangeUnderline.count {
-                if rangeUnderline[i].startIndex > lastFirstRange {
-                    let charStart: Character = rangeUnderline[i].startIndex != 0 ? Array(textAfterItalic.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1))[0] : Array("0")[0]
-                    if (rangeUnderline[i].startIndex == 0 || (!charStart.isLetter && !charStart.isNumber)) {
-                        lastFirstRange = rangeUnderline[i].startIndex
-                        continueCheckingUnderline = true
-                    } else {
-                        continueCheckingUnderline = false
-                    }
-                }
-                if !continueCheckingUnderline {
-                    continue
-                }
-                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
-                    }
-                }
-                let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveUnderlineSign)).countEmojiCharacter()
-                let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveUnderlineSign), to: rangeUnderline[i].endIndex - (2*countRemoveUnderlineSign)).countEmojiCharacter()
-                totalEmoji = countEmoji + countEmojiBefore
-                finalText.addAttribute(.underlineStyle, value: NSUnderlineStyle.thick.rawValue, range: NSRange(location: lastFirstRange - (2*countRemoveUnderlineSign) + countEmojiBefore + 1, length: (rangeUnderline[i].endIndex + countEmoji - 1) - lastFirstRange))
-                if !isEditing{
-                    finalText.mutableString.replaceOccurrences(of: "\(underlineSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveUnderlineSign), length: 1))
-                    finalText.mutableString.replaceOccurrences(of: "\(underlineSign)", with: "", options: .literal, range: NSRange(location: rangeUnderline[i].endIndex + totalEmoji - (2*countRemoveUnderlineSign) - 1, length: 1))
-                    countRemoveUnderlineSign += 1
-                } else {
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + countEmojiBefore, length: 1))
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeUnderline[i].endIndex + totalEmoji, length: 1))
-                }
-                lastFirstRange = rangeUnderline[i].endIndex
-                continueCheckingUnderline = false
-            }
-        }
-        
-        //Strikethrough
-        let textAfterUnderline = finalText.string
-        let rangeStrikethrough = getRangeOfWordWithSign(sentence: textAfterUnderline, sign: strikethroughSign)
-        if rangeStrikethrough.count > 0 {
-            var lastFirstRange = -1
-            var countRemoveStrikethroughSign = 0
-            var continueCheckingStrikethrough = false
-            var totalEmoji = 0
-            for i in 0..<rangeStrikethrough.count {
-                if rangeStrikethrough[i].startIndex > lastFirstRange {
-                    let charStart: Character = rangeStrikethrough[i].startIndex != 0 ? Array(textAfterUnderline.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1))[0] : Array("0")[0]
-                    if (rangeStrikethrough[i].startIndex == 0 || (!charStart.isLetter && !charStart.isNumber)) {
-                        lastFirstRange = rangeStrikethrough[i].startIndex
-                        continueCheckingStrikethrough = true
-                    } else {
-                        continueCheckingStrikethrough = false
-                    }
-                }
-                if !continueCheckingStrikethrough {
-                    continue
-                }
-                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
-                    }
-                }
-                let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveStrikethroughSign)).countEmojiCharacter()
-                let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveStrikethroughSign), to: rangeStrikethrough[i].endIndex - (2*countRemoveStrikethroughSign)).countEmojiCharacter()
-                totalEmoji = countEmoji + countEmojiBefore
-                finalText.addAttribute(.strikethroughStyle, value: 2, range: NSRange(location: lastFirstRange - (2*countRemoveStrikethroughSign) + countEmojiBefore + 1, length: (rangeStrikethrough[i].endIndex + countEmoji - 1) - lastFirstRange))
-                if !isEditing{
-                    finalText.mutableString.replaceOccurrences(of: "\(strikethroughSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveStrikethroughSign), length: 1))
-                    finalText.mutableString.replaceOccurrences(of: "\(strikethroughSign)", with: "", options: .literal, range: NSRange(location: rangeStrikethrough[i].endIndex + totalEmoji - (2*countRemoveStrikethroughSign) - 1, length: 1))
-                    countRemoveStrikethroughSign += 1
-                } else {
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + countEmojiBefore, length: 1))
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeStrikethrough[i].endIndex + totalEmoji, length: 1))
-                }
-                lastFirstRange = rangeStrikethrough[i].endIndex
-                continueCheckingStrikethrough = false
-            }
+        let formattingRules: [(String, [NSAttributedString.Key: Any])] = [
+            ("*_", [.font: boldItalicFont]), // Bold + Italic
+            ("_*", [.font: boldItalicFont]), // Bold + Italic
+            ("*", [.font: boldFont]), // Bold
+            ("_", [.font: italicFont]), // Italic
+            ("~", [.strikethroughStyle: NSUnderlineStyle.single.rawValue]),
+            ("^", [.underlineStyle: NSUnderlineStyle.single.rawValue]),
+            ("$", [.font: italicFont, .foregroundColor: UIColor.darkGray]) // Italic + Gray for $
+        ]
+
+        for (sign, attributes) in formattingRules {
+            applyTextFormatting(to: finalText, sign: sign, attributes: attributes, isEditing: isEditing)
         }
         
-        //ItalicGrey
-        let textAfterStrikeThrough = finalText.string
-        let rangeItalicGrey = getRangeOfWordWithSign(sentence: textAfterStrikeThrough, sign: italicGreySign)
-        if rangeItalicGrey.count > 0 {
-            var lastFirstRange = -1
-            var countRemoveItalicGreySign = 0
-            var continueCheckingItalicGrey = false
-            var totalEmoji = 0
-            for i in 0..<rangeItalicGrey.count {
-                if rangeItalicGrey[i].startIndex > lastFirstRange {
-                    let charStart: Character = rangeItalicGrey[i].startIndex != 0 ? Array(textAfterStrikeThrough.substring(from: rangeItalicGrey[i].startIndex - 1, to: rangeItalicGrey[i].startIndex - 1))[0] : Array("0")[0]
-                    if (rangeItalicGrey[i].startIndex == 0 || (!charStart.isLetter && !charStart.isNumber)) {
-                        lastFirstRange = rangeItalicGrey[i].startIndex
-                        continueCheckingItalicGrey = true
-                    } else {
-                        continueCheckingItalicGrey = false
-                    }
-                }
-                if !continueCheckingItalicGrey {
-                    continue
-                }
-                if rangeItalicGrey[i].endIndex != (textAfterStrikeThrough.count-1) {
-                    let char: Character = Array(textAfterStrikeThrough.substring(from: rangeItalicGrey[i].endIndex + 1, to: rangeItalicGrey[i].endIndex + 1))[0]
-                    if char.isLetter || char.isNumber {
-                        continue
-                    }
-                }
-                let countEmojiBefore = finalText.string.substring(from: 0, to: lastFirstRange - (2*countRemoveItalicGreySign)).countEmojiCharacter()
-                let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveItalicGreySign), to: rangeItalicGrey[i].endIndex - (2*countRemoveItalicGreySign)).countEmojiCharacter()
-                totalEmoji = countEmoji + countEmojiBefore
-                finalText.addAttribute(.font, value: italicFont, range: NSRange(location: lastFirstRange - (2*countRemoveItalicGreySign) + countEmojiBefore, length: (rangeItalicGrey[i].endIndex + countEmoji + 1) - lastFirstRange))
-                finalText.addAttribute(.foregroundColor, value: UIColor.darkGray, range: NSRange(location: lastFirstRange - (2*countRemoveItalicGreySign) + countEmojiBefore, length: (rangeItalicGrey[i].endIndex + countEmoji + 1) - lastFirstRange))
-                if !isEditing{
-                    finalText.mutableString.replaceOccurrences(of: "\(italicGreySign)", with: "", options: .literal, range: NSRange(location: lastFirstRange + countEmojiBefore - (2*countRemoveItalicGreySign), length: 1))
-                    finalText.mutableString.replaceOccurrences(of: "\(italicGreySign)", with: "", options: .literal, range: NSRange(location: rangeItalicGrey[i].endIndex + totalEmoji - (2*countRemoveItalicGreySign) - 1, length: 1))
-                    countRemoveItalicGreySign += 1
-                } else {
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + countEmojiBefore, length: 1))
-                    finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeItalicGrey[i].endIndex + totalEmoji, length: 1))
-                }
-                lastFirstRange = rangeItalicGrey[i].endIndex
-                continueCheckingItalicGrey = false
-            }
-        }
+        processMentions(in: finalText, groupID: group_id, isEditing: isEditing)
         
-        //Check Mention
-        let finalTextAfterRichText = finalText.string
-        if finalTextAfterRichText.contains("@") {
-            let listTextEnter = finalText.string.split(separator: "\n")
-            for j in 0...listTextEnter.count - 1 {
-                let listText = listTextEnter[j].split(separator: " ")
-                let listMention = listText.filter({ $0.starts(with: "@")})
-                if listMention.count > 0 {
-                    for i in 0..<listMention.count {
-                        let f_pin = (String(listMention[i])).substring(from: 1, to: listMention[i].count)
-                        let member = Member.getMember(f_pin: f_pin)
-                        if member != nil {
-                            let name = (member!.firstName + " " + member!.lastName).trimmingCharacters(in: .whitespaces)
-                            finalText.mutableString.replaceOccurrences(of: f_pin, with: name, options: .literal, range: NSString(string: finalText.string).range(of: f_pin))
-                            if !group_id.isEmpty && Member.getMemberInGroup(f_pin: f_pin, group_id: group_id) != nil {
-                                finalText.addAttribute(.foregroundColor, value: UIColor.mentionColor, range: NSString(string: finalText.string).range(of: "@\(name)"))
-                            }
-                        }
-                    }
-                }
-            }
-        }
         if isSearching {
-            let range = NSString(string: finalText.string).range(of: textSearch, options: .caseInsensitive) // 2
-            let highlightColor = UIColor.systemYellow // 3
-            let highlightedAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.backgroundColor: highlightColor] // 4
-            
-            finalText.addAttributes(highlightedAttributes, range: range) // 5
+            highlightSearchText(in: finalText, searchText: textSearch)
         }
         
         return finalText
     }
-    
-    func isIntInRangeList(_ intValue: Int, rangeList: [NSRange]) -> Bool {
-        for range in rangeList {
-            if intValue >= range.location && intValue < range.location + range.length {
-                return true
+
+    // MARK: - Helper Functions
+
+    private func applyTextFormatting(
+        to text: NSMutableAttributedString,
+        sign: String,
+        attributes: [NSAttributedString.Key: Any],
+        isEditing: Bool
+    ) {
+        let escapedSign = NSRegularExpression.escapedPattern(for: sign)
+        let pattern = "\(escapedSign)(.+?)\(escapedSign)" // Ensure sign is correctly escaped in regex
+        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return }
+
+        let matches = regex.matches(in: text.string, options: [], range: NSRange(location: 0, length: text.length))
+
+        for match in matches.reversed() { // Iterate in reverse to prevent index shifting
+            let fullRange = match.range
+            let textRange = match.range(at: 1)
+
+            // Apply the desired formatting
+            for (key, value) in attributes {
+                text.addAttribute(key, value: value, range: textRange)
+            }
+
+            if !isEditing {
+                // Remove formatting characters (signs)
+                text.replaceCharacters(in: NSRange(location: fullRange.upperBound - sign.count, length: sign.count), with: "")
+                text.replaceCharacters(in: NSRange(location: fullRange.lowerBound, length: sign.count), with: "")
+            } else {
+                // Change color of formatting characters (grayed out)
+                text.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: fullRange.lowerBound, length: sign.count))
+                text.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: fullRange.upperBound - sign.count, length: sign.count))
             }
         }
-        return false
     }
-    
-    func checkStartWithLink() -> Bool {
-        return self.starts(with: "https://") || self.starts(with: "http://") || self.starts(with: "www.")
-    }
-    
-    func getRangeOfWordWithSign(sentence: String, sign: Character) -> [Range<Int>] {
-        let asterisk: Character = sign
-        var ranges = [Range<Int>]()
-        
-        var startIndex = sentence.startIndex
-        
-        while let startRange = sentence[startIndex...].firstIndex(of: asterisk),
-              let endRange = sentence[startRange...].dropFirst().firstIndex(of: asterisk) {
-            
-            let range = startRange..<endRange
-            let word = sentence[range].replacingOccurrences(of: "\(sign)", with: "")
+
+    private func processMentions(in text: NSMutableAttributedString, groupID: String, isEditing: Bool) {
+        let regex = try? NSRegularExpression(pattern: "@(\\w+)", options: [])
+        let matches = regex?.matches(in: text.string, options: [], range: NSRange(location: 0, length: text.length)) ?? []
+
+        for match in matches.reversed() {
+            let range = match.range(at: 1)
+            let username = (text.string as NSString).substring(with: range)
             
-            if !word.isEmpty {
-                let lower = sentence.distance(from: sentence.startIndex, to: startRange)
-                let upper = sentence.distance(from: sentence.startIndex, to: endRange)
-                ranges.append(Range(uncheckedBounds: (lower: lower, upper: upper)))
+            if let member = Member.getMember(f_pin: username) {
+                let fullName = "\(member.firstName) \(member.lastName)".trimmingCharacters(in: .whitespaces)
+                text.replaceCharacters(in: range, with: fullName)
+                
+                if !groupID.isEmpty, Member.getMemberInGroup(f_pin: username, group_id: groupID) != nil {
+                    let newRange = (text.string as NSString).range(of: "@\(fullName)")
+                    text.addAttribute(.foregroundColor, value: UIColor.mentionColor, range: newRange)
+                }
             }
-            
-            startIndex = endRange
         }
-        
-        return ranges
+    }
+
+    private func highlightSearchText(in text: NSMutableAttributedString, searchText: String) {
+        let range = (text.string as NSString).range(of: searchText, options: .caseInsensitive)
+        if range.location != NSNotFound {
+            text.addAttribute(.backgroundColor, value: UIColor.systemYellow, range: range)
+        }
     }
     
 }

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -4309,7 +4309,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
             
             timeMessage.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: -8).isActive = true
             
-            if (dataMessages[indexPath.row]["lock"] as? String != "2") {
+            if (dataMessages[indexPath.row]["lock"] as? String == "0" || (dataMessages[indexPath.row]["lock"] as? String ?? "").isEmpty) {
                 cellMessage.contentView.addSubview(statusMessage)
                 statusMessage.translatesAutoresizingMaskIntoConstraints = false
                 statusMessage.bottomAnchor.constraint(equalTo: timeMessage.topAnchor).isActive = true

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -5549,7 +5549,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
             
             timeMessage.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: -8).isActive = true
             
-            if (dataMessages[indexPath.row]["lock"] as? String != "2") {
+            if (dataMessages[indexPath.row]["lock"] as? String == "0" || (dataMessages[indexPath.row]["lock"] as? String ?? "").isEmpty) {
                 cell.contentView.addSubview(statusMessage)
                 statusMessage.translatesAutoresizingMaskIntoConstraints = false
                 statusMessage.bottomAnchor.constraint(equalTo: timeMessage.topAnchor).isActive = true

+ 0 - 13
NexilisLite/NexilisLite/Source/View/Chat/MessageInfo.swift

@@ -735,19 +735,6 @@ class MessageInfo: UIViewController, UITableViewDelegate, UITableViewDataSource,
             } else {
                 messageText.attributedText = textChat.richText()
             }
-            messageText.isUserInteractionEnabled = true
-            if !textChat.isEmpty {
-                let listText = textChat.split(separator: " ")
-                for i in 0...listText.count - 1 {
-                    if listText[i].lowercased().checkStartWithLink() {
-                        if ((listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 3) || (!listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 2)) && listText[i].lowercased().split(separator: ".").last!.count >= 2 {
-                            let objectGesture = ObjectGesture(target: self, action: #selector(tapMessageText(_:)))
-                            objectGesture.message_id = "\(listText[i])"
-                            messageText.addGestureRecognizer(objectGesture)
-                        }
-                    }
-                }
-            }
             
             let stringDate = (data["server_date"] as? String) ?? ""
             if !stringDate.isEmpty {

+ 2 - 30
NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift

@@ -296,35 +296,7 @@ class ContactChatViewController: UITableViewController {
     }
     
     @objc func onStatusChat(notification: NSNotification) {
-        DispatchQueue.main.async { [self] in
-            let data:[AnyHashable : Any] = notification.userInfo!
-            if let dataMessage = data["message"] as? TMessage {
-                var idMessage = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
-                if dataMessage.mBodies["message_id"] != nil {
-                    idMessage = dataMessage.getBody(key: "message_id")
-                    if idMessage.contains("'") {
-                        idMessage = idMessage.replacingOccurrences(of: "'", with: "")
-                    }
-                }
-                if idMessage.contains(",") {
-                    let listString = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID).components(separatedBy: ",")
-                    idMessage = listString[listString.count - 1]
-                }
-                let indexChat = chats.firstIndex(where: { $0.messageId == idMessage })
-                if indexChat != nil {
-                    if dataMessage.getBody(key: CoreMessage_TMessageKey.DELETE_MESSAGE_FLAG) == "1" {
-                        chats[indexChat!].lock = "1"
-                    }
-                    if segment.selectedSegmentIndex == 0 {
-                        tableView.beginUpdates()
-                        tableView.reloadRows(at: [IndexPath(row: indexChat!, section: 0)], with: .none)
-                        tableView.endUpdates()
-                    } else {
-                        tableView.reloadData()
-                    }
-                }
-            }
-        }
+        reloadAllData()
     }
     
     @objc func add(sender: Any) {
@@ -440,7 +412,7 @@ class ContactChatViewController: UITableViewController {
                             parentChat.counter = "\(Int(counterParent)! + Int(singleChat.counter)!)"
                         }
                         if let parentExist = chatParentInPreviousChats, parentExist.isSelected {
-                            if let indexParent = previousChat.firstIndex(where: { $0.isParent && $0.groupId == singleChat.groupId }){
+                            if let indexParent = tempChats.firstIndex(where: { $0.isParent && $0.groupId == singleChat.groupId }){
                                 tempChats.insert(singleChat, at: indexParent + self.chatGroupMaps[singleChat.groupId]!.count)
                             }
                         }

+ 4 - 4
NexilisLite/Podfile

@@ -9,14 +9,14 @@ target 'NexilisLite' do
 
   pod 'nuSDKService', '~> 4.0.4'
   pod 'FMDB', '~> 2.7.12'
-  pod 'NotificationBannerSwift', '3.1.0'
-  pod 'Alamofire', '~> 5.10.1'
+  pod 'NotificationBannerSwift', :git => 'https://github.com/Daltron/NotificationBanner.git', :tag => '4.0.0'
+  pod 'Alamofire', '~> 5.10.2'
   pod 'SDWebImage', '~> 5.20.0'
   pod 'Toast-Swift', '~> 5.1.1'
   pod 'ZIPFoundation', '~> 0.9.19'
   pod 'SwiftLinkPreview', '~> 3.4.0'
-  pod 'Popover'
-  pod 'KeychainAccess'
+  pod 'Popover', '~> 4.2.2'
+  pod 'KeychainAccess', '~> 1.3.0'
 
   target 'NexilisLiteTests' do
     # Pods for testing