Jelajahi Sumber

update fix bugs and new request

alqindiirsyam 1 tahun lalu
induk
melakukan
86f08d82ed

+ 56 - 61
appbuilder-ios/AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -21,17 +21,6 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
     var switchSaveToGallery = UISwitch()
     var switchAutoDownload = UISwitch()
     
-    let separatorBackupRestore = UIView()
-    let separatorNotifPersonal = UIView()
-    let separatorAutoDownload = UIView()
-    let separatorVersion = UIView()
-    let separatorLogin = UIView()
-    let separatorCFBTop = UIView()
-    let separatorCFBBot = UIView()
-    let separatorCYATop = UIView()
-    let separatorCYABot = UIView()
-    let separatorBCABot = UIView()
-    
     @IBOutlet weak var tableView: UITableView!
     @IBOutlet weak var backgroundImage: UIImageView!
     
@@ -90,16 +79,6 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
     }
 
     public override func viewWillDisappear(_ animated: Bool) {
-        separatorBackupRestore.removeFromSuperview()
-        separatorNotifPersonal.removeFromSuperview()
-        separatorAutoDownload.removeFromSuperview()
-        separatorVersion.removeFromSuperview()
-        separatorLogin.removeFromSuperview()
-        separatorCFBTop.removeFromSuperview()
-        separatorCFBBot.removeFromSuperview()
-        separatorCYATop.removeFromSuperview()
-        separatorCYABot.removeFromSuperview()
-        separatorBCABot.removeFromSuperview()
         if ViewController.isExpandButton {
             ViewController.expandButton()
         }
@@ -189,8 +168,12 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 if !isChangeProfile {
                     Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()))
                 } else if isChangeProfile {
-                    Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.clockwise.icloud"), title: "Backup & Restore".localized()))
-                    Item.menus["Personal"]?.insert(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()), at: 1)
+                    if Nexilis.checkingAccess(key: "backup_restore") {
+                        Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.clockwise.icloud"), title: "Backup & Restore".localized()))
+                    }
+                    if Utils.getLimitValidTrans() == "1" {
+                        Item.menus["Personal"]?.insert(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()), at: 1)
+                    }
                 }
                 let image = cursorUser.string(forColumnIndex: 1)
                 if image != nil {
@@ -302,7 +285,9 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
             Item(icon: UIImage(named: "pb_powered_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), title: "Powered by Nexilis".localized()),
         ]
         if isChangeProfile {
-            Item.menus["Version"]?.insert(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()), at: 0)
+            if Nexilis.checkingAccess(key: "logout"){
+                Item.menus["Version"]?.insert(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()), at: 0)
+            }
         }
     }
     
@@ -463,10 +448,6 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
         return Item.sections.count
     }
     
-    public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        return 1
-    }
-    
     public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         return Item.menuFor(section: section).count
     }
@@ -498,42 +479,18 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 cell.accessoryType = .disclosureIndicator
             case "Sign-Up/Sign-In".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorLogin.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorLogin)
             case "Configure Floating Button".localized():
                 cell.accessoryType = .disclosureIndicator
-                if !isChangeProfile || Utils.getEnableMobileBuilder() != "1" {
-                    separatorCFBTop.removeFromSuperview()
-                    cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCFBTop)
-                }
-                separatorCFBBot.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCFBBot)
             case "Notification Message(s)".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorNotifPersonal.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorNotifPersonal)
             case "Backup & Restore".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorBackupRestore.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorBackupRestore)
             case "Validation Transaction Limit".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Create Your Own App".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorCYATop.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCYATop)
-                if !Nexilis.showButtonFB && !Utils.getIsLoadThemeFromOther() {
-                    separatorCYABot.removeFromSuperview()
-                    cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCYABot)
-                }
-            case "Back to Company App".localized():
-                if !Nexilis.showButtonFB {
-                    separatorBCABot.removeFromSuperview()
-                    cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorBCABot)
-                }
             case "Notification Message(s) Group".localized():
                 cell.accessoryType = .disclosureIndicator
-//            case "Logout".localized():
             case "Change Admin / Internal Password".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Change Language".localized():
@@ -551,21 +508,12 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 accessoryButton.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
                 accessoryButton.contentMode = .scaleAspectFit
                 cell.accessoryView = accessoryButton as UIView
-                if !isChangeProfile {
-                    separatorVersion.removeFromSuperview()
-                    cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorVersion)
-                }
             case "Vibrate Mode".localized():
                 cell.accessoryView = switchVibrateMode
             case "Save to Gallery".localized():
                 cell.accessoryView = switchSaveToGallery
             case "Auto Download".localized():
                 cell.accessoryView = switchAutoDownload
-                separatorAutoDownload.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorAutoDownload)
-            case "Sign-Out".localized():
-                separatorVersion.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorVersion)
             default:
                 content.secondaryText = nil
             }
@@ -574,6 +522,53 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
         return cell
     }
     
+    public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+        let footerView = UIView()
+        if section != 3 {
+            footerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            footerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: footerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: footerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: footerView.bottomAnchor)
+            ])
+        }
+        return footerView
+    }
+    
+    public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        let headerView = UIView()
+        if (section == 2 && Item.menus["Config"]!.count > 0) || section == 3 {
+            headerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            headerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: headerView.bottomAnchor)
+            ])
+        }
+        return headerView
+    }
+    
+    public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        if section == 2 || section == 3 {
+            return 6
+        }
+        return 1
+    }
+    
     public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         let item = Item.menuFor(section: indexPath.section)[indexPath.row]
         if item.title == "Personal Information".localized() {

+ 0 - 6
appbuilder-ios/AppBuilder/AppBuilder/SceneDelegate.swift

@@ -55,14 +55,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
                     let isDarkMode = rootViewController.traitCollection.userInterfaceStyle == .dark
                     if isDarkMode {
                         tabBarAppearance.backgroundColor = .black.withAlphaComponent(0.7)
-                        UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
-                        let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
-                        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
                     } else {
                         tabBarAppearance.backgroundColor = .white.withAlphaComponent(0.9)
-                        UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
-                        let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
-                        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
                     }
                     if Utils.getReverseTab() == "1" {
                         tabBarAppearance.backgroundColor = .black.withAlphaComponent(0.7)

+ 12 - 1
appbuilder-ios/NexilisLite/NexilisLite/Resource/Palio.storyboard

@@ -3,7 +3,7 @@
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
         <capability name="Image references" minToolsVersion="12.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -2999,6 +2999,13 @@
                                 <color key="textColor" systemColor="systemGrayColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="icL-yb-DMM">
+                                <rect key="frame" x="40" y="399.5" width="334" height="125.5"/>
+                                <string key="text">Disclaimer : Signing up with a nickname provides full privacy since %app_name% does not know your identity, which is usually linked to your email account or mobile number. However, if you use a nickname, we will not be able to reset your password if you lose or forget it, so please keep your password secure.</string>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <color key="textColor" systemColor="systemGrayColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="RRi-TQ-BYu"/>
                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -3012,8 +3019,11 @@
                             <constraint firstItem="uMG-xq-HNf" firstAttribute="top" secondItem="RRi-TQ-BYu" secondAttribute="top" constant="40" id="Opj-Sk-O2m"/>
                             <constraint firstItem="RRi-TQ-BYu" firstAttribute="trailing" secondItem="OGC-mO-8T0" secondAttribute="trailing" constant="20" id="P6s-86-sIR"/>
                             <constraint firstItem="Q4b-oV-sHi" firstAttribute="top" secondItem="uMG-xq-HNf" secondAttribute="bottom" constant="10" id="RzA-zE-Hrr"/>
+                            <constraint firstItem="icL-yb-DMM" firstAttribute="leading" secondItem="RRi-TQ-BYu" secondAttribute="leading" constant="40" id="VGd-8t-NGv"/>
+                            <constraint firstItem="icL-yb-DMM" firstAttribute="top" secondItem="5jw-G4-iGy" secondAttribute="bottom" constant="30" id="i5h-FB-69z"/>
                             <constraint firstItem="RRi-TQ-BYu" firstAttribute="trailing" secondItem="5jw-G4-iGy" secondAttribute="trailing" constant="20" id="iNS-JR-wnP"/>
                             <constraint firstAttribute="trailingMargin" secondItem="Q4b-oV-sHi" secondAttribute="trailing" constant="20" id="kmp-rV-hmS"/>
+                            <constraint firstItem="RRi-TQ-BYu" firstAttribute="trailing" secondItem="icL-yb-DMM" secondAttribute="trailing" constant="40" id="lPZ-ru-Zxi"/>
                             <constraint firstItem="Q4b-oV-sHi" firstAttribute="leading" secondItem="j0h-JE-i7E" secondAttribute="leadingMargin" constant="20" id="p1t-77-e6w"/>
                             <constraint firstItem="RRi-TQ-BYu" firstAttribute="trailing" secondItem="kwq-ci-Qkk" secondAttribute="trailing" constant="40" id="pl1-5Z-wxf"/>
                             <constraint firstItem="OGC-mO-8T0" firstAttribute="leading" secondItem="RRi-TQ-BYu" secondAttribute="leading" constant="20" id="qxd-Nm-RjI"/>
@@ -3022,6 +3032,7 @@
                         </constraints>
                     </view>
                     <connections>
+                        <outlet property="descDisclaimer" destination="icL-yb-DMM" id="MQY-7H-oJc"/>
                         <outlet property="descSignUpSignIn" destination="kwq-ci-Qkk" id="z3Q-k3-wbp"/>
                         <outlet property="passwordField" destination="5jw-G4-iGy" id="o5r-JE-N89"/>
                         <outlet property="showPasswordButton" destination="SAR-sw-Oq9" id="xhD-bu-DFc"/>

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

@@ -208,7 +208,7 @@
 "New password min 6 character" = "Kata sandi baru min 6 karakter";
 "Successfully changed password" = "Berhasil mengubah kata sandi";
 "Please enter your registered nickname or email address to Sign-In" = "Harap masukkan nama atau alamat email kamu yang terdaftar untuk masuk";
-"Please enter your nickname or email address and your password" = "Harap masukkan nama atau alamat email kamu dan kata sandi kamu";
+"Please enter your nickname and your password" = "Harap masukkan nama dan kata sandi kamu";
 "Sign-Up/Sign-In" = "Daftar/Masuk";
 "Welcome to" = "Selamat datang di";
 "Read our Terms of Service. Tap \"Agree and Continue\" to accept Terms of Service." = "Baca syarat dan ketentuan kami. Ketuk \"Setuju dan Lanjutkan\" untuk menyetujui Persyaratan Layanan.";
@@ -370,3 +370,9 @@
 "Set a transation validation amount" = "Tetapkan jumlah validasi transaksi";
 "Any transaction over this amount will display an alert and require you to accept the alert to validate before proceeding with the transaction" = "Setiap transaksi yang melebihi jumlah ini akan menampilkan peringatan dan mengharuskan Anda menerima peringatan tersebut untuk memvalidasi sebelum melanjutkan transaksi";
 "Stay Alert, Stay Safe, Keep Clean and don't Panic. #stayhome" = "Tetap Waspada, Tetap Aman, Tetap Bersih dan jangan Panik. #tinggal di rumah";
+"Disclaimer : Signing up with a nickname provides full privacy since" = "Catatan : Mendaftar dengan nickname memberikan privasi penuh karena";
+"does not know your identity, which is usually linked to your email account or mobile number. However, if you use a nickname, we will not be able to reset your password if you lose or forget it, so please keep your password secure." = "tidak mengetahui identitasmu, yang biasanya terkait dengan akun email atau nomor telepon kamu. Namun, jika kamu menggunakan nama panggilan, kami tidak dapat mereset passwordmu jika passwordmu hilang atau kamu lupa passwordmu, jadi harap simpan passwordmu dengan aman.";
+"Failed" = "Gagal";
+"Failed, unknown user" = "Gagal, pengguna tidak dikenal";
+"Failed, blocked user" = "Gagal, pengguna telah diblokir";
+

+ 8 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/IncomingThread.swift

@@ -187,6 +187,8 @@ class IncomingThread {
             initPrefs(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.NOTIFY_TO_CALLING {
             notifyCalling(message: message)
+        } else if message.getCode() == CoreMessage_TMessageCode.CALLING {
+            sendOnlineUser(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.PAYMENT_NOTIFICATION {
             showTransactionApprovalRequest(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.LOGOUT {
@@ -306,6 +308,12 @@ class IncomingThread {
         ack(message: message)
     }
     
+    private func sendOnlineUser(message: TMessage) -> Void {
+        if let packetId = message.mBodies[CoreMessage_TMessageKey.PACKET_ID] {
+            _ = Nexilis.responseString(packetId: packetId, message: "01", timeout: 3000)
+        }
+    }
+    
     private func notifyCalling(message: TMessage) -> Void {
         let lPin = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
         if let packetId = message.mBodies[CoreMessage_TMessageKey.PACKET_ID] {

+ 38 - 9
appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -243,18 +243,31 @@ public class Nexilis: NSObject {
                     getPullGroupNoMember()
                     delegate.onSuccess(userId: me)
                     getPullDefaultCC()
-                    if showButton {
-                        DispatchQueue.main.async {
-                            var viewController = UIApplication.shared.windows.first?.rootViewController
-                            var notNull = false
-                            while !notNull {
-                                viewController = UIApplication.shared.windows.first?.rootViewController
-                                if viewController != nil && Utils.getFinishInitPrefsr() {
-                                    notNull = true
-                                }
+                    DispatchQueue.main.async {
+                        var viewController = UIApplication.shared.windows.first?.rootViewController
+                        var notNull = false
+                        while !notNull {
+                            viewController = UIApplication.shared.windows.first?.rootViewController
+                            if viewController != nil && Utils.getFinishInitPrefsr() {
+                                notNull = true
                             }
+                        }
+                        if showButton {
                             addFB(viewController: viewController!, fromMAB: fromMAB)
                         }
+                        if let rootViewController = viewController {
+                            // Check if dark mode is enabled
+                            let isDarkMode = rootViewController.traitCollection.userInterfaceStyle == .dark
+                            if isDarkMode {
+                                UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
+                                let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+                                UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
+                            } else {
+                                UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
+                                let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+                                UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
+                            }
+                        }
                     }
                     Nexilis.destroyAll()
                     if (Utils.getSetProfile() && !Utils.getFinishInitPrefsr()) || (!Utils.getForceAnonymous() && !Utils.getFinishInitPrefsr()) {
@@ -505,6 +518,7 @@ public class Nexilis: NSObject {
         DispatchQueue.global().asyncAfter(deadline: .now(), execute: {
             Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "get_feature_access")!) { data, response, error in
                 if let data = data, let responseString = String(data: data, encoding: .utf8) {
+                    Utils.setFeatureAccess(value: responseString)
                     if let jsonArray = try? JSONSerialization.jsonObject(with: responseString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
                         do {
                             let umr = jsonArray[0]["upload_max_retry"] as? Int
@@ -558,6 +572,21 @@ public class Nexilis: NSObject {
         })
     }
     
+    public static func checkingAccess(key: String) -> Bool {
+        let dataAccess = Utils.getFeatureAccess()
+        if let jsonArray = try? JSONSerialization.jsonObject(with: dataAccess.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
+            let backupRest = jsonArray[0]["backup_restore"] as? Int
+            let logout = jsonArray[0]["logout"] as? Int
+            if backupRest != nil && backupRest == 1 {
+                return true
+            }
+            if logout != nil && logout == 1 {
+                return true
+            }
+        }
+        return false
+    }
+    
     private static func getPullWorkingArea() {
         DispatchQueue.global().asyncAfter(deadline: .now(), execute: {
             if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getWorkingAreaContactCenter(), timeout: 30 * 1000), response.isOk() {

+ 19 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/Utils.swift

@@ -230,6 +230,22 @@ public final class Utils {
         UserDefaults.standard.string(forKey: "call_center") ?? "1500046"
     }
     
+    static func setValidTrans(value: String) {
+        UserDefaults.standard.set(value, forKey: "enable_valid_trans")
+    }
+
+    static func getValidTrans() -> String {
+        UserDefaults.standard.string(forKey: "enable_valid_trans") ?? "0"
+    }
+    
+    static func setFeatureAccess(value: String) {
+        UserDefaults.standard.set(value, forKey: "pb_feature_access")
+    }
+
+    static func getFeatureAccess() -> String {
+        UserDefaults.standard.string(forKey: "pb_feature_access") ?? ""
+    }
+    
     
     public static func sGetCurrentDateTime(sFormat: String!) -> String! {
         let todaysDate = NSDate()
@@ -536,6 +552,9 @@ public final class Utils {
                     if json[CoreMessage_TMessageKey.KEY] as! String == "call_center" {
                         Utils.setCallCenter(value: json[CoreMessage_TMessageKey.VALUE] as! String)
                     }
+                    if json[CoreMessage_TMessageKey.KEY] as! String == "enable_valid_trans" {
+                        Utils.setValidTrans(value: json[CoreMessage_TMessageKey.VALUE] as! String)
+                    }
                 }
             } catch {
             }

+ 56 - 64
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/SettingTableViewController.swift

@@ -20,17 +20,6 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
     var switchSaveToGallery = UISwitch()
     var switchAutoDownload = UISwitch()
     
-    let separatorBackupRestore = UIView()
-    let separatorNotifPersonal = UIView()
-    let separatorAutoDownload = UIView()
-    let separatorVersion = UIView()
-    let separatorLogin = UIView()
-    let separatorCFBTop = UIView()
-    let separatorCFBBot = UIView()
-    let separatorCYATop = UIView()
-    let separatorCYABot = UIView()
-    let separatorBCABot = UIView()
-    
     var notInTab = false
     
     var fromAPI = false
@@ -78,19 +67,6 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
     @objc func didTapExit() {
         self.dismiss(animated: true)
     }
-
-    public override func viewWillDisappear(_ animated: Bool) {
-        separatorBackupRestore.removeFromSuperview()
-        separatorNotifPersonal.removeFromSuperview()
-        separatorAutoDownload.removeFromSuperview()
-        separatorVersion.removeFromSuperview()
-        separatorLogin.removeFromSuperview()
-        separatorCFBTop.removeFromSuperview()
-        separatorCFBBot.removeFromSuperview()
-        separatorCYATop.removeFromSuperview()
-        separatorCYABot.removeFromSuperview()
-        separatorBCABot.removeFromSuperview()
-    }
     
     public override func viewDidAppear(_ animated: Bool) {
         self.navigationController?.navigationBar.topItem?.title = "Settings".localized()
@@ -151,8 +127,12 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 if !isChangeProfile {
                     Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()))
                 } else if isChangeProfile {
-                    Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.clockwise.icloud"), title: "Backup & Restore".localized()))
-                    Item.menus["Personal"]?.insert(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()), at: 1)
+                    if Nexilis.checkingAccess(key: "backup_restore") {
+                        Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.clockwise.icloud"), title: "Backup & Restore".localized()))
+                    }
+                    if Utils.getLimitValidTrans() == "1" {
+                        Item.menus["Personal"]?.insert(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()), at: 1)
+                    }
                 }
                 let image = cursorUser.string(forColumnIndex: 1)
                 if image != nil {
@@ -264,7 +244,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
             Item(icon: UIImage(named: "pb_powered_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), title: "Powered by Nexilis".localized()),
         ]
         if isChangeProfile {
-            Item.menus["Version"]?.insert(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()), at: 0)
+            if Nexilis.checkingAccess(key: "logout"){
+                Item.menus["Version"]?.insert(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()), at: 0)
+            }
         }
     }
     
@@ -300,10 +282,6 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
         return Item.sections.count
     }
     
-    public override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        return 1
-    }
-    
     public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         return Item.menuFor(section: section).count
     }
@@ -335,42 +313,18 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 cell.accessoryType = .disclosureIndicator
             case "Sign-Up/Sign-In".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorLogin.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorLogin)
             case "Configure Floating Button".localized():
                 cell.accessoryType = .disclosureIndicator
-                if !isChangeProfile || Utils.getEnableMobileBuilder() != "1" {
-                    separatorCFBTop.removeFromSuperview()
-                    cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCFBTop)
-                }
-                separatorCFBBot.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCFBBot)
             case "Notification Message(s)".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorNotifPersonal.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorNotifPersonal)
             case "Backup & Restore".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorBackupRestore.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorBackupRestore)
             case "Validation Transaction Limit".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Create Your Own App".localized():
                 cell.accessoryType = .disclosureIndicator
-                separatorCYATop.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCYATop)
-                if !Nexilis.showButtonFB {
-                    separatorCYABot.removeFromSuperview()
-                    cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorCYABot)
-                }
-            case "Back to Company App".localized():
-                if !Nexilis.showButtonFB {
-                    separatorBCABot.removeFromSuperview()
-                    cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorBCABot)
-                }
             case "Notification Message(s) Group".localized():
                 cell.accessoryType = .disclosureIndicator
-//            case "Logout".localized():
             case "Change Admin / Internal Password".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Change Language".localized():
@@ -388,21 +342,12 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 accessoryButton.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
                 accessoryButton.contentMode = .scaleAspectFit
                 cell.accessoryView = accessoryButton as UIView
-                if !isChangeProfile {
-                    separatorVersion.removeFromSuperview()
-                    cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorVersion)
-                }
             case "Vibrate Mode".localized():
                 cell.accessoryView = switchVibrateMode
             case "Save to Gallery".localized():
                 cell.accessoryView = switchSaveToGallery
             case "Auto Download".localized():
                 cell.accessoryView = switchAutoDownload
-                separatorAutoDownload.removeFromSuperview()
-                cell.addBottomBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorAutoDownload)
-            case "Sign-Out".localized():
-                separatorVersion.removeFromSuperview()
-                cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorVersion)
             default:
                 content.secondaryText = nil
             }
@@ -411,6 +356,53 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
         return cell
     }
     
+    public override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+        let footerView = UIView()
+        if section != 3 {
+            footerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            footerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: footerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: footerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: footerView.bottomAnchor)
+            ])
+        }
+        return footerView
+    }
+    
+    public override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        let headerView = UIView()
+        if (section == 2 && Item.menus["Config"]!.count > 0) || section == 3 {
+            headerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            headerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: headerView.bottomAnchor)
+            ])
+        }
+        return headerView
+    }
+    
+    public override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        if section == 2 || section == 3 {
+            return 6
+        }
+        return 1
+    }
+    
     public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         let item = Item.menuFor(section: indexPath.section)[indexPath.row]
         if item.title == "Personal Information".localized() {

+ 24 - 3
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/SignUpSignIn.swift

@@ -14,6 +14,7 @@ public class SignUpSignIn: UIViewController {
     @IBOutlet weak var usernameField: UITextField!
     @IBOutlet weak var passwordField: PasswordTextField!
     @IBOutlet weak var showPasswordButton: UIButton!
+    @IBOutlet weak var descDisclaimer: UILabel!
     
     public var isDismiss: ((String) -> ())?
     public var forceLogin = false
@@ -33,7 +34,9 @@ public class SignUpSignIn: UIViewController {
         navigationController?.navigationBar.tintColor = .white
 
         self.title = "Sign-Up/Sign-In".localized()
-        descSignUpSignIn.text = "Please enter your nickname or email address and your password".localized()
+        descSignUpSignIn.text = "Please enter your nickname and your password".localized()
+        descDisclaimer.text = "Disclaimer : Signing up with a nickname provides full privacy since".localized() + " \(Bundle.main.infoDictionary?["CFBundleName"] as! String) " + "does not know your identity, which is usually linked to your email account or mobile number. However, if you use a nickname, we will not be able to reset your password if you lose or forget it, so please keep your password secure.".localized()
+        descDisclaimer.font = UIFont.italicSystemFont(ofSize: 14)
         navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Submit".localized(), style: .plain, target: self, action: #selector(didTapSubmit(sender:)))
         
         if forceLogin {
@@ -43,7 +46,7 @@ public class SignUpSignIn: UIViewController {
         passwordField.addPadding(.right(40))
         passwordField.isSecureTextEntry = true
         showPasswordButton.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
-        usernameField.placeholder = "Your Nickname".localized() + "/" + "Email".localized()
+        usernameField.placeholder = "Your Nickname".localized()
         passwordField.placeholder = "Password".localized()
         usernameField.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
         passwordField.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
@@ -278,12 +281,30 @@ public class SignUpSignIn: UIViewController {
                             banner.show()
                         })
                     }
+                } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
+                    DispatchQueue.main.async {
+                        Nexilis.hideLoader(completion: {
+                            let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                            imageView.tintColor = .white
+                            let banner = FloatingNotificationBanner(title: "Failed, unknown user".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                            banner.show()
+                        })
+                    }
+                } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "4u" {
+                    DispatchQueue.main.async {
+                        Nexilis.hideLoader(completion: {
+                            let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                            imageView.tintColor = .white
+                            let banner = FloatingNotificationBanner(title: "Failed, blocked user".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                            banner.show()
+                        })
+                    }
                 } else if !response.isOk() {
                     DispatchQueue.main.async {
                         Nexilis.hideLoader(completion: {
                             let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
                             imageView.tintColor = .white
-                            let banner = FloatingNotificationBanner(title: "Unable to access servers. Try again later".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                            let banner = FloatingNotificationBanner(title: "Failed".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
                             banner.show()
                         })
                     }