浏览代码

update fix bugs and add indicator tab MAB

alqindiirsyam 7 月之前
父节点
当前提交
2a150947f4

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

@@ -527,8 +527,8 @@
 				BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 2;
-				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				CURRENT_PROJECT_VERSION = 4;
+				DEVELOPMENT_TEAM = TS9C3K7699;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Frameworks",
@@ -540,8 +540,8 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.2.9;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1;
+				MARKETING_VERSION = 4.0.5;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder2;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
@@ -559,8 +559,8 @@
 				BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 2;
-				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				CURRENT_PROJECT_VERSION = 4;
+				DEVELOPMENT_TEAM = TS9C3K7699;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)/Frameworks",
@@ -572,8 +572,8 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.2.9;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1;
+				MARKETING_VERSION = 4.0.5;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder2;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
@@ -588,7 +588,7 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
-				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				DEVELOPMENT_TEAM = TS9C3K7699;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = NotificationService/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
@@ -600,7 +600,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1.NotificationService;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder2.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;
@@ -616,7 +616,7 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
-				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				DEVELOPMENT_TEAM = TS9C3K7699;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = NotificationService/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
@@ -628,7 +628,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1.NotificationService;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder2.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;

+ 0 - 3
AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -146,9 +146,6 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
                 Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()),
             ]
-            if Nexilis.showButtonFB {
-                Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "gearshape.circle"), title: "Configure Floating Button".localized()))
-            }
         } else {
             Database.shared.database?.inTransaction({ fmdb, rollback in
                 let idMe = User.getMyPin() as String?

+ 2 - 0
AppBuilder/AppBuilder/Info.plist

@@ -209,5 +209,7 @@
 	</array>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<true/>
+    <key>UIUserInterfaceStyle</key>
+    <string>Light</string>
 </dict>
 </plist>

+ 223 - 82
AppBuilder/AppBuilder/ViewController.swift

@@ -53,6 +53,9 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
     let privacyWV = WKWebView()
     let indicatorCounterFB = UIView()
     let labelCounterFB = UILabel()
+    var indicatorView : UIView!
+    var indicatorImage : UIImageView!
+    var imageIndicator: UIImage!
     
     public static var def: ViewController?
 
@@ -120,50 +123,122 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
         }
         DispatchQueue.global().async {
             if !Utils.getTab1Icon().isEmpty {
-                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab1Icon())")!) { data, response, error in
-                    guard let data = data, error == nil else { return }
-                    // always update the UI from the main thread
-                    DispatchQueue.main.async() { [self] in
-                        tabs[0].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                let urlString = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab1Icon())"
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                    DispatchQueue.main.async() {
+                        tabs[0].tabBarItem = UITabBarItem(title: "", image: self.resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: self.resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                    }
+                } else {
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() { [self] in
+                            if UIImage(data: data) != nil {
+                                tabs[0].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
+                        }
                     }
                 }
             }
             if !Utils.getTab2Icon().isEmpty {
-                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab2Icon())")!) { data, response, error in
-                    guard let data = data, error == nil else { return }
-                    // always update the UI from the main thread
+                let urlString = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab2Icon())"
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
                     DispatchQueue.main.async() { [self] in
-                        tabs[1].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        tabs[1].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                    }
+                } else {
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() { [self] in
+                            if UIImage(data: data) != nil {
+                                tabs[1].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
+                        }
                     }
                 }
             }
             if !Utils.getTab3Icon().isEmpty {
-                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab3Icon())")!) { data, response, error in
-                    guard let data = data, error == nil else { return }
-                    // always update the UI from the main thread
+                let urlString = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab3Icon())"
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
                     DispatchQueue.main.async() { [self] in
                         if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
-                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
                         } else {
-                            tabs[2].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                            tabs[2].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        }
+                    }
+                } else {
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() { [self] in
+                            if UIImage(data: data) != nil {
+                                if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
+                                    tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                } else {
+                                    tabs[2].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                }
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
                         }
                     }
                 }
             }
             if !Utils.getTab4Icon().isEmpty {
-                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab4Icon())")!) { data, response, error in
-                    guard let data = data, error == nil else { return }
-                    // always update the UI from the main thread
+                let urlString = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab4Icon())"
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
                     DispatchQueue.main.async() { [self] in
                         if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
-                            tabs[4].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                            tabs[4].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
                         } else {
-                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: cachedImage, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        }
+                    }
+                } else {
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() { [self] in
+                            if UIImage(data: data) != nil {
+                                if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
+                                    tabs[4].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                } else {
+                                    tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                                }
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
                         }
                     }
                 }
             }
         }
+        if !Utils.getIndicatorTabImage().isEmpty {
+            let indicatorImage = Utils.getIndicatorTabImage()
+            let fullUrl = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(indicatorImage)"
+            if let cachedImage = ImageCache.shared.image(forKey: fullUrl) {
+                DispatchQueue.main.async() { [self] in
+                    imageIndicator = cachedImage
+                    addCustomViewAboveTabBarItem(at: 0, image: imageIndicator)
+                }
+            } else {
+                Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: fullUrl)!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        if UIImage(data: data) != nil {
+                            imageIndicator = UIImage(data: data)!
+                            addCustomViewAboveTabBarItem(at: 0, image: imageIndicator)
+                            ImageCache.shared.save(image: UIImage(data: data)!, forKey: fullUrl)
+                        }
+                    }
+                }
+            }
+        } else {
+//            addCustomViewAboveTabBarItem(at: 0, image: imageIndicator)
+        }
         if((cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
             createMidFloatingButton()
             navigationController?.setNavigationBarHidden(true, animated: false)
@@ -194,6 +269,39 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
 //        Nexilis.debugBroadcast()
     }
     
+    func addCustomViewAboveTabBarItem(at index: Int, image: UIImage?) {
+        guard let tabBarItems = tabBar.items, index < tabBarItems.count else { return }
+        let tabBarFrame = tabBar.frame
+        let tabBarItemWidth = tabBarFrame.width / CGFloat(tabBarItems.count)
+        let xCenter = CGFloat(index) * tabBarItemWidth + (tabBarItemWidth / 2)
+        let yCenter = tabBarFrame.origin.y + (tabBarFrame.height / 2)
+        if image != nil {
+            indicatorImage = UIImageView(image: image)
+            indicatorImage.contentMode = .scaleAspectFit
+            indicatorImage.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
+            indicatorImage.center = CGPoint(x: xCenter, y: yCenter)
+            view.addSubview(indicatorImage)
+        } else {
+            indicatorView = UIView()
+            indicatorView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
+            indicatorView.center = CGPoint(x: xCenter, y: yCenter)
+            let gradientLayer = CAGradientLayer()
+            gradientLayer.type = .radial
+            gradientLayer.colors = [
+                UIColor(white: 1.0, alpha: 0.0).cgColor,
+                UIColor(white: 1.0, alpha: 0.0).cgColor,
+                UIColor(red: 0.75, green: 0.71, blue: 0.71, alpha: 1.0).cgColor
+            ]
+            gradientLayer.locations = [0.0, 0.7, 1.0]
+            gradientLayer.bounds = CGRect(x: 0, y: 0, width: 90, height: 90)
+            gradientLayer.position = CGPoint(x: 45, y: 45)
+            indicatorView.layer.insertSublayer(gradientLayer, at: 0)
+            indicatorView.layer.cornerRadius = indicatorView.frame.width / 2
+            indicatorView.clipsToBounds = true
+            view.addSubview(indicatorView)
+        }
+    }
+    
     static func getiPhoneModel() -> String {
         var systemInfo = utsname()
         uname(&systemInfo)
@@ -358,30 +466,6 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
         ViewController.isTab2 = false
         ViewController.isTab3 = false
         ViewController.isTab4 = false
-//        if ViewController.isTab1 {
-//            ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis")!
-//        }
-//        else {
-//            ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis_off")!
-//        }
-//        if ViewController.isTab2 {
-//            ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis")!
-//        }
-//        else {
-//            ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis_off")!
-//        }
-//        if ViewController.isTab3 {
-//            ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis")!
-//        }
-//        else {
-//            ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis_off")!
-//        }
-//        if ViewController.isTab4 {
-//            ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis")!
-//        }
-//        else {
-//            ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis_off")!
-//        }
     }
     
     override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
@@ -467,13 +551,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
         ViewController.middleButton = UIButton(frame: CGRect(x: buttonCenterX - 40 , y: buttonCenterY - 40, width: 80, height: 80))
         if !PrefsUtil.getIconDock().isEmpty {
             if PrefsUtil.getIconDock().contains(".gif") {
-                ViewController.middleButton.sd_setBackgroundImage(with: URL(string: PrefsUtil.getIconCenterAnim()!), for: .normal, completed: { (image, error, cacheType, imageURL) in
-                    if let error = error {
-                        //print("Error loading image: \(error.localizedDescription)")
-                    } else {
-                        //print("Image loaded successfully")
-                    }
-                })
+                ViewController.middleButton.sd_setBackgroundImage(with: URL(string: PrefsUtil.getIconCenterAnim()!), for: .normal, completed: nil)
             } else {
                 DispatchQueue.global().async {
                     let urlString = PrefsUtil.getUrlDock()!
@@ -539,6 +617,12 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
     }
     
     func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
+        if let selectedIndex = viewControllers?.firstIndex(of: viewController) {
+            if indicatorImage != nil {
+                indicatorImage.removeFromSuperview()
+                addCustomViewAboveTabBarItem(at: selectedIndex, image: imageIndicator)
+            }
+        }
         if viewController != secondTab {
             let idxTabChat = self.viewControllers?.firstIndex(where: {$0 == secondTab})
             if idxTabChat != nil {
@@ -1036,20 +1120,38 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                             let icon = customIcons[i]
                             listPullFB.append("\(package_id)|\(app_id)")
                             DispatchQueue.global().async {
-                                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "get_file_from_path?img=\(icon)")!) { data, response, error in
+                                let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=\(icon)"
+                                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                    if i == 0 {
+                                        ViewController.chatButton.setBackgroundImage(cachedImage, for: .normal)
+                                    } else if i == 1 {
+                                        ViewController.callButton.setBackgroundImage(cachedImage, for: .normal)
+                                    }  else if i == 2 {
+                                        ViewController.ccButton.setBackgroundImage(cachedImage, for: .normal)
+                                    }  else if i == 3 {
+                                        ViewController.postButton.setBackgroundImage(cachedImage, for: .normal)
+                                    }  else if i == 4 {
+                                        ViewController.streamingButton.setBackgroundImage(cachedImage, for: .normal)
+                                    }
+                                    return
+                                }
+                                Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                     guard let data = data, error == nil else { return }
                                     // always update the UI from the main thread
                                     DispatchQueue.main.async() {
-                                        if i == 0 {
-                                            ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
-                                        } else if i == 1 {
-                                            ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
-                                        }  else if i == 2 {
-                                            ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
-                                        }  else if i == 3 {
-                                            ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
-                                        }  else if i == 4 {
-                                            ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        if UIImage(data: data) != nil {
+                                            if i == 0 {
+                                                ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                            } else if i == 1 {
+                                                ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                            }  else if i == 2 {
+                                                ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                            }  else if i == 3 {
+                                                ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                            }  else if i == 4 {
+                                                ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                            }
+                                            ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
                                         }
                                     }
                                 }
@@ -1072,14 +1174,24 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                                             let app_id = (json["app_id"] as? String) ?? ""
                                             let icon = (json["icon"] as? String) ?? ""
                                             listPullFB.append("\(package_id)|\(app_id)")
+                                            let urlString = "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)"
                                             if count == 0 {
                                                 if !icon.isEmpty {
                                                     DispatchQueue.global().async {
-                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.chatButton.setBackgroundImage(cachedImage, for: .normal)
+                                                            }
+                                                            return
+                                                        }
+                                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                                             guard let data = data, error == nil else { return }
                                                             // always update the UI from the main thread
                                                             DispatchQueue.main.async() {
-                                                                ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                if UIImage(data: data) != nil {
+                                                                    ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                                }
                                                             }
                                                         }
                                                     }
@@ -1089,58 +1201,94 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                                             } else if count == 1 {
                                                 if !icon.isEmpty {
                                                     DispatchQueue.global().async {
-                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.callButton.setBackgroundImage(cachedImage, for: .normal)
+                                                            }
+                                                            return
+                                                        }
+                                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                                             guard let data = data, error == nil else { return }
                                                             // always update the UI from the main thread
                                                             DispatchQueue.main.async() {
-                                                                ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                if UIImage(data: data) != nil {
+                                                                    ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                                }
                                                             }
                                                         }
                                                     }
                                                 } else {
-                                                    ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                    ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
                                                 }
                                             } else if count == 2 {
                                                 if !icon.isEmpty {
                                                     DispatchQueue.global().async {
-                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.ccButton.setBackgroundImage(cachedImage, for: .normal)
+                                                            }
+                                                            return
+                                                        }
+                                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                                             guard let data = data, error == nil else { return }
                                                             // always update the UI from the main thread
                                                             DispatchQueue.main.async() {
-                                                                ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                if UIImage(data: data) != nil {
+                                                                    ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                                }
                                                             }
                                                         }
                                                     }
                                                 } else {
-                                                    ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                    ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
                                                 }
                                             } else if count == 3 {
                                                 if !icon.isEmpty {
                                                     DispatchQueue.global().async {
-                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.postButton.setBackgroundImage(cachedImage, for: .normal)
+                                                            }
+                                                            return
+                                                        }
+                                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                                             guard let data = data, error == nil else { return }
                                                             // always update the UI from the main thread
                                                             DispatchQueue.main.async() {
-                                                                ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                if UIImage(data: data) != nil {
+                                                                    ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                                }
                                                             }
                                                         }
                                                     }
                                                 } else {
-                                                    ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                    ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_post", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
                                                 }
                                             } else if count == 4 {
                                                 if !icon.isEmpty {
                                                     DispatchQueue.global().async {
-                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.streamingButton.setBackgroundImage(cachedImage, for: .normal)
+                                                            }
+                                                            return
+                                                        }
+                                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                                             guard let data = data, error == nil else { return }
                                                             // always update the UI from the main thread
                                                             DispatchQueue.main.async() {
-                                                                ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                if UIImage(data: data) != nil {
+                                                                    ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                                }
                                                             }
                                                         }
                                                     }
                                                 } else {
-                                                    ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                    ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
                                                 }
                                             }
                                             count += 1
@@ -1253,13 +1401,6 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
 //        ViewController.postButton.removeFromSuperview()
         ViewController.middleButton.isHidden = true
     }
-    
-    public static func getDataImageFromUrl(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
-        let urlConfig = URLSessionConfiguration.default
-        let sessionDelegate = SelfSignedURLSessionDelegate()
-        let session = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil)
-        session.dataTask(with: url, completionHandler: completion).resume()
-    }
 
 }
 

+ 36 - 24
NexilisLite/NexilisLite/Source/FloatingButton/FloatingButton.swift

@@ -335,11 +335,7 @@ public class FloatingButton: UIView {
             return
         }
         if groupView.subviews.count == 0 {
-            if !Utils.getHistoryPullFB().isEmpty {
-                setFBFromPull()
-            } else {
-                getDefaultButton()
-            }
+            getDefaultButton()
         }
         DispatchQueue.global().async { [self] in
             if !Utils.getCustomButtons().isEmpty && configModeFB != MODE_HORIZONTAL_SIDE_TAB && configModeFB != MODE_HORIZONTAL_ANIMATION && configModeFB != MODE_VERTICAL_SIDE_TAB && Nexilis.fromMAB {
@@ -355,12 +351,21 @@ public class FloatingButton: UIView {
                         let newButton = UIButton()
                         newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
                         newButton.translatesAutoresizingMaskIntoConstraints = false
-                        DispatchQueue.global().async {[self] in
-                            getDataImageFromUrl(from: URL(string: Utils.getURLBase() + "get_file_from_path?img=" + icon)!) { data, response, error in
+                        DispatchQueue.global().async {
+                            let urlString = Utils.getURLBase() + "get_file_from_path?img=" + icon
+                            if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                DispatchQueue.main.async() {
+                                    newButton.setImage(cachedImage, for: .normal)
+                                }
+                                return
+                            }
+                            Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                 guard let data = data, error == nil else { return }
-                                DispatchQueue.main.async {
+                                // always update the UI from the main thread
+                                DispatchQueue.main.async() {
                                     if let image = UIImage(data: data) {
                                         newButton.setImage(image, for: .normal)
+                                        ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
                                     }
                                 }
                             }
@@ -371,13 +376,16 @@ public class FloatingButton: UIView {
                         newButton.addTarget(self, action: #selector(fbTap), for: .touchUpInside)
                     }
                 }
-                return
-            }
-            if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000){
-                if response.isOk() {
-                    Utils.setHistoryPullFB(value: response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: ""))
+            } else {
+                if !Utils.getHistoryPullFB().isEmpty {
                     setFBFromPull()
                 }
+                if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000){
+                    if response.isOk() {
+                        Utils.setHistoryPullFB(value: response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: ""))
+                        setFBFromPull()
+                    }
+                }
             }
         }
     }
@@ -443,11 +451,22 @@ public class FloatingButton: UIView {
                                     newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_more" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_more" : "pb_button_others", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
                                 }
                                 if !icon.isEmpty {
-                                    DispatchQueue.global().async { [self] in
-                                        getDataImageFromUrl(from: URL(string: Utils.getURLBase() + "get_file_from_path?img=" + icon)!) { data, response, error in
+                                    DispatchQueue.global().async {
+                                        let urlString = Utils.getURLBase() + "get_file_from_path?img=" + icon
+                                        if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                                            DispatchQueue.main.async() {
+                                                newButton.setImage(cachedImage, for: .normal)
+                                            }
+                                            return
+                                        }
+                                        Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
                                             guard let data = data, error == nil else { return }
-                                            DispatchQueue.main.async {
-                                                newButton.setImage(UIImage(data: data), for: .normal)
+                                            // always update the UI from the main thread
+                                            DispatchQueue.main.async() {
+                                                if let image = UIImage(data: data) {
+                                                    newButton.setImage(image, for: .normal)
+                                                    ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                                                }
                                             }
                                         }
                                     }
@@ -464,13 +483,6 @@ public class FloatingButton: UIView {
         }
     }
     
-    private func getDataImageFromUrl(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
-        let urlConfig = URLSessionConfiguration.default
-        let sessionDelegate = SelfSignedURLSessionDelegate()
-        let session = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil)
-        session.dataTask(with: url, completionHandler: completion).resume()
-    }
-    
     func getDefaultButton() {
         let mode = configModeFB
         var data = [Nexilis.IDX_NOTIF_CENTER, Nexilis.IDX_CC, Nexilis.IDX_CONVERSATION, Nexilis.IDX_CALL, Nexilis.IDX_STREAM]

+ 26 - 1
NexilisLite/NexilisLite/Source/Utils.swift

@@ -589,7 +589,8 @@ public final class Utils {
         let apiKey: String = SecureUserDefaults.shared.value(forKey: "apiKey") ?? ""
         let parameters = [
             "app_id": APIS.getAppNm(),
-            "apikey": apiKey
+            "apikey": apiKey,
+            "f_pin": User.getMyPin()
         ]
         var jsonArray: [[String: Any]] = []
         jsonArray.append(parameters)
@@ -742,6 +743,21 @@ public final class Utils {
                     if Array(json.keys)[i] == "fb_icon_center" {
                         Utils.setIconCenter(value: Array(json.values)[i] as? String ?? "")
                     }
+                    if Array(json.keys)[i] == "tab1_icon" {
+                        Utils.setTab1Icon(value: Array(json.values)[i] as? String ?? "")
+                    }
+                    if Array(json.keys)[i] == "tab2_icon" {
+                        Utils.setTab2Icon(value: Array(json.values)[i] as? String ?? "")
+                    }
+                    if Array(json.keys)[i] == "tab3_icon" {
+                        Utils.setTab3Icon(value: Array(json.values)[i] as? String ?? "")
+                    }
+                    if Array(json.keys)[i] == "tab4_icon" {
+                        Utils.setTab4Icon(value: Array(json.values)[i] as? String ?? "")
+                    }
+                    if Array(json.keys)[i] == "indicator_tab_image" {
+                        Utils.setIndicatorTabImage(value: Array(json.values)[i] as? String ?? "")
+                    }
                 }
                 Utils.setFinishInitPrefs(value: true)
                 DispatchQueue.main.async {
@@ -1206,6 +1222,15 @@ public final class Utils {
         }
         return "0"
     }
+    public static func setIndicatorTabImage(value: String) {
+        SecureUserDefaults.shared.set(value, forKey: "indicator_tab_image")
+    }
+    public static func getIndicatorTabImage() -> String {
+        if let value: String = SecureUserDefaults.shared.value(forKey: "indicator_tab_image") {
+            return value
+        }
+        return ""
+    }
     static func setDebugBC(value: [String: String]) {
         SecureUserDefaults.shared.set(value, forKey: "debugBc")
     }

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

@@ -4215,10 +4215,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
                 return
             }
             for i in 0..<countSelected {
-                if let groupingImages = groupImages[dataMessages[i]["message_id"] as! String] {
+                if groupImages[dataMessages[i]["message_id"] as! String] != nil {
                     var tempData = dataMessages
                     tempData.remove(at: 0)
-                    var dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
+                    let dataMessageInGrouping = (groupImages[dataMessages[i]["message_id"] as! String]!).map({ $0.dataMessage })
                     tempData.insert(contentsOf: dataMessageInGrouping, at: i)
                     dataMessages = tempData
                 }

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

@@ -991,7 +991,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                         row["video_id"] = cursorData.string(forColumnIndex: 8)
                         row["image_id"] = cursorData.string(forColumnIndex: 9)
                         row["thumb_id"] = cursorData.string(forColumnIndex: 10)
-                        row["read_receipts"] = cursorData.int(forColumnIndex: 11)
+                        row["read_receipts"] = cursorData.string(forColumnIndex: 11)
                         row["chat_id"] = cursorData.string(forColumnIndex: 12)
                         row["file_id"] = cursorData.string(forColumnIndex: 13)
                         row["attachment_flag"] = cursorData.string(forColumnIndex: 14)