Bläddra i källkod

add dialog and add transaction limit

alqindiirsyam 1 år sedan
förälder
incheckning
e1c70e38d0

+ 8 - 1
appbuilder-ios/AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -182,6 +182,7 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                     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"]?.append(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()))
                     Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()))
                 }
                 let image = cursorUser.string(forColumnIndex: 1)
@@ -386,6 +387,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 cell.addTopBorder(with: .lightGray.withAlphaComponent(0.5), andWidth: 1, view: separatorNotifPersonal)
             case "Backup & Restore".localized():
                 cell.accessoryType = .disclosureIndicator
+            case "Validation Transaction Limit".localized():
+                cell.accessoryType = .disclosureIndicator
             case "Notification Message(s) Group".localized():
                 cell.accessoryType = .disclosureIndicator
 //            case "Logout".localized():
@@ -401,7 +404,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 let accessoryButton = UIButton(type: .custom)
                 accessoryButton.setTitle(UIApplication.appVersion, for: .normal)
                 accessoryButton.setTitleColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .black, for: .normal)
-                accessoryButton.contentHorizontalAlignment = .right;
+                accessoryButton.titleLabel?.font = .systemFont(ofSize: 18)
+                accessoryButton.contentHorizontalAlignment = .right
                 accessoryButton.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
                 accessoryButton.contentMode = .scaleAspectFit
                 cell.accessoryView = accessoryButton as UIView
@@ -701,6 +705,9 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
             viewConfigureFB.modalTransitionStyle = .crossDissolve
             viewConfigureFB.modalPresentationStyle = .custom
             self.present(viewConfigureFB, animated: true)
+        } else if item.title == "Validation Transaction Limit".localized() {
+            let controller = ValidationTransactionLimit()
+            navigationController?.show(controller, sender: nil)
         }
     }
     

+ 4 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings

@@ -345,3 +345,7 @@
 "Early Threat Detection" = "Deteksi Ancaman Dini";
 "Emergency Data Control" = "Mengontrol Data Penting";
 "Please feel free to contact us for more information." = "Jangan ragu untuk menghubungi kami untuk informasi lebih lanjut.";
+"Transaction Approval Request" = "Permintaan Persetujuan Transaksi";
+"We have detected a" = "Kami mendeteksi adanya";
+"transaction using credit card no. XXXX-XXXX-XXXX-1234 on" = "transaksi menggunakan kartu kredit dengan no. XXXX-XXXX-XXXX-1234 pada";
+"Before processing your payment, kindly verify and confirm the transaction details." = "Sebelum memproses pembayaran anda, silakan verifikasi dan konfirmasi detail transaksi.";

+ 2 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageCode.swift

@@ -769,4 +769,6 @@ public class CoreMessage_TMessageCode {
     public static let CANCEL_CALL_NOTIFICATION = "CCN";
     
     public static let FEATURE_ACCESS_ALL = "FA02";
+    
+    public static let PAYMENT_NOTIFICATION = "PAY";
 }

+ 2 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageKey.swift

@@ -485,4 +485,6 @@ public class CoreMessage_TMessageKey {
     
     public static let IS_ENABLED_ANONYMOUS = "A999";
     
+    public static let TOTAL_PAYMENT = "TPM";
+    
 }

+ 6 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/Extension.swift

@@ -1037,6 +1037,12 @@ extension UIButton {
         self.actionHandleBlock(action: action)
         self.addTarget(self, action: #selector(self.triggerActionHandleBlock), for: control)
     }
+    
+    public func setImageRightOfText(image: UIImage?, for state: UIControl.State) {
+        self.setImage(image, for: state)
+        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: -((image?.size.width ?? 0) + 5), bottom: 0, right: (image?.size.width ?? 0))
+        self.imageEdgeInsets = UIEdgeInsets(top: 10, left: (self.titleLabel?.frame.size.width ?? 0) + 90, bottom: 10, right: -((self.titleLabel?.frame.size.width ?? 0) + 5))
+    }
 }
 
 extension UINavigationController {

+ 25 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/IncomingThread.swift

@@ -187,7 +187,9 @@ class IncomingThread {
             initPrefs(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.NOTIFY_TO_CALLING {
             notifyCalling(message: message)
-        } else {
+        } else if message.getCode() == CoreMessage_TMessageCode.PAYMENT_NOTIFICATION {
+            showTransactionApprovalRequest(message: message)
+        }  else {
             //print("unprocessed code", message.getCode())
             ack(message: message)
         }
@@ -199,6 +201,28 @@ class IncomingThread {
     /**
      *
      */
+    
+    private func showTransactionApprovalRequest(message: TMessage) -> Void {
+        let limit = Utils.getLimitValidTrans()
+        let totalPayment = message.getBody(key: CoreMessage_TMessageKey.TOTAL_PAYMENT, default_value: limit)
+        
+        if Int64(totalPayment) ?? 0 > Int64(limit) ?? 0 {
+            let dialog = DialogTransactionApproval()
+            dialog.modalTransitionStyle = .crossDissolve
+            dialog.modalPresentationStyle = .overCurrentContext
+            dialog.valueAmount = "Rp." + totalPayment
+            if let packetId = message.mBodies[CoreMessage_TMessageKey.PACKET_ID] {
+                dialog.packetId = packetId
+                _ = Nexilis.responseString(packetId: packetId, message: "00", timeout: 3000)
+            }
+            UIApplication.shared.visibleViewController?.present(dialog, animated: true)
+        } else {
+            if let packetId = message.mBodies[CoreMessage_TMessageKey.PACKET_ID] {
+                _ = Nexilis.responseString(packetId: packetId, message: "00", 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] {

+ 239 - 6
appbuilder-ios/NexilisLite/NexilisLite/Source/Utils.swift

@@ -8,6 +8,7 @@
 
 import Foundation
 import UIKit
+import NotificationBannerSwift
 //import var CommonCrypto.CC_MD5_DIGEST_LENGTH
 //import func CommonCrypto.CC_MD5
 //import typealias CommonCrypto.CC_LONG
@@ -614,6 +615,14 @@ public final class Utils {
     public static func getConnectionID() -> String {
         UserDefaults.standard.string(forKey: "connection_id") ?? ""
     }
+    
+    public static func setLimitValidTrans(value: String) {
+        UserDefaults.standard.set(value, forKey: "pb_set_valid_trans")
+    }
+
+    public static func getLimitValidTrans() -> String {
+        UserDefaults.standard.string(forKey: "pb_set_valid_trans") ?? "100000"
+    }
 }
 public extension UIImage {
     var jpeg: Data? { jpegData(compressionQuality: 1) }  // QUALITY min = 0 / max = 1
@@ -986,17 +995,17 @@ public class DialogSignIn: UIViewController {
     }
     
     @objc func ccTapped() {
-        print("kycTapped")
+        print("ccTapped")
         self.dismiss(animated: true)
     }
     
     @objc func verifyTapped() {
-        print("tryAgainTapped")
+        print("verifyTapped")
         self.dismiss(animated: true)
     }
     
     @objc func blockTapped() {
-        print("cancelTapped")
+        print("blockTapped")
         self.dismiss(animated: true)
     }
 }
@@ -1172,17 +1181,17 @@ public class DialogSecurityShield: UIViewController {
     }
     
     @objc func ccTapped() {
-        print("kycTapped")
+        print("ccTapped")
         self.dismiss(animated: true)
     }
     
     @objc func activateTapped() {
-        print("tryAgainTapped")
+        print("activateTapped")
         self.dismiss(animated: true)
     }
     
     @objc func deactiveTapped() {
-        print("cancelTapped")
+        print("deactiveTapped")
         self.dismiss(animated: true)
     }
     
@@ -1190,3 +1199,227 @@ public class DialogSecurityShield: UIViewController {
         self.dismiss(animated: true)
     }
 }
+
+public class DialogTransactionApproval: UIViewController {
+    
+    public var valueLink = "https://hdtrack.com"
+    public var valueAmount = "$142.90"
+    public var packetId = ""
+    
+    public override func viewDidLoad() {
+        super.viewDidLoad()
+        self.view.backgroundColor = .black.withAlphaComponent(0.5)
+        
+        let container = UIView()
+        self.view.addSubview(container)
+        container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
+        container.layer.cornerRadius = 20.0
+        container.clipsToBounds = true
+        container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
+        
+        let title = UILabel()
+        title.text = "Transaction Approval Request".localized()
+        title.font = .systemFont(ofSize: 14, weight: .medium)
+        title.numberOfLines = 0
+        title.textAlignment = .center
+        title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+        container.addSubview(title)
+        title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
+        
+        let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        container.addSubview(imageWarning)
+        imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
+        
+        let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        container.addSubview(imageChat)
+        imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
+        
+        let sContent1 = "We have detected a".localized()
+        let sContent1a = "Rp."
+        let sContent2 = "transaction using credit card no. XXXX-XXXX-XXXX-1234 on".localized()
+        let sContent3 = "Before processing your payment, kindly verify and confirm the transaction details.".localized()
+        let fullString = sContent1 + " " + sContent1a + " " + formatText(valueAmount) + " " + sContent2 + " " + valueLink + ".\n\n" + sContent3
+        let contentFull = NSMutableAttributedString(string: fullString)
+        contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12), .foregroundColor: (self.traitCollection.userInterfaceStyle == .dark ? UIColor.white : UIColor.black)], range: NSRange(location: 0, length: fullString.count))
+        if let range = fullString.range(of: valueLink) {
+            let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
+            contentFull.addAttributes([.foregroundColor: UIColor.red, .underlineStyle: NSUnderlineStyle.single.rawValue, .link: URL(string: valueLink)!], range: NSRange(location: index, length: valueLink.count))
+        }
+        
+        let contentS = UILabel()
+        contentS.attributedText = contentFull
+        contentS.numberOfLines = 0
+        container.addSubview(contentS)
+        contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
+        contentS.isUserInteractionEnabled = true
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelTapped))
+        contentS.addGestureRecognizer(tapGesture)
+        
+        let buttonCC = UIButton(type: .custom)
+        let backgroundImageKYC = resizeImage(image: UIImage(named: "pb_startup_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
+        buttonCC.setBackgroundImage(backgroundImageKYC, for: .normal)
+        buttonCC.imageView?.contentMode = .scaleAspectFill
+        buttonCC.addTarget(self, action: #selector(ccTapped), for: .touchUpInside)
+        buttonCC.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        container.addSubview(buttonCC)
+        buttonCC.anchor(top: contentS.bottomAnchor, paddingTop: 10, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
+        
+        let buttonApprove = UIButton(type: .custom)
+        let backgroundImageTryAgain = resizeImage(image: UIImage(named: "pb_security_approve", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
+        buttonApprove.setBackgroundImage(backgroundImageTryAgain, for: .normal)
+        buttonApprove.imageView?.contentMode = .scaleAspectFill
+        buttonApprove.addTarget(self, action: #selector(approveTapped), for: .touchUpInside)
+        buttonApprove.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        container.addSubview(buttonApprove)
+        buttonApprove.anchor(top: contentS.bottomAnchor, right: buttonCC.leftAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
+        
+        let buttonReject = UIButton(type: .custom)
+        let backgroundImageCancel = resizeImage(image: UIImage(named: "pb_security_reject", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
+        buttonReject.setBackgroundImage(backgroundImageCancel, for: .normal)
+        buttonReject.imageView?.contentMode = .scaleAspectFill
+        buttonReject.addTarget(self, action: #selector(rejectTapped), for: .touchUpInside)
+        buttonReject.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        container.addSubview(buttonReject)
+        buttonReject.anchor(top: contentS.bottomAnchor, left: buttonCC.rightAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
+        
+        let footer = UILabel()
+        footer.text = "We value your security".localized()
+        footer.font = .systemFont(ofSize: 12)
+        footer.textColor = .gray
+        footer.numberOfLines = 0
+        container.addSubview(footer)
+        footer.anchor(top: buttonReject.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
+        
+    }
+    
+    @objc func ccTapped() {
+        print("ccTapped")
+        self.dismiss(animated: true)
+    }
+    
+    @objc func approveTapped() {
+        print("approveTapped")
+//        _ = Nexilis.responseString(packetId: packetId, message: "00", timeout: 3000)
+        self.dismiss(animated: true)
+    }
+    
+    @objc func rejectTapped() {
+        print("rejectTapped")
+//        _ = Nexilis.responseString(packetId: packetId, message: "00", timeout: 3000)
+        self.dismiss(animated: true)
+    }
+    
+    @objc func labelTapped(sender: UITapGestureRecognizer) {
+        guard let url = URL(string: valueLink) else { return }
+        UIApplication.shared.open(url)
+    }
+    
+    func formatText(_ s: String) -> String {
+        let text = s
+        if text.isEmpty { return "" }
+        
+        let cleanString = text.replacingOccurrences(of: "[^\\d]", with: "", options: .regularExpression)
+        
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        formatter.locale = Locale(identifier: "en_US")
+        let formattedString = formatter.string(from: NSNumber(value: Int(cleanString)!)) ?? ""
+        
+        return formattedString
+    }
+}
+
+public class ValidationTransactionLimit: UIViewController, UITextFieldDelegate {
+    var textField = UITextField()
+    var formatter = NumberFormatter()
+    
+    public override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        let title = UILabel()
+        title.text = "Set a transation validation amount".localized()
+        title.font = .systemFont(ofSize: 18, weight: .medium)
+        title.numberOfLines = 0
+        title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
+        self.view.addSubview(title)
+        title.anchor(top: self.view.safeAreaLayoutGuide.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 10, paddingLeft: 20, paddingRight: 20)
+        
+        let content = UILabel()
+        content.text = "Any transaction over this amount will display an alert and require you to accept the alert to validate before proceeding with the transaction".localized()
+        content.font = .systemFont(ofSize: 14)
+        content.numberOfLines = 0
+        content.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
+        self.view.addSubview(content)
+        content.anchor(top: title.bottomAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20)
+        
+        self.view.addSubview(textField)
+        textField.anchor(top: content.bottomAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20, height: 40)
+        textField.textAlignment = .center
+        textField.keyboardType = .numberPad
+        textField.layer.borderWidth = 1
+        textField.layer.borderColor = UIColor.gray.cgColor
+        textField.layer.cornerRadius = 10
+        textField.clipsToBounds = true
+        textField.text = formatText(Utils.getLimitValidTrans())
+        
+        textField.delegate = self
+        
+    }
+    
+    public override func viewDidAppear(_ animated: Bool) {
+        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        
+        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Submit".localized(), style: .plain, target: self, action: #selector(submit))
+        
+        let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16.0), NSAttributedString.Key.foregroundColor: UIColor.white]
+        let navBarAppearance = UINavigationBarAppearance()
+        navBarAppearance.configureWithOpaqueBackground()
+        navBarAppearance.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : UIColor.mainColor
+        navBarAppearance.titleTextAttributes = attributes
+        navigationController?.navigationBar.standardAppearance = navBarAppearance
+        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
+        self.navigationController?.navigationBar.topItem?.title = "Validation Transaction Limit".localized()
+        self.navigationController?.navigationBar.setNeedsLayout()
+        self.title = "Validation Transaction Limit".localized()
+    }
+    
+    @objc func submit() {
+        if !textField.text!.isEmpty {
+            var text = textField.text!
+            text = text.replacingOccurrences(of: ",", with: "", options: .regularExpression)
+            Utils.setLimitValidTrans(value: text)
+            let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+            imageView.tintColor = .white
+            let banner = FloatingNotificationBanner(title: "Successfully changed".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
+            banner.show()
+            self.navigationController?.popViewController(animated: true)
+        }
+    }
+    
+    public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+        guard string != "\n" else {
+           return true
+        }
+        let currentText = textField.text ?? ""
+        let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
+        let formattedNumber = formatText(newText)
+        if formattedNumber.count <= 13 {
+            textField.text = formattedNumber
+        }
+       return false
+    }
+
+    func formatText(_ s: String) -> String {
+        let text = s
+        if text.isEmpty { return "" }
+        
+        let cleanString = text.replacingOccurrences(of: "[^\\d]", with: "", options: .regularExpression)
+        
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        formatter.locale = Locale(identifier: "en_US")
+        let formattedString = formatter.string(from: NSNumber(value: Int(cleanString)!)) ?? ""
+        
+        return formattedString
+    }
+}