import Foundation import MyIdSDK import UIKit /// Translates the JS payload into the SDK's own config objects. /// /// A property is assigned only when its key is present, so an omitted option /// keeps whatever default `MyIdConfig()` / `MyIdAppearance()` already set rather /// than being overwritten with a value invented here. /// /// Unrecognised enum strings fall back to the SDK default instead of throwing — /// a typo should not hard-fail a verification the user already started. enum MyidSdkConfigBuilder { static func makeConfig( from dictionary: NSDictionary, appearance appearanceDictionary: NSDictionary ) -> MyIdConfig { let config = MyIdConfig() config.sessionId = dictionary.string(for: "sessionId") config.clientHash = dictionary.string(for: "clientHash") config.clientHashId = dictionary.string(for: "clientHashId") if let minAge = dictionary.number(for: "minAge") { config.minAge = minAge.intValue } if let distance = dictionary.number(for: "distance") { config.distance = distance.floatValue } if let showErrorScreen = dictionary.number(for: "showErrorScreen") { config.showErrorScreen = showErrorScreen.boolValue } if let environment = dictionary.enumValue(for: "environment") { config.environment = environment == "DEBUG" ? .debug : .production } if let entryType = dictionary.enumValue(for: "entryType") { switch entryType { case "FACE_DETECTION": config.entryType = .faceDetection case "VIDEO_IDENTIFICATION": config.entryType = .videoIdentification default: config.entryType = .identification } } if let residency = dictionary.enumValue(for: "residency") { switch residency { case "USER_DEFINED": config.residency = .userDefined case "NON_RESIDENT": config.residency = .nonResident default: config.residency = .resident } } if let locale = dictionary.enumValue(for: "locale") { switch locale { case "ENGLISH": config.locale = .english case "RUSSIAN": config.locale = .russian // UZBEK_CYRILLIC, KARAKALPAK and TAJIK exist on Android only. default: config.locale = .uzbek } } if let cameraShape = dictionary.enumValue(for: "cameraShape") { config.cameraShape = cameraShape == "ELLIPSE" ? .ellipse : .circle } if let cameraSelector = dictionary.enumValue(for: "cameraSelector") { config.cameraSelector = cameraSelector == "BACK" ? .back : .front } if let presentationStyle = dictionary.enumValue(for: "presentationStyle") { config.presentationStyle = presentationStyle == "SHEET" ? .sheet : .full } if let details = dictionary["organizationDetails"] as? NSDictionary { let organizationDetails = MyIdOrganizationDetails() organizationDetails.phoneNumber = details.string(for: "phone") if let logoName = details.string(for: "logo") { organizationDetails.logo = UIImage(named: logoName) } config.organizationDetails = organizationDetails } if appearanceDictionary.count > 0 { config.appearance = makeAppearance(from: appearanceDictionary) } return config } private static func makeAppearance(from dictionary: NSDictionary) -> MyIdAppearance { let appearance = MyIdAppearance() appearance.colorPrimary = dictionary.color(for: "colorPrimary") appearance.colorOnPrimary = dictionary.color(for: "colorOnPrimary") appearance.colorError = dictionary.color(for: "colorError") appearance.colorOnError = dictionary.color(for: "colorOnError") appearance.colorOutline = dictionary.color(for: "colorOutline") appearance.colorDivider = dictionary.color(for: "colorDivider") appearance.colorSuccess = dictionary.color(for: "colorSuccess") appearance.colorButtonContainer = dictionary.color(for: "colorButtonContainer") appearance.colorButtonContainerDisabled = dictionary.color(for: "colorButtonContainerDisabled") appearance.colorButtonContent = dictionary.color(for: "colorButtonContent") appearance.colorButtonContentDisabled = dictionary.color(for: "colorButtonContentDisabled") appearance.colorScanButtonContainer = dictionary.color(for: "colorScanButtonContainer") if let cornerRadius = dictionary.number(for: "buttonCornerRadius") { appearance.buttonCornerRadius = cornerRadius.floatValue } return appearance } } private extension NSDictionary { func string(for key: String) -> String? { self[key] as? String } func number(for key: String) -> NSNumber? { self[key] as? NSNumber } /// Enum values travel as strings; normalise case so "debug" works like "DEBUG". func enumValue(for key: String) -> String? { string(for: key)?.uppercased() } func color(for key: String) -> UIColor? { guard let hex = string(for: key) else { return nil } return UIColor(myIdHex: hex) } } extension UIColor { /// Accepts `#RRGGBB` and `RRGGBB`. Returns nil for anything unparseable so a /// bad value leaves the SDK's own color in place. convenience init?(myIdHex hex: String) { var value = hex.trimmingCharacters(in: .whitespacesAndNewlines) if value.hasPrefix("#") { value.removeFirst() } guard value.count == 6 else { return nil } var rgb: UInt64 = 0 guard Scanner(string: value).scanHexInt64(&rgb) else { return nil } self.init( red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0, blue: CGFloat(rgb & 0x0000FF) / 255.0, alpha: 1.0 ) } }