Skip to main content
This migration guide covers significant changes in the SDK API that might affect your integration.
No custom views? If you have not overridden any SDK views or protocols, you typically only need to update the pod/package version — no code changes required.

[8.x.x] -> [9.0.0]

New iDenfy Privacy Policy View

New privacy policy view is a required step for onboarding users. PrivacyPolicyViewableV2 was completely redone: New Privacy Policy
@objc open class PrivacyPolicyViewV2: UIView, PrivacyPolicyViewableV2 {
    open weak var delegate: PrivacyPolicyViewButtonActionsDelegate?

    override public init(frame: CGRect) {
        super.init(frame: frame)
        setupConstraints()
    }

    public required convenience init?(coder _: NSCoder) {
        self.init(frame: CGRect.zero)
    }

    public var toolbar: IdenfyToolbarV2WithLanguageSelection = {
        let toolbar = IdenfyToolbarV2WithLanguageSelection(frame: .zero)
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        return toolbar
    }()

    public var scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.showsVerticalScrollIndicator = false
        return scrollView
    }()

    public var contentView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var privacyPolicyTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCommonInformationTitleFont
        label.textAlignment = .center
        label.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCommonInformationTitleTextColor
        return label
    }()

    public var privacyPolicyDescription: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCommonInformationDescriptionFont
        label.textAlignment = .center
        label.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCommonInformationDescriptionTextColor
        return label
    }()

    public var processStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.backgroundColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBackgroundColor
        stack.spacing = 0
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.clipsToBounds = true
        stack.layer.cornerRadius = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBorderRadius
        return stack
    }()

    public var processHeaderView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var processTitleLabel: UILabel = {
        let label = UILabel()
        label.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleFont
        label.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleTextColor
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    public var processArrowImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "idenfy_ic_arrow_down", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        return imageView
    }()

    public var processContentView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 16
        stack.isLayoutMarginsRelativeArrangement = true
        stack.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 16, right: 16)
        stack.isHidden = false
        return stack
    }()

    public var photoIdentityStepIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_photo_identity_step", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var photoIdentityStepTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var selfieStepIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_selfie_check_step", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var selfieStepTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var automatedVerificationStepIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_automated_verification_step", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var automatedVerificationStepTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var dataProtectionStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.backgroundColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBackgroundColor
        stack.spacing = 0
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.clipsToBounds = true
        stack.layer.cornerRadius = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBorderRadius
        return stack
    }()

    public var dataProtectionHeaderView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var dataProtectionTitleLabel: UILabel = {
        let label = UILabel()
        label.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleFont
        label.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleTextColor
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    public var dataProtectionArrowImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "idenfy_ic_arrow_down", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    public var dataProtectionContentView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 16
        stack.isLayoutMarginsRelativeArrangement = true
        stack.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 16, right: 16)
        stack.isHidden = false
        return stack
    }()

    public var secureEncryptionIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_lock", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var secureEncryptionTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var limitedAccessIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_access", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var limitedAccessTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var neverSoldIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_block_share", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var neverSoldTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var usedForVerificationIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = UIImage(named: "idenfy_ic_privacy_security", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemIconColor
        return imageView
    }()

    public var usedForVerificationTitle: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var complianceStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.backgroundColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBackgroundColor
        stack.spacing = 0
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.clipsToBounds = true
        stack.layer.cornerRadius = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardBorderRadius
        return stack
    }()

    public var complianceHeaderView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var complianceTitleLabel: UILabel = {
        let label = UILabel()
        label.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleFont
        label.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardTitleTextColor
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    public var complianceArrowImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "idenfy_ic_arrow_down", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.tintColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    public var complianceContentView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 16
        stack.isLayoutMarginsRelativeArrangement = true
        stack.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 16, right: 16)
        stack.isHidden = false
        return stack
    }()

    public var complianceDescription: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        return uilabel
    }()

    public var privacyPolicyText: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        uilabel.textAlignment = .center
        uilabel.isUserInteractionEnabled = true
        return uilabel
    }()

    public var partnerPrivacyPolicyText: UILabel = {
        let uilabel = UILabel()
        uilabel.font = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemFont
        uilabel.textColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyCardItemTextColor
        uilabel.translatesAutoresizingMaskIntoConstraints = false
        uilabel.numberOfLines = 0
        uilabel.textAlignment = .center
        uilabel.isUserInteractionEnabled = true
        return uilabel
    }()

    public var privacyPolicyAgreeButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.contentMode = .scaleToFill
        button.isUserInteractionEnabled = true
        button.contentHorizontalAlignment = .center
        button.layer.cornerRadius = IdenfyButtonsUISettingsV2.idenfyButtonCorderRadius
        button.layer.masksToBounds = true
        button.titleLabel?.font = IdenfyButtonsUISettingsV2.idenfyButtonFont
        return button
    }()

    public var loadingSpinner: LottieAnimationView = {
        let lottieView = LottieAnimationView(frame: .zero)
        lottieView.translatesAutoresizingMaskIntoConstraints = false
        if let path = Bundle(identifier: "com.idenfy.idenfyviews")?.path(forResource: "idenfy_custom_country_loader", ofType: "json") {
            lottieView.animation = LottieAnimation.filepath(path)
        }
        lottieView.contentMode = .scaleAspectFit
        lottieView.play()
        lottieView.backgroundBehavior = .pauseAndRestore
        lottieView.loopMode = .loop
        lottieView.isHidden = true
        return lottieView
    }()

    open func setupConstraints() {
        backgroundColor = IdenfyPrivacyPolicyViewUISettingsV2.idenfyPrivacyPolicyViewBackgroundColor
        setupToolbar()
        setupContinueButton()
        setupScrollView()
        setupCenterView()
        setupDataProtectionCard()
        setupProcessCard()
        setupComplianceCard()
        setupPrivacyPolicyTexts()
        setupButtonActions()
    }

    private func setupButtonActions() {
        privacyPolicyAgreeButton.addTarget(self, action: #selector(agreeButtonPressed), for: .touchUpInside)
        dataProtectionHeaderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dataProtectionHeaderViewPressed)))
        processHeaderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(processHeaderViewPressed)))
        complianceHeaderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(complianceHeaderViewPressed)))
        privacyPolicyText.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(privacyPolicyTextViewPressed)))
        partnerPrivacyPolicyText.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(partnerPrivacyPolicyTextViewPressed)))
    }

    @objc func processHeaderViewPressed() {
        delegate?.processHeaderViewPressed()
    }

    @objc func dataProtectionHeaderViewPressed() {
        delegate?.dataProtectionHeaderViewPressed()
    }

    @objc func complianceHeaderViewPressed() {
        delegate?.complianceHeaderViewPressed()
    }

    @objc func privacyPolicyTextViewPressed() {
        delegate?.privacyPolicyTextViewPressed()
    }

    @objc func partnerPrivacyPolicyTextViewPressed() {
        delegate?.partnerPrivacyPolicyTextViewPressed()
    }

    @objc func agreeButtonPressed() {
        delegate?.agreeButtonPressed()
    }

    open func setupToolbar() {
        addSubview(toolbar)
        toolbar.leftAnchor.constraint(equalTo: safeLeftAnchor).isActive = true
        toolbar.rightAnchor.constraint(equalTo: safeRightAnchor).isActive = true
        toolbar.topAnchor.constraint(equalTo: self.safeTopAnchor).isActive = true
        toolbar.heightAnchor.constraint(equalToConstant: IdenfyToolbarUISettingsV2.idenfyToolbarHeight).isActive = true
    }

    open func setupScrollView() {
        addSubview(scrollView)
        scrollView.topAnchor.constraint(equalTo: toolbar.bottomAnchor).isActive = true
        scrollView.leftAnchor.constraint(equalTo: safeLeftAnchor).isActive = true
        scrollView.rightAnchor.constraint(equalTo: safeRightAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: privacyPolicyAgreeButton.topAnchor, constant: -8).isActive = true

        scrollView.addSubview(contentView)
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
        contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
        contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
    }

    open func setupCenterView() {
        contentView.addSubview(privacyPolicyTitle)
        privacyPolicyTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true
        privacyPolicyTitle.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        privacyPolicyTitle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 24).isActive = true

        contentView.addSubview(privacyPolicyDescription)
        privacyPolicyDescription.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true
        privacyPolicyDescription.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        privacyPolicyDescription.topAnchor.constraint(equalTo: privacyPolicyTitle.bottomAnchor, constant: 24).isActive = true
    }

    open func setupProcessCard() {
        contentView.addSubview(processStackView)
        processStackView.topAnchor.constraint(equalTo: dataProtectionStackView.bottomAnchor, constant: 12).isActive = true
        processStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        processStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true

        processStackView.addArrangedSubview(processHeaderView)
        processStackView.addArrangedSubview(processContentView)

        processHeaderView.heightAnchor.constraint(equalToConstant: 50).isActive = true

        processHeaderView.addSubview(processTitleLabel)
        processHeaderView.addSubview(processArrowImageView)

        processArrowImageView.centerYAnchor.constraint(equalTo: processHeaderView.centerYAnchor).isActive = true
        processArrowImageView.trailingAnchor.constraint(equalTo: processHeaderView.trailingAnchor, constant: -16).isActive = true
        processArrowImageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
        processTitleLabel.centerYAnchor.constraint(equalTo: processArrowImageView.centerYAnchor).isActive = true
        processTitleLabel.leadingAnchor.constraint(equalTo: processHeaderView.leadingAnchor, constant: 16).isActive = true
        processTitleLabel.trailingAnchor.constraint(equalTo: processArrowImageView.leadingAnchor, constant: -16).isActive = true

        processContentView.addArrangedSubview(createRow(icon: photoIdentityStepIcon, label: photoIdentityStepTitle))
        processContentView.addArrangedSubview(createRow(icon: selfieStepIcon, label: selfieStepTitle))
        processContentView.addArrangedSubview(createRow(icon: automatedVerificationStepIcon, label: automatedVerificationStepTitle))
    }

    open func setupDataProtectionCard() {
        contentView.addSubview(dataProtectionStackView)
        dataProtectionStackView.topAnchor.constraint(equalTo: privacyPolicyDescription.bottomAnchor, constant: 24).isActive = true
        dataProtectionStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        dataProtectionStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true

        dataProtectionStackView.addArrangedSubview(dataProtectionHeaderView)
        dataProtectionStackView.addArrangedSubview(dataProtectionContentView)

        dataProtectionHeaderView.heightAnchor.constraint(equalToConstant: 50).isActive = true

        dataProtectionHeaderView.addSubview(dataProtectionTitleLabel)
        dataProtectionHeaderView.addSubview(dataProtectionArrowImageView)

        dataProtectionArrowImageView.centerYAnchor.constraint(equalTo: dataProtectionHeaderView.centerYAnchor).isActive = true
        dataProtectionArrowImageView.trailingAnchor.constraint(equalTo: dataProtectionHeaderView.trailingAnchor, constant: -16).isActive = true
        dataProtectionArrowImageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
        dataProtectionTitleLabel.centerYAnchor.constraint(equalTo: dataProtectionArrowImageView.centerYAnchor).isActive = true
        dataProtectionTitleLabel.leadingAnchor.constraint(equalTo: dataProtectionHeaderView.leadingAnchor, constant: 16).isActive = true
        dataProtectionTitleLabel.trailingAnchor.constraint(equalTo: dataProtectionArrowImageView.leadingAnchor, constant: -16).isActive = true

        dataProtectionContentView.addArrangedSubview(createRow(icon: secureEncryptionIcon, label: secureEncryptionTitle))
        dataProtectionContentView.addArrangedSubview(createRow(icon: limitedAccessIcon, label: limitedAccessTitle))
        dataProtectionContentView.addArrangedSubview(createRow(icon: neverSoldIcon, label: neverSoldTitle))
        dataProtectionContentView.addArrangedSubview(createRow(icon: usedForVerificationIcon, label: usedForVerificationTitle))
    }

    open func setupComplianceCard() {
        contentView.addSubview(complianceStackView)
        complianceStackView.topAnchor.constraint(equalTo: processStackView.bottomAnchor, constant: 12).isActive = true
        complianceStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        complianceStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true

        complianceStackView.addArrangedSubview(complianceHeaderView)
        complianceStackView.addArrangedSubview(complianceContentView)

        complianceHeaderView.heightAnchor.constraint(equalToConstant: 50).isActive = true

        complianceHeaderView.addSubview(complianceTitleLabel)
        complianceHeaderView.addSubview(complianceArrowImageView)

        complianceArrowImageView.centerYAnchor.constraint(equalTo: complianceHeaderView.centerYAnchor).isActive = true
        complianceArrowImageView.trailingAnchor.constraint(equalTo: complianceHeaderView.trailingAnchor, constant: -16).isActive = true
        complianceArrowImageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
        complianceTitleLabel.centerYAnchor.constraint(equalTo: complianceArrowImageView.centerYAnchor).isActive = true
        complianceTitleLabel.leadingAnchor.constraint(equalTo: processHeaderView.leadingAnchor, constant: 16).isActive = true
        complianceTitleLabel.trailingAnchor.constraint(equalTo: complianceArrowImageView.leadingAnchor, constant: -16).isActive = true

        complianceContentView.addArrangedSubview(complianceDescription)
    }

    private func setupPrivacyPolicyTexts() {
        contentView.addSubview(privacyPolicyText)
        privacyPolicyText.topAnchor.constraint(equalTo: complianceStackView.bottomAnchor, constant: 24).isActive = true
        privacyPolicyText.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        privacyPolicyText.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true

        contentView.addSubview(partnerPrivacyPolicyText)
        partnerPrivacyPolicyText.topAnchor.constraint(equalTo: privacyPolicyText.bottomAnchor, constant: 24).isActive = true
        partnerPrivacyPolicyText.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        partnerPrivacyPolicyText.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true
        partnerPrivacyPolicyText.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -24).isActive = true
    }

    open func setupContinueButton() {
        addSubview(privacyPolicyAgreeButton)
        privacyPolicyAgreeButton.rightAnchor.constraint(equalTo: safeRightAnchor, constant: -32).isActive = true
        privacyPolicyAgreeButton.leftAnchor.constraint(equalTo: safeLeftAnchor, constant: 32).isActive = true
        privacyPolicyAgreeButton.bottomAnchor.constraint(equalTo: safeBottomAnchor, constant: -16).isActive = true
        privacyPolicyAgreeButton.heightAnchor.constraint(equalToConstant: 42).isActive = true

        addSubview(loadingSpinner)
        loadingSpinner.centerYAnchor.constraint(equalTo: privacyPolicyAgreeButton.centerYAnchor).isActive = true
        loadingSpinner.leftAnchor.constraint(equalTo: privacyPolicyAgreeButton.safeLeftAnchor, constant: 16).isActive = true
        loadingSpinner.widthAnchor.constraint(equalToConstant: 25).isActive = true
        loadingSpinner.heightAnchor.constraint(equalToConstant: 25).isActive = true
    }

    private func createRow(icon: UIImageView, label: UILabel) -> UIStackView {
        let row = UIStackView(arrangedSubviews: [icon, label])
        row.axis = .horizontal
        row.spacing = 8
        row.alignment = .center
        icon.widthAnchor.constraint(equalToConstant: 22).isActive = true
        icon.heightAnchor.constraint(equalToConstant: 22).isActive = true
        return row
    }

    open func applyGradients() {
        privacyPolicyAgreeButton.applyButtonGradient(colors: [IdenfyButtonsUISettingsV2.idenfyGradientButtonColorStart.cgColor, IdenfyButtonsUISettingsV2.idenfyGradientButtonColorEnd.cgColor])
    }
}
A new color from IdenfyCommonColors is used in this view:
    @MainActor @objc public static var idenfyLightGrayColor = UIColor(hexString: "#F2F4F8")

Country & Document Selection Steps Combined Into One View

A new Country & Document selection view was added, which combines the old two views into one. The new CountryAndDocumentSelectionViewable is added: New Country & Document selection
@objc open class CountryAndDocumentSelectionView: UIView, CountryAndDocumentSelectionViewable {
    open weak var delegate: CountryAndDocumentSelectionViewButtonActionsDelegate?

    override public init(frame: CGRect) {
        super.init(frame: frame)
        setupConstraints()
    }

    public required convenience init?(coder _: NSCoder) {
        self.init(frame: CGRect.zero)
    }

    public var toolbar: IdenfyToolbarV2WithLanguageSelection = {
        let toolbar = IdenfyToolbarV2WithLanguageSelection(frame: .zero)
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        return toolbar
    }()

    private var scrollView: UIScrollView = {
        let scrollView = UIScrollView(frame: .zero)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.alwaysBounceVertical = false
        return scrollView
    }()

    private var contentView: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var countryAndDocumentSelectionTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewTitleFont
        label.textAlignment = .center
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewTitleTextColor
        return label
    }()

    public var countryAndDocumentSelectionDescription: UILabel = {
        let label = UILabel(frame: .zero)
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewDescriptionFont
        label.textAlignment = .center
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewDescriptionTextColor
        return label
    }()

    public var countrySelectionInputView: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBackgroundColor
        view.layer.cornerRadius = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionCornerRadius
        view.layer.borderWidth = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderWidth
        view.layer.borderColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderColor.cgColor
        view.layer.masksToBounds = true
        view.layer.sublayerTransform = CATransform3DMakeTranslation(10, 0, 0)
        view.isUserInteractionEnabled = true
        return view
    }()

    public var countrySelectionFlagImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFill
        imageView.isOpaque = true
        imageView.layer.masksToBounds = true
        imageView.layer.borderWidth = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewCountryFlagBorderWidth
        imageView.layer.borderColor = UIColor.black.cgColor
        return imageView
    }()

    public var countrySelectionUILabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionFont
        label.textAlignment = .left
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionTextColor
        return label
    }()

    public var countrySelectionCancelButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isOpaque = true
        button.isHidden = true
        button.isUserInteractionEnabled = true
        button.imageEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 5)
        button.tintColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionTextColor
        button.setImage(UIImage(named: "idenfy_ic_language_selection_close_button", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate), for: .normal)
        return button
    }()

    public var countrySelectionArrowIcon: UIImageView = {
        let imageView = UIImageView(frame: .zero)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.isOpaque = true
        imageView.tintColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionTextColor
        imageView.image = UIImage(named: "idenfy_ic_arrow_down", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        return imageView
    }()

    private var documentSelectionStackView: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.spacing = 8
        stackView.alignment = .fill
        stackView.distribution = .fill
        return stackView
    }()

    public var verificationMethodTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewVerificationMethodTitleFont
        label.textAlignment = .left
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewDocumentSelectionTitleTextColor
        return label
    }()

    public var digitalIdTableView: UITableView = {
        let tableView = UITableView(frame: .zero)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
        tableView.showsVerticalScrollIndicator = false
        tableView.allowsMultipleSelection = false
        tableView.isScrollEnabled = false
        tableView.contentInset = UIEdgeInsets.zero
        tableView.contentInsetAdjustmentBehavior = .never
        tableView.sectionHeaderHeight = 0
        tableView.sectionFooterHeight = 0
        tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
        tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
        return tableView
    }()

    public var documentSelectionTitleContainer: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var documentSelectionTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewPhysicalDocumentTitleFont
        label.textAlignment = .center
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewDocumentSelectionTitleTextColor
        return label
    }()

    private var documentSelectionLeftLine: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderColor
        return view
    }()

    private var documentSelectionRightLine: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderColor
        return view
    }()

    public var documentTableView: UITableView = {
        let tableView = UITableView(frame: .zero)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
        tableView.showsVerticalScrollIndicator = false
        tableView.allowsMultipleSelection = false
        tableView.isScrollEnabled = false
        tableView.contentInset = UIEdgeInsets.zero
        tableView.contentInsetAdjustmentBehavior = .never
        tableView.sectionHeaderHeight = 0
        tableView.sectionFooterHeight = 0
        tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
        tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
        return tableView
    }()

    public var continueDisabledButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.contentMode = .scaleToFill
        button.isUserInteractionEnabled = true
        button.setTitleColor(IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewContinueButtonDisabledTextColor, for: .normal)
        button.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewContinueButtonDisabledBackgroundColor
        button.contentHorizontalAlignment = .center
        button.layer.cornerRadius = IdenfyButtonsUISettingsV2.idenfyButtonCorderRadius
        button.layer.masksToBounds = true
        button.titleLabel?.font = IdenfyButtonsUISettingsV2.idenfyButtonFont
        button.isUserInteractionEnabled = false
        button.alpha = 0.4
        button.isHidden = false
        return button
    }()

    public var continueEnabledButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.contentMode = .scaleToFill
        button.isUserInteractionEnabled = true
        button.setTitleColor(IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewContinueButtonEnabledTextColor, for: .normal)
        button.contentHorizontalAlignment = .center
        button.layer.cornerRadius = IdenfyButtonsUISettingsV2.idenfyButtonCorderRadius
        button.layer.masksToBounds = true
        button.titleLabel?.font = IdenfyButtonsUISettingsV2.idenfyButtonFont
        button.isUserInteractionEnabled = true
        button.isHidden = true
        return button
    }()

    public var continueButtonSpinner: LottieAnimationView = {
        let lottieView = LottieAnimationView(frame: .zero)
        lottieView.translatesAutoresizingMaskIntoConstraints = false
        if let path = Bundle(identifier: "com.idenfy.idenfyviews")?.path(forResource: "idenfy_custom_country_loader", ofType: "json") {
            lottieView.animation = LottieAnimation.filepath(path)
        }
        lottieView.contentMode = .scaleAspectFit
        lottieView.play()
        lottieView.loopMode = .loop
        lottieView.backgroundBehavior = .pauseAndRestore
        lottieView.isHidden = true
        lottieView.applyColorTint(IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewCountryLoadingSpinnerTintColor)
        return lottieView
    }()

    open func setupConstraints() {
        backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewBackgroundColor
        setupToolbar()
        setupContinueButton()
        setupScrollView()
        setupTopTitle()
        setupCountrySelectionPicker()
        setupDocumentSelection()
        setupButtonActions()
    }

    private func setupButtonActions() {
        continueEnabledButton.addTarget(self, action: #selector(continueButtonPressed), for: .touchUpInside)
    }

    @objc func continueButtonPressed() {
        delegate?.continueButtonPressed()
    }

    private func setupToolbar() {
        addSubview(toolbar)
        toolbar.leftAnchor.constraint(equalTo: safeLeftAnchor).isActive = true
        toolbar.rightAnchor.constraint(equalTo: safeRightAnchor).isActive = true
        toolbar.topAnchor.constraint(equalTo: self.safeTopAnchor).isActive = true
        toolbar.heightAnchor.constraint(equalToConstant: IdenfyToolbarUISettingsV2.idenfyToolbarHeight).isActive = true
    }

    private func setupScrollView() {
        addSubview(scrollView)
        scrollView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        scrollView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: toolbar.bottomAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: continueEnabledButton.topAnchor, constant: -16).isActive = true

        scrollView.addSubview(contentView)
        contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
        contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
        contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
    }

    open func setupTopTitle() {
        contentView.addSubview(countryAndDocumentSelectionTitle)
        countryAndDocumentSelectionTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16).isActive = true
        countryAndDocumentSelectionTitle.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        countryAndDocumentSelectionTitle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 24).isActive = true

        contentView.addSubview(countryAndDocumentSelectionDescription)
        countryAndDocumentSelectionDescription.widthAnchor.constraint(equalTo: countryAndDocumentSelectionTitle.widthAnchor, multiplier: 0.8).isActive = true
        countryAndDocumentSelectionDescription.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        countryAndDocumentSelectionDescription.topAnchor.constraint(equalTo: countryAndDocumentSelectionTitle.bottomAnchor, constant: 16).isActive = true
    }

    open func setupCountrySelectionPicker() {
        contentView.addSubview(countrySelectionInputView)
        countrySelectionInputView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 32).isActive = true
        countrySelectionInputView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -32).isActive = true
        countrySelectionInputView.heightAnchor.constraint(equalToConstant: 50).isActive = true
        countrySelectionInputView.topAnchor.constraint(equalTo: countryAndDocumentSelectionDescription.bottomAnchor, constant: 32).isActive = true

        contentView.addSubview(countrySelectionFlagImageView)
        countrySelectionFlagImageView.leftAnchor.constraint(equalTo: countrySelectionInputView.leftAnchor, constant: 12).isActive = true
        countrySelectionFlagImageView.centerYAnchor.constraint(equalTo: countrySelectionInputView.centerYAnchor).isActive = true
        countrySelectionFlagImageView.heightAnchor.constraint(equalToConstant: 25).isActive = true
        countrySelectionFlagImageView.widthAnchor.constraint(equalToConstant: 35).isActive = true

        contentView.addSubview(countrySelectionUILabel)
        countrySelectionUILabel.leftAnchor.constraint(equalTo: countrySelectionInputView.leftAnchor, constant: 16).isActive = true
        countrySelectionUILabel.centerYAnchor.constraint(equalTo: countrySelectionInputView.centerYAnchor).isActive = true
        countrySelectionUILabel.rightAnchor.constraint(equalTo: countrySelectionInputView.rightAnchor, constant: -16).isActive = true

        contentView.addSubview(countrySelectionCancelButton)
        countrySelectionCancelButton.heightAnchor.constraint(equalToConstant: 20).isActive = true
        countrySelectionCancelButton.widthAnchor.constraint(equalToConstant: 20).isActive = true
        countrySelectionCancelButton.rightAnchor.constraint(equalTo: countrySelectionInputView.rightAnchor, constant: -16).isActive = true
        countrySelectionCancelButton.centerYAnchor.constraint(equalTo: countrySelectionInputView.centerYAnchor).isActive = true

        contentView.addSubview(countrySelectionArrowIcon)
        countrySelectionArrowIcon.heightAnchor.constraint(equalToConstant: 25).isActive = true
        countrySelectionArrowIcon.widthAnchor.constraint(equalToConstant: 25).isActive = true
        countrySelectionArrowIcon.rightAnchor.constraint(equalTo: countrySelectionInputView.rightAnchor, constant: -16).isActive = true
        countrySelectionArrowIcon.centerYAnchor.constraint(equalTo: countrySelectionInputView.centerYAnchor).isActive = true
    }

    open func setupDocumentSelection() {
        contentView.addSubview(documentSelectionStackView)
        documentSelectionStackView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 32).isActive = true
        documentSelectionStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -32).isActive = true
        documentSelectionStackView.topAnchor.constraint(equalTo: countrySelectionInputView.bottomAnchor, constant: 24).isActive = true
        documentSelectionStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true

        documentSelectionStackView.addArrangedSubview(verificationMethodTitle)
        documentSelectionStackView.addArrangedSubview(digitalIdTableView)
        documentSelectionStackView.addArrangedSubview(documentSelectionTitleContainer)
        documentSelectionStackView.addArrangedSubview(documentTableView)

        setupDocumentSelectionTitleWithLines()

        let heightConstraintDigital = digitalIdTableView.heightAnchor.constraint(greaterThanOrEqualToConstant: 56)
        heightConstraintDigital.priority = .defaultLow
        heightConstraintDigital.isActive = true

        let heightConstraint = documentTableView.heightAnchor.constraint(greaterThanOrEqualToConstant: 56)
        heightConstraint.priority = .defaultLow
        heightConstraint.isActive = true
    }

    private func setupDocumentSelectionTitleWithLines() {
        documentSelectionTitleContainer.addSubview(documentSelectionLeftLine)
        documentSelectionTitleContainer.addSubview(documentSelectionTitle)
        documentSelectionTitleContainer.addSubview(documentSelectionRightLine)

        documentSelectionLeftLine.leftAnchor.constraint(equalTo: documentSelectionTitleContainer.leftAnchor).isActive = true
        documentSelectionLeftLine.centerYAnchor.constraint(equalTo: documentSelectionTitle.centerYAnchor).isActive = true
        documentSelectionLeftLine.heightAnchor.constraint(equalToConstant: 1).isActive = true
        documentSelectionLeftLine.rightAnchor.constraint(equalTo: documentSelectionTitle.leftAnchor, constant: -8).isActive = true

        documentSelectionTitle.centerXAnchor.constraint(equalTo: documentSelectionTitleContainer.centerXAnchor).isActive = true
        documentSelectionTitle.topAnchor.constraint(equalTo: documentSelectionTitleContainer.topAnchor).isActive = true
        documentSelectionTitle.bottomAnchor.constraint(equalTo: documentSelectionTitleContainer.bottomAnchor).isActive = true

        documentSelectionRightLine.rightAnchor.constraint(equalTo: documentSelectionTitleContainer.rightAnchor).isActive = true
        documentSelectionRightLine.centerYAnchor.constraint(equalTo: documentSelectionTitle.centerYAnchor).isActive = true
        documentSelectionRightLine.heightAnchor.constraint(equalToConstant: 1).isActive = true
        documentSelectionRightLine.leftAnchor.constraint(equalTo: documentSelectionTitle.rightAnchor, constant: 8).isActive = true
    }

    open func setupContinueButton() {
        addSubview(continueEnabledButton)
        continueEnabledButton.rightAnchor.constraint(equalTo: safeRightAnchor, constant: -32).isActive = true
        continueEnabledButton.leftAnchor.constraint(equalTo: safeLeftAnchor, constant: 32).isActive = true
        continueEnabledButton.bottomAnchor.constraint(equalTo: safeBottomAnchor, constant: -24).isActive = true
        continueEnabledButton.heightAnchor.constraint(equalToConstant: 42).isActive = true

        addSubview(continueDisabledButton)
        continueDisabledButton.rightAnchor.constraint(equalTo: safeRightAnchor, constant: -32).isActive = true
        continueDisabledButton.leftAnchor.constraint(equalTo: safeLeftAnchor, constant: 32).isActive = true
        continueDisabledButton.bottomAnchor.constraint(equalTo: safeBottomAnchor, constant: -24).isActive = true
        continueDisabledButton.heightAnchor.constraint(equalToConstant: 42).isActive = true

        addSubview(continueButtonSpinner)
        continueButtonSpinner.centerYAnchor.constraint(equalTo: continueEnabledButton.centerYAnchor).isActive = true
        continueButtonSpinner.leftAnchor.constraint(equalTo: continueEnabledButton.safeLeftAnchor, constant: 16).isActive = true
        continueButtonSpinner.widthAnchor.constraint(equalToConstant: 25).isActive = true
        continueButtonSpinner.heightAnchor.constraint(equalToConstant: 25).isActive = true
    }

    open func applyGradients() {
        continueEnabledButton.applyButtonGradient(colors: [IdenfyButtonsUISettingsV2.idenfyGradientButtonColorStart.cgColor, IdenfyButtonsUISettingsV2.idenfyGradientButtonColorEnd.cgColor])
    }
}

@objc open class DocumentTypeWithCountryCell: UITableViewCell, DocumentTypeWithCountryCellViewable {

    public let leftContainerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBackgroundColor
        view.layer.borderColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderColor.cgColor
        view.layer.borderWidth = 1
        view.layer.cornerRadius = 4
        view.layer.masksToBounds = true
        return view
    }()

    public let rightContainerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBackgroundColor
        view.layer.borderColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionBorderColor.cgColor
        view.layer.borderWidth = 1
        view.layer.cornerRadius = 4
        view.layer.masksToBounds = true
        return view
    }()

    private let leftStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .horizontal
        stackView.spacing = 8
        stackView.alignment = .center
        stackView.distribution = .fill
        return stackView
    }()

    private let rightStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .horizontal
        stackView.spacing = 8
        stackView.alignment = .center
        stackView.distribution = .fill
        return stackView
    }()

    public let leftIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    public let rightIcon: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    public let leftLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionFont
        label.textAlignment = .left
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionTextColor
        return label
    }()

    public let rightLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionFont
        label.textAlignment = .left
        label.textColor = IdenfyCountryAndDocumentSelectionViewUISettingsV2.idenfyCountryAndDocumentSelectionViewItemSelectionTextColor
        return label
    }()

    public var documentLabel: UILabel {
        return leftLabel
    }

    override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }

    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    open func setupView() {
        backgroundColor = .clear

        contentView.addSubview(leftContainerView)
        leftContainerView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
        leftContainerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6).isActive = true
        leftContainerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -6).isActive = true
        leftContainerView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.48).isActive = true

        contentView.addSubview(rightContainerView)
        rightContainerView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
        rightContainerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6).isActive = true
        rightContainerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -6).isActive = true
        rightContainerView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.48).isActive = true

        // Setup left container with stack view
        leftContainerView.addSubview(leftStackView)
        leftStackView.leftAnchor.constraint(equalTo: leftContainerView.leftAnchor, constant: 12).isActive = true
        leftStackView.rightAnchor.constraint(equalTo: leftContainerView.rightAnchor, constant: -12).isActive = true
        leftStackView.topAnchor.constraint(equalTo: leftContainerView.topAnchor, constant: 8).isActive = true
        leftStackView.bottomAnchor.constraint(equalTo: leftContainerView.bottomAnchor, constant: -8).isActive = true

        let leftHeightConstraint = leftStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: 34)
        leftHeightConstraint.priority = .defaultHigh
        leftHeightConstraint.isActive = true

        // Add icon and label to left stack view
        leftStackView.addArrangedSubview(leftIcon)
        leftStackView.addArrangedSubview(leftLabel)

        leftIcon.widthAnchor.constraint(equalToConstant: 24).isActive = true
        leftIcon.heightAnchor.constraint(equalToConstant: 24).isActive = true

        // Setup right container with stack view
        rightContainerView.addSubview(rightStackView)
        rightStackView.leftAnchor.constraint(equalTo: rightContainerView.leftAnchor, constant: 12).isActive = true
        rightStackView.rightAnchor.constraint(equalTo: rightContainerView.rightAnchor, constant: -12).isActive = true
        rightStackView.topAnchor.constraint(equalTo: rightContainerView.topAnchor, constant: 8).isActive = true
        rightStackView.bottomAnchor.constraint(equalTo: rightContainerView.bottomAnchor, constant: -8).isActive = true

        let rightHeightConstraint = rightStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: 34)
        rightHeightConstraint.priority = .defaultHigh
        rightHeightConstraint.isActive = true

        // Add icon and label to right stack view
        rightStackView.addArrangedSubview(rightIcon)
        rightStackView.addArrangedSubview(rightLabel)

        rightIcon.widthAnchor.constraint(equalToConstant: 24).isActive = true
        rightIcon.heightAnchor.constraint(equalToConstant: 24).isActive = true
    }
}
New colors from IdenfyCommonColors are used in this view:
    @MainActor @objc public static var idenfyPurpleV2 = UIColor(hexString: "#734BFB")
    @MainActor @objc public static var idenfyPurpleTextV2 = UIColor(hexString: "#452D97")
    @MainActor @objc public static var idenfyBackgroundPurpleV2 = UIColor(hexString: "#EFEBFF")

Auto Country & Document Detection Feature

Along with this feature, a new card is presented in DocumentCameraViewableV2 to show detected country and supported documents for it. An updated view looks like this: New Country & Document selection
@objc open class DocumentCameraViewV2: UIView, DocumentCameraViewableV2 {
    override public init(frame: CGRect) {
        super.init(frame: frame)
        setupConstraints()
    }

    public convenience init() {
        self.init(frame: CGRect.zero)
    }

    public required convenience init?(coder _: NSCoder) {
        self.init(frame: CGRect.zero)
    }

    public lazy var cameraView: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.isOpaque = true
        view.backgroundColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraPreviewSessionBackgroundColor
        return view
    }()

    public var photoImageView: UIImageView = {
        let imageView = UIImageView(frame: .zero)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.isOpaque = true
        return imageView
    }()

    public var rectangleView: IdenfyRectangleViewV2 = {
        let view = IdenfyRectangleViewV2(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor.clear
        view.tintColor = UIColor.clear
        view.isOpaque = true
        return view
    }()

    public var rectanglePathView: IdenfyRectanglePathViewV2 = {
        let imageView = IdenfyRectanglePathViewV2(frame: .zero)
        imageView.isOpaque = true
        imageView.contentMode = .scaleToFill
        return imageView
    }()

    public var cameraSessionsButtons: CameraSessionsButtonsViewableV2 = {
        let view = CameraSessionsButtonsViewV2(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.isOpaque = true
        return view
    }()

    public var drawerContentView: DrawerContentViewableV2 = {
        let view = DrawerContentViewV2(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    public var documentCameraAlertCard: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardBackgroundColor
        view.isHidden = true
        return view
    }()

    public var documentCameraAlertCardImage: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.layer.masksToBounds = true
        imageView.image = UIImage(named: "idenfy_ic_warning_alert", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.contentMode = .scaleAspectFit
        imageView.tintColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardImageTintColor
        return imageView
    }()

    public var documentCameraAlertCardTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardTitleFont
        label.textAlignment = .left
        label.textColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardTitleColor
        return label
    }()

    public var documentCameraAcceptedDocumentsAlertCard: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAcceptedDocumentsAlertCardBackgroundColor
        view.isHidden = true
        return view
    }()

    public var documentCameraAcceptedDocumentsAlertCardTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAcceptedDocumentsAlertCardTitleFont
        label.textAlignment = .left
        label.textColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAcceptedDocumentsAlertCardTitleColor
        return label
    }()

    public var alertCardsStackView: UIStackView = {
        let stack = UIStackView(frame: .zero)
        stack.axis = .vertical
        stack.distribution = .fill
        stack.alignment = .fill
        stack.translatesAutoresizingMaskIntoConstraints = false
        return stack
    }()

    @objc private func setupConstraints() {
        setupCameraView()
        setupPhotoView()
        setupRectangleView()
        setupCameraSessionsButtons()
        setupDrawerView()
        setupAcceptedDocumentsCard()
        setupDocumentWarningCard()
        setupAlertCardsStackView()
    }

    func setupAcceptedDocumentsCard() {
        documentCameraAcceptedDocumentsAlertCard.heightAnchor.constraint(greaterThanOrEqualToConstant: 50).isActive = true

        documentCameraAcceptedDocumentsAlertCard.addSubview(documentCameraAcceptedDocumentsAlertCardTitle)
        documentCameraAcceptedDocumentsAlertCardTitle.leftAnchor.constraint(equalTo: documentCameraAcceptedDocumentsAlertCard.safeLeftAnchor, constant: 16).isActive = true
        documentCameraAcceptedDocumentsAlertCardTitle.rightAnchor.constraint(equalTo: documentCameraAcceptedDocumentsAlertCard.safeRightAnchor, constant: -24).isActive = true
        documentCameraAcceptedDocumentsAlertCardTitle.topAnchor.constraint(equalTo: documentCameraAcceptedDocumentsAlertCard.safeTopAnchor, constant: 8).isActive = true
        documentCameraAcceptedDocumentsAlertCardTitle.bottomAnchor.constraint(equalTo: documentCameraAcceptedDocumentsAlertCard.safeBottomAnchor, constant: -8).isActive = true
    }

    func setupDocumentWarningCard() {
        documentCameraAlertCard.heightAnchor.constraint(greaterThanOrEqualToConstant: 50).isActive = true

        documentCameraAlertCard.addSubview(documentCameraAlertCardImage)
        documentCameraAlertCardImage.leftAnchor.constraint(equalTo: documentCameraAlertCard.safeLeftAnchor, constant: 16).isActive = true
        documentCameraAlertCardImage.topAnchor.constraint(equalTo: documentCameraAlertCard.safeTopAnchor).isActive = true
        documentCameraAlertCardImage.bottomAnchor.constraint(equalTo: documentCameraAlertCard.safeBottomAnchor).isActive = true

        documentCameraAlertCard.addSubview(documentCameraAlertCardTitle)
        documentCameraAlertCardTitle.leftAnchor.constraint(equalTo: documentCameraAlertCard.safeLeftAnchor, constant: 50).isActive = true
        documentCameraAlertCardTitle.rightAnchor.constraint(equalTo: documentCameraAlertCard.safeRightAnchor, constant: -24).isActive = true
        documentCameraAlertCardTitle.topAnchor.constraint(equalTo: documentCameraAlertCard.safeTopAnchor, constant: 8).isActive = true
        documentCameraAlertCardTitle.bottomAnchor.constraint(equalTo: documentCameraAlertCard.safeBottomAnchor, constant: -8).isActive = true
    }

    func setupAlertCardsStackView() {
        addSubview(alertCardsStackView)
        alertCardsStackView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        alertCardsStackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -(UIScreen.main.bounds.height * ConstsIdenfyUI.idenfyCameraBottomControlsHeightMultiplier + 16)).isActive = true
        alertCardsStackView.leftAnchor.constraint(equalTo: leftAnchor, constant: 16).isActive = true
        alertCardsStackView.rightAnchor.constraint(equalTo: rightAnchor, constant: -16).isActive = true
        alertCardsStackView.spacing = 16

        alertCardsStackView.addArrangedSubview(documentCameraAlertCard)
        alertCardsStackView.addArrangedSubview(documentCameraAcceptedDocumentsAlertCard)
    }

    func setupDrawerView() {
        addSubview(drawerContentView)
        drawerContentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        drawerContentView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        drawerContentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        drawerContentView.heightAnchor.constraint(equalToConstant: CameraSessionUIHelper.getDrawerHeight()).isActive = true
    }

    func setupCameraSessionsButtons() {
        addSubview(cameraSessionsButtons)
        cameraSessionsButtons.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        cameraSessionsButtons.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        cameraSessionsButtons.topAnchor.constraint(equalTo: topAnchor).isActive = true
        cameraSessionsButtons.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }

    func setupCameraView() {
        addSubview(cameraView)
        cameraView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        cameraView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        cameraView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        cameraView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }

    func setupPhotoView() {
        cameraView.addSubview(photoImageView)
        photoImageView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
        photoImageView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor).isActive = true
        photoImageView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
        photoImageView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    }

    func setupRectangleView() {
        cameraView.addSubview(rectangleView)
        cameraView.addSubview(rectanglePathView)
        rectangleView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
        rectangleView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor).isActive = true
        rectangleView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
        rectangleView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    }
}

Updated UI for iDenfy Splash Screen

Both SplashScreenV2View and FaceAuthenticationSplashScreenV2View were redone, we use simple white and black colors without complicated iDenfy gradients: New Splash Screen
@objc open class SplashScreenV2View: UIView, SplashScreenV2Viewable {
    override public init(frame: CGRect) {
        super.init(frame: frame)
        setupConstraints()
        backgroundColor = IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewBackgroundColor
    }

    public required convenience init?(coder _: NSCoder) {
        self.init(frame: CGRect.zero)
    }

    public var idenfyLogo: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.isOpaque = true
        imageView.image = UIImage(named: "idenfy_ic_splash_screen_logo", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    var loadingSpinner: LottieAnimationView = {
        let lottieView = LottieAnimationView(frame: .zero)
        lottieView.translatesAutoresizingMaskIntoConstraints = false
        if let path = Bundle(identifier: "com.idenfy.idenfyviews")?.path(forResource: "idenfy_custom_file_loader", ofType: "json") {
            lottieView.animation = LottieAnimation.filepath(path)
        }
        lottieView.contentMode = .scaleAspectFit
        lottieView.play()
        lottieView.loopMode = .loop
        lottieView.backgroundBehavior = .pauseAndRestore
        lottieView.applyColorTint(IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewSpinnerTintColor)
        return lottieView
    }()

    public var splashScreenTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewTitleTextColor
        label.numberOfLines = 0
        label.font = IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewTitleFont
        label.textAlignment = .center
        return label
    }()

    public var splashScreenDescription: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewDescriptionTextColor
        label.numberOfLines = 0
        label.font = IdenfySplashScreenViewUISettingsV2.idenfySplashScreenViewDescriptionFont
        label.textAlignment = .center
        return label
    }()

    public var idenfyImageViewPowered: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.isOpaque = true
        imageView.image = UIImage(named: "idenfy_ic_powered_by_idenfy_v2", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    public var bottomStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .horizontal
        stackView.distribution = .fill
        stackView.alignment = .center
        stackView.spacing = 4
        return stackView
    }()

    open func setupConstraints() {
        setupViews()
    }

    @objc open func setupViews() {
        addSubview(splashScreenTitle)
        splashScreenTitle.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        splashScreenTitle.widthAnchor.constraint(equalToConstant: frame.width * 0.8).isActive = true
        splashScreenTitle.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true

        addSubview(idenfyLogo)
        idenfyLogo.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        idenfyLogo.bottomAnchor.constraint(equalTo: splashScreenTitle.topAnchor, constant: -12).isActive = true
        idenfyLogo.heightAnchor.constraint(equalToConstant: IdenfySplashScreenViewUISettingsV2.idenfySplashScreenLogoSize).isActive = true

        addSubview(loadingSpinner)
        loadingSpinner.topAnchor.constraint(equalTo: splashScreenTitle.bottomAnchor, constant: 40).isActive = true
        loadingSpinner.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        loadingSpinner.widthAnchor.constraint(equalToConstant: 53).isActive = true
        loadingSpinner.heightAnchor.constraint(equalToConstant: 53).isActive = true

        bottomStackView.addArrangedSubview(splashScreenDescription)
        bottomStackView.addArrangedSubview(idenfyImageViewPowered)

        addSubview(bottomStackView)
        bottomStackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16).isActive = true
        bottomStackView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true

        idenfyImageViewPowered.widthAnchor.constraint(equalToConstant: 35).isActive = true
        idenfyImageViewPowered.heightAnchor.constraint(equalToConstant: 120).isActive = true
        idenfyImageViewPowered.transform = CGAffineTransform(translationX: 0, y: 2)
    }
}
A new color from IdenfyCommonColors is used in this view:
    @MainActor @objc public static var idenfyBlackV2 = UIColor(hexString: "#19181D")

[8.6.x] to [8.7.5]

Updated Country Selection UISearchBar to Support iOS 26

Follow this migration guide point if you have implemented custom views of CountrySelectionViewableV2.
Update the country search bar to the following to avoid iOS 26 rounding up the corners:
    public var countrySearchBar: UISearchBar = {
        let searchBar = UISearchBar()
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        searchBar.setImage(UIImage(), for: .search, state: .normal)
        searchBar.setPositionAdjustment(UIOffset(horizontal: -10, vertical: 0), for: .search)
        searchBar.semanticContentAttribute = .forceLeftToRight
        searchBar.barTintColor = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarBackgroundColor
        searchBar.backgroundColor = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarBackgroundColor
        searchBar.backgroundImage = UIImage()
        searchBar.layer.cornerRadius = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarCorderRadius
        searchBar.layer.borderWidth = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarBorderWidth
        searchBar.layer.borderColor = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarBorderColor.cgColor
        let textField = searchBar.searchTextField
        textField.backgroundColor = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarBackgroundColor
        textField.textColor = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewCountrySearchBarTextColor
        textField.borderStyle = .none
        textField.clearButtonMode = .never
        textField.font = IdenfyCountrySelectionViewUISettingsV2.idenfyCountrySelectionViewSearchBarFont
        if #available(iOS 26.0, *) {
            textField.layer.cornerRadius = 0
            textField.layer.borderWidth = 0
            textField.layer.masksToBounds = true
        }
        return searchBar
    }()

[8.6.2] to [8.6.3]

Updated Face Capture Oval Design

Face Oval V2
Follow this migration guide point if you have implemented custom views of FaceCameraViewableV2.
A new idenfyUIViewFaceOvalV3 oval class was added, which replaces idenfyUIViewFaceOval in FaceCameraViewableV2:
    public var idenfyUIViewFaceOvalV3: IdenfyFaceOvalV3? = {
        let view = IdenfyFaceOvalV3(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.isOpaque = false
        return view
    }()
    
    func setupUIViewFaceOval() {
        if let unwrappedIdenfyUIViewFaceOvalV3 = idenfyUIViewFaceOvalV3 {
            addSubview(unwrappedIdenfyUIViewFaceOvalV3)
            unwrappedIdenfyUIViewFaceOvalV3.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
            unwrappedIdenfyUIViewFaceOvalV3.bottomAnchor.constraint(equalTo: cameraSessionsButtons.idenfyUIViewContainerOfButtons.topAnchor).isActive = true
            let top = CameraSessionUIHelper.getDrawerHeight()
            unwrappedIdenfyUIViewFaceOvalV3.topAnchor.constraint(equalTo: topAnchor, constant: top).isActive = true
            unwrappedIdenfyUIViewFaceOvalV3.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
            unwrappedIdenfyUIViewFaceOvalV3.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
            unwrappedIdenfyUIViewFaceOvalV3.setNeedsDisplay()
        }
    }
The idenfyUIViewFaceOval is still available but deprecated and will be removed in the future.

[8.5.x] to [8.6.0]

Added Realtime Blur Glare Detection in Document Capture

Follow this migration guide point if you have implemented custom views of DocumentCameraViewableV2.
With the latest realtime blur glare detection feature, a warning alert card was added to DocumentCameraViewableV2:
    public var documentCameraAlertCard: UIView = {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardBackgroundColor
        view.isHidden = true
        return view
    }()

    public var documentCameraAlertCardImage: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.layer.masksToBounds = true
        imageView.image = UIImage(named: "idenfy_ic_warning_alert", in: Bundle(identifier: "com.idenfy.idenfyviews"), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
        imageView.contentMode = .scaleAspectFit
        imageView.tintColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardImageTintColor
        return imageView
    }()

    public var documentCameraAlertCardTitle: UILabel = {
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.font = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardTitleFont
        label.textAlignment = .left
        label.textColor = IdenfyDocumentCameraSessionUISettingsV2.idenfyDocumentCameraAlertCardTitleColor
        return label
    }()

[8.5.x] to [8.5.7]

KYC Questionnaire FILE and IMAGE Questions Merged

ImageQuestionCell has been removed:
    .withImageQuestionCellView(ImageQuestionCell.self)

[8.4.x] to [8.5.0]

Added Face Detection Progress View to the Camera Drawer

Follow this migration guide point if you have implemented custom views of DrawerContentViewableV2.
With the latest face authentication auto capture feature, a progress view was added to DrawerContentViewableV2:
    public var faceDetectionProgressView: UIProgressView = {
        let progressView = UIProgressView(frame: .zero)
        progressView.translatesAutoresizingMaskIntoConstraints = false
        progressView.progressTintColor = IdenfyInstructionAlertUISettigsV2.idenfyInstructionAlertProgressBarFillColor
        progressView.trackTintColor = UIColor.clear
        progressView.isHidden = true
        return progressView
    }()
    
    ...
    
    open func setupProgressView() {
        addSubview(faceDetectionProgressView)
        faceDetectionProgressView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        faceDetectionProgressView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        faceDetectionProgressView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        faceDetectionProgressView.heightAnchor.constraint(equalToConstant: 3).isActive = true
    }

[8.3.x] to [8.4.0]

Removed Dynamic OnBoarding View

.withOnBoardingViewType(.multipleDynamic) option is no longer available in IdenfyUISettingsV2.
Follow this migration guide point if you have implemented custom views of DynamicCameraOnBoardingViewableV2.
The IdenfyViewsBuilderV2 will no longer have a .withDynamicCameraOnBoardingView option. Use .withStaticCameraOnBoardingView viewable instead. You can check new, fully implemented views in the sample application. The IdenfyDynamicCameraOnBoardingViewUISettingsV2 class has been removed. The static onBoarding view has its own IdenfyStaticCameraOnBoardingViewUISettingsV2 class.

[8.2.x] to [8.3.0]

Removed Instructions Drawer Option from Camera View

The instructions drawer has been removed. The top drawer will remain static as if instructions were disabled, and will only hold camera descriptions and the app bar. .withInstructions(IdenfyInstructionsType.drawer) option is no longer available in IdenfyUIBuilderV2.
Follow this migration guide point if you have implemented custom views of DrawerContentViewableV2, DocumentCameraViewableV2 or FaceCameraViewableV2.
The IdenfyViewsBuilderV2 will no longer have a .withDrawerContentView option. However, DocumentCameraViewableV2 and FaceCameraViewableV2 now include the DrawerContentViewableV2 view, which you can easily override:
    public var drawerContentView: DrawerContentViewableV2 = {
        let view = DrawerContentViewV2(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    @objc private func setupConstraints() {
        ...
        setupDrawerView()
    }
    
    func setupDrawerView() {
        addSubview(drawerContentView)
        drawerContentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        drawerContentView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        drawerContentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        drawerContentView.heightAnchor.constraint(equalToConstant: CameraSessionUIHelper.getDrawerHeight()).isActive = true
    }
The setupUIViewFaceOval() function of FaceCameraViewV2 has been refactored with a helper function to get the drawer height:
    func setupUIViewFaceOval() {
        addSubview(idenfyUIViewFaceOval)
        idenfyUIViewFaceOval.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        idenfyUIViewFaceOval.bottomAnchor.constraint(equalTo: cameraSessionsButtons.idenfyUIViewContainerOfButtons.topAnchor, constant: -16).isActive = true
        var top = CameraSessionUIHelper.getDrawerHeight()
        // adding more for better margin
        top += 16
        idenfyUIViewFaceOval.topAnchor.constraint(equalTo: topAnchor, constant: top).isActive = true
        idenfyUIViewFaceOval.widthAnchor.constraint(equalTo: idenfyUIViewFaceOval.heightAnchor, multiplier: 0.7).isActive = true
    }
The DrawerContentViewableV2 protocol has changed:
public protocol DrawerContentViewableV2: UIView {
    var delegate: CameraSessionDrawerDelegate? { get set }
    var toolbar: IdenfyToolbarV2CameraSession { get }
    var infoLabel: UILabel { get }
    var descriptionLabelV2: UILabel { get }
    var faceDetectionAlertImage: UIImageView { get }
}
As well as the CameraSessionDrawerDelegate:
public protocol CameraSessionDrawerDelegate: AnyObject {
    func backButtonPressedAction()
    func toggleFlashButtonPressedAction()
    func instructionDialogButtonPressedAction()
}
You can check new, fully implemented views in the sample application. All colors and UI customizations related to the instructions drawer have been removed. See the updated UI customization files.

After Capturing Photos, Camera Results View Will Appear Instantly

Since the camera results view will appear instantly, it will show a loading spinner while the photo loads.
Follow this migration guide point if you have implemented custom views of CameraResultViewableV2.
The CameraResultViewableV2 now has an additional photoResultDetailsSpinner view you must implement:
    public var photoResultDetailsSpinner: LottieAnimationView = {
        let lottieView = LottieAnimationView(frame: .zero)
        lottieView.translatesAutoresizingMaskIntoConstraints = false
        if let path = Bundle(identifier: "com.idenfy.idenfyviews")?.path(forResource: "idenfy_custom_animation_photo_result_loading_indicator", ofType: "json") {
            lottieView.animation = LottieAnimation.filepath(path)
        }
        lottieView.contentMode = .scaleAspectFit
        lottieView.play()
        lottieView.loopMode = .loop
        lottieView.backgroundBehavior = .pauseAndRestore
        lottieView.alpha = 0.6
        lottieView.isHidden = true
        return lottieView
    }()
Find fully implemented views in the sample application.

Changed Photo Cropping to Preserve Higher Resolution

The position of the document camera rectangle has been changed to match the logic of the Android SDK. Now the x position will be 0.05 * screen width. The CameraSessionsButtonsViewV2 height multiplier has been moved to a constant. It affects picture cropping. Make sure you change the height of idenfyUIViewContainerOfButtons by changing the idenfyCameraBottomControlsHeightMultiplier constant:
    /**
     idenfyCameraBottomControlsHeightMultiplier is used in photo cropping,
     make sure you change the height of idenfyUIViewContainerOfButtons by changing the idenfyCameraBottomControlsHeightMultiplier constant
     */
    open func setupUIViewContainerOfButtons() {
        addSubview(idenfyUIViewContainerOfButtons)
        idenfyUIViewContainerOfButtons.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        idenfyUIViewContainerOfButtons.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        idenfyUIViewContainerOfButtons.heightAnchor.constraint(equalTo: heightAnchor, multiplier: ConstsIdenfyUI.idenfyCameraBottomControlsHeightMultiplier).isActive = true
        idenfyUIViewContainerOfButtons.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }
Find fully implemented views in the sample application.