sumup / sumup-ios-sdk

Other
46 stars 25 forks source link

Support for SwiftUI #107

Open ralfebert opened 3 years ago

ralfebert commented 3 years ago

When using the Sumup SDK in a SwiftUI app, the usage is a bit cumbersome, because the API assumes you have a UIViewController handy which you usually don't have in a SwiftUI app. It would be nice if the SDK would provide a SwiftUI wrapper or accessible UIViewController classes that can be wrapped with UIViewControllerRepresentable.

A workaround to make it work today - SumupView can be embedded in the SwiftUI view hierarchy to make the Sumup login/checkout controller appear:

import SumUpSDK
import SwiftUI

class SumupPaymentJob {

    let request: CheckoutRequest
    let completion: (_ paid: Bool) -> Void

    init(api_key: String, request: CheckoutRequest, completion: @escaping (_ paid: Bool) -> Void) {
        SumUpSDK.setup(withAPIKey: api_key)
        self.request = request
        self.completion = completion
    }

}

class SumupViewController: UIViewController {

    let paymentJob: SumupPaymentJob

    init(paymentJob: SumupPaymentJob) {
        self.paymentJob = paymentJob
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) not supported")
    }

    func login() {
        SumUpSDK.presentLogin(from: self, animated: false) { success, error in
            if success {
                self.purchase()
            } else {
                self.paymentJob.completion(false)
            }
        }
    }

    func purchase() {
        SumUpSDK.checkout(with: self.paymentJob.request, from: self) { result, error in
            self.paymentJob.completion(result?.success ?? false)
        }
    }

    var started = false

    override func viewWillAppear(_ animated: Bool) {
        if !self.started {
            self.started = true
            if !SumUpSDK.isLoggedIn {
                self.login()
            } else {
                self.purchase()
            }
        }
    }

}

struct SumupView: UIViewControllerRepresentable {

    let paymentJob: SumupPaymentJob

    func makeUIViewController(context: Context) -> UIViewController {
        SumupViewController(paymentJob: self.paymentJob)
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
chadmulligan commented 3 years ago

Hi Ralf, Thanks for the code, much appreciated. I am trying to invoke this from the cordova plugin, but so far I've had no luck (I am a very beginner with Swift). How would one trigger the SDK with the proper UI wrapper ? Thanks for the help