I am attempting to implement a custom login UI with the AWS Amplify framework. I have successfully implemented the signIn() function, as follows:
public func signIn(username: String, password: String) {
_ = Amplify.Auth.signIn(username: username, password: password) { result in
switch result {
case .success(_):
print("Sign in succeeded")
// nothing else required, the event HUB will trigger the UI refresh
case .failure(let error):
print("Sign in failed \(error)")
// in real life present a message to the user
}
}
}
The above code has been placed in my AppDelegate file. Now what I would like to be able to do is to display a message to the user in my Login view when the sign has failed, but I do not know how to pass the error from the signIn() function into the login view. Here is the relevant part of my Login view class:
let app = UIApplication.shared.delegate as! AppDelegate
self.phoneField?.bindUserInputToPhoneNumber()
self.deleteWhitespaceAndParensFromUserInput()
app.signIn(username: self.phoneNumber, password: self.password)
Any help would be greatly appreciated.
The easiest way is to create some kind of model object that will hold this data for you. You can start with an ObservableObject
that you will pass to your root ContentView
(if you're continuining to use this from the template):
final class Model: ObservableObject {
struct AuthStatus {
case unknown
case loggedIn(User) // or whatever your auth object/struct etc. is
case error(Error)
}
@Published var authStatus: AuthStatus = .unknown
}
Now you can pass this to your ContentView
a couple different ways, but one of the nicest for this kind of global state, is EnvironmentObject
. Since you mentioned an AppDelegate
, i'm assuming you're not using the new SwiftUI only app lifecycle code, which means you're using UIHostingController
. Add the following in AppDelegate
.
var window: UIWindow?
var model: Model = .init()
And then this should go in applicationDidFinishLaunching
where you set up your root view controller.
window?.rootViewController = UIHostingController(root:
ContentView()
.environmentObject(model)
)
Now your content view can just declare it wants this environment object:
struct ContentView: View {
@EnvironmentObject private var model: Model // swiftui will resolve this for you
var body: some View {
Text("Auth status: \(model.authStatus)")
}
}
If you want to more easily differentiate errors etc, you may want to create an additional @Published
var in your Model instead of combining then into an enum
as I have done here.