mirror of
https://bitbucket.org/vendoo/vendoo_v1.0.git
synced 2025-12-25 19:57:41 +00:00
526 lines
18 KiB
Swift
526 lines
18 KiB
Swift
//
|
|
// Copyright (c) 2016 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
// [START usermanagement_view_import]
|
|
import Firebase
|
|
// [END usermanagement_view_import]
|
|
import GoogleSignIn
|
|
import FBSDKCoreKit
|
|
import FBSDKLoginKit
|
|
import TwitterKit
|
|
|
|
@objc(MainViewController)
|
|
class MainViewController: UITableViewController, GIDSignInDelegate, GIDSignInUIDelegate {
|
|
|
|
let kSectionToken = 3
|
|
let kSectionProviders = 2
|
|
let kSectionUser = 1
|
|
let kSectionSignIn = 0
|
|
|
|
enum AuthProvider {
|
|
case AuthEmail
|
|
case AuthAnonymous
|
|
case AuthFacebook
|
|
case AuthGoogle
|
|
case AuthTwitter
|
|
case AuthCustom
|
|
}
|
|
|
|
/*! @var kOKButtonText
|
|
@brief The text of the "OK" button for the Sign In result dialogs.
|
|
*/
|
|
let kOKButtonText = "OK"
|
|
|
|
/*! @var kTokenRefreshedAlertTitle
|
|
@brief The title of the "Token Refreshed" alert.
|
|
*/
|
|
let kTokenRefreshedAlertTitle = "Token"
|
|
|
|
/*! @var kTokenRefreshErrorAlertTitle
|
|
@brief The title of the "Token Refresh error" alert.
|
|
*/
|
|
let kTokenRefreshErrorAlertTitle = "Get Token Error"
|
|
|
|
/** @var kSetDisplayNameTitle
|
|
@brief The title of the "Set Display Name" error dialog.
|
|
*/
|
|
let kSetDisplayNameTitle = "Set Display Name"
|
|
|
|
/** @var kUnlinkTitle
|
|
@brief The text of the "Unlink from Provider" error Dialog.
|
|
*/
|
|
let kUnlinkTitle = "Unlink from Provider"
|
|
|
|
/** @var kChangeEmailText
|
|
@brief The title of the "Change Email" button.
|
|
*/
|
|
let kChangeEmailText = "Change Email"
|
|
|
|
/** @var kChangePasswordText
|
|
@brief The title of the "Change Password" button.
|
|
*/
|
|
let kChangePasswordText = "Change Password"
|
|
|
|
/** @var handle
|
|
@brief The handler for the auth state listener, to allow cancelling later.
|
|
*/
|
|
var handle: FIRAuthStateDidChangeListenerHandle?
|
|
|
|
func showAuthPicker(providers: [AuthProvider]) {
|
|
let picker = UIAlertController(title: "Select Provider",
|
|
message: nil,
|
|
preferredStyle: .ActionSheet)
|
|
for provider in providers {
|
|
var action : UIAlertAction
|
|
switch(provider) {
|
|
case .AuthEmail:
|
|
action = UIAlertAction(title: "Email", style: .Default, handler: { (UIAlertAction) in
|
|
self.performSegueWithIdentifier("email", sender:nil)
|
|
})
|
|
case .AuthCustom:
|
|
action = UIAlertAction(title: "Custom", style: .Default, handler: { (UIAlertAction) in
|
|
self.performSegueWithIdentifier("customToken", sender: nil)
|
|
})
|
|
case .AuthAnonymous:
|
|
action = UIAlertAction(title: "Guest", style: .Default, handler: { (UIAlertAction) in
|
|
self.showSpinner({
|
|
// [START firebase_auth_anonymous]
|
|
FIRAuth.auth()?.signInAnonymouslyWithCompletion() { (user, error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END firebase_auth_anonymous]
|
|
})
|
|
|
|
})
|
|
case .AuthFacebook:
|
|
action = UIAlertAction(title: "Facebook", style: .Default, handler: { (UIAlertAction) in
|
|
let loginManager = FBSDKLoginManager()
|
|
loginManager.logInWithReadPermissions(["email"], fromViewController: self, handler: { (result, error) in
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
} else if(result.isCancelled) {
|
|
print("FBLogin cancelled")
|
|
} else {
|
|
// [START headless_facebook_auth]
|
|
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
|
|
// [END headless_facebook_auth]
|
|
self.firebaseLogin(credential)
|
|
}
|
|
})
|
|
})
|
|
case .AuthGoogle:
|
|
action = UIAlertAction(title: "Google", style: .Default, handler: { (UIAlertAction) in
|
|
GIDSignIn.sharedInstance().clientID = FIRApp.defaultApp()?.options.clientID
|
|
GIDSignIn.sharedInstance().uiDelegate = self
|
|
GIDSignIn.sharedInstance().delegate = self
|
|
GIDSignIn.sharedInstance().signIn()
|
|
|
|
})
|
|
case .AuthTwitter:
|
|
action = UIAlertAction(title: "Twitter", style: .Default, handler: { (UIAlertAction) in
|
|
Twitter.sharedInstance().logInWithCompletion() { (session, error) in
|
|
if let session = session {
|
|
// [START headless_twitter_auth]
|
|
let credential = FIRTwitterAuthProvider.credentialWithToken(session.authToken, secret: session.authTokenSecret)
|
|
// [END headless_twitter_auth]
|
|
self.firebaseLogin(credential)
|
|
} else {
|
|
self.showMessagePrompt((error?.localizedDescription)!)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
picker.addAction(action)
|
|
}
|
|
|
|
picker.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
|
|
presentViewController(picker, animated: true, completion: nil)
|
|
|
|
}
|
|
|
|
|
|
@IBAction func didTapSignIn(sender: AnyObject) {
|
|
showAuthPicker([
|
|
AuthProvider.AuthEmail,
|
|
AuthProvider.AuthAnonymous,
|
|
AuthProvider.AuthGoogle,
|
|
AuthProvider.AuthFacebook,
|
|
AuthProvider.AuthTwitter,
|
|
AuthProvider.AuthCustom
|
|
])
|
|
}
|
|
|
|
@IBAction func didTapLink(sender: AnyObject) {
|
|
var providers = Set([
|
|
AuthProvider.AuthEmail,
|
|
AuthProvider.AuthGoogle,
|
|
AuthProvider.AuthFacebook,
|
|
AuthProvider.AuthTwitter
|
|
])
|
|
// Remove any existing providers. Note that this is not a complete list of
|
|
// providers, so always check the documentation for a complete reference:
|
|
// https://firebase.google.com/docs/auth
|
|
let user = FIRAuth.auth()?.currentUser
|
|
for info in (user?.providerData)! {
|
|
if (info.providerID == FIREmailPasswordAuthProviderID) {
|
|
providers.remove(AuthProvider.AuthEmail)
|
|
} else if (info.providerID == FIRTwitterAuthProviderID) {
|
|
providers.remove(AuthProvider.AuthTwitter)
|
|
} else if (info.providerID == FIRFacebookAuthProviderID) {
|
|
providers.remove(AuthProvider.AuthFacebook)
|
|
} else if (info.providerID == FIRGoogleAuthProviderID) {
|
|
providers.remove(AuthProvider.AuthGoogle)
|
|
}
|
|
}
|
|
showAuthPicker(Array(providers))
|
|
}
|
|
|
|
func setTitleDisplay(user: FIRUser?) {
|
|
if let name = user?.displayName {
|
|
self.navigationItem.title = "Welcome \(name)"
|
|
} else {
|
|
self.navigationItem.title = "Authentication Example"
|
|
}
|
|
}
|
|
|
|
func firebaseLogin(credential: FIRAuthCredential) {
|
|
showSpinner({
|
|
if let user = FIRAuth.auth()?.currentUser {
|
|
// [START link_credential]
|
|
user.linkWithCredential(credential) { (user, error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END link_credential]
|
|
} else {
|
|
// [START signin_credential]
|
|
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END signin_credential]
|
|
}
|
|
})
|
|
}
|
|
|
|
// [START headless_google_auth]
|
|
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError?) {
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
|
|
let authentication = user.authentication
|
|
let credential = FIRGoogleAuthProvider.credentialWithIDToken(authentication.idToken,
|
|
accessToken: authentication.accessToken)
|
|
// [START_EXCLUDE]
|
|
firebaseLogin(credential)
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END headless_google_auth]
|
|
|
|
@IBAction func didTapSignOut(sender: AnyObject) {
|
|
// [START signout]
|
|
let firebaseAuth = FIRAuth.auth()
|
|
do {
|
|
try firebaseAuth?.signOut()
|
|
} catch let signOutError as NSError {
|
|
print ("Error signing out: %@", signOutError)
|
|
}
|
|
// [END signout]
|
|
}
|
|
|
|
override func viewWillAppear(animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
handle = FIRAuth.auth()?.addAuthStateDidChangeListener() { (auth, user) in
|
|
self.setTitleDisplay(user)
|
|
self.tableView.reloadData()
|
|
}
|
|
}
|
|
|
|
override func viewWillDisappear(animated: Bool) {
|
|
super.viewWillDisappear(animated)
|
|
FIRAuth.auth()?.removeAuthStateDidChangeListener(handle!)
|
|
}
|
|
|
|
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
switch section {
|
|
case kSectionSignIn:
|
|
return 1
|
|
case kSectionUser, kSectionToken:
|
|
if FIRAuth.auth()?.currentUser != nil {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case kSectionProviders:
|
|
if let user = FIRAuth.auth()?.currentUser {
|
|
return user.providerData.count
|
|
}
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
|
let cell: UITableViewCell?
|
|
switch indexPath.section {
|
|
case kSectionSignIn:
|
|
if FIRAuth.auth()?.currentUser != nil {
|
|
cell = tableView.dequeueReusableCellWithIdentifier("SignOut")
|
|
} else {
|
|
cell = tableView.dequeueReusableCellWithIdentifier("SignIn")
|
|
}
|
|
case kSectionUser:
|
|
cell = tableView.dequeueReusableCellWithIdentifier("Profile")
|
|
let user = FIRAuth.auth()?.currentUser
|
|
let emailLabel = cell?.viewWithTag(1) as! UILabel
|
|
let userIDLabel = cell?.viewWithTag(2) as! UILabel
|
|
let profileImageView = cell?.viewWithTag(3) as! UIImageView
|
|
emailLabel.text = user?.email
|
|
userIDLabel.text = user?.uid
|
|
|
|
let photoURL = user?.photoURL
|
|
struct last {
|
|
static var photoURL: NSURL? = nil
|
|
}
|
|
last.photoURL = photoURL; // to prevent earlier image overwrites later one.
|
|
if let photoURL = photoURL {
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
|
|
let data = NSData.init(contentsOfURL: photoURL)
|
|
if let data = data {
|
|
let image = UIImage.init(data: data)
|
|
dispatch_async(dispatch_get_main_queue(), {
|
|
if (photoURL == last.photoURL) {
|
|
profileImageView.image = image
|
|
}
|
|
})
|
|
}
|
|
})
|
|
} else {
|
|
profileImageView.image = UIImage.init(named: "ic_account_circle")
|
|
}
|
|
case kSectionProviders:
|
|
cell = tableView.dequeueReusableCellWithIdentifier("Provider")
|
|
let userInfo = FIRAuth.auth()?.currentUser?.providerData[indexPath.row]
|
|
cell?.textLabel?.text = userInfo?.providerID
|
|
cell?.detailTextLabel?.text = userInfo?.uid
|
|
case kSectionToken:
|
|
cell = tableView.dequeueReusableCellWithIdentifier("Token")
|
|
default:
|
|
cell = nil
|
|
}
|
|
return cell!
|
|
}
|
|
|
|
override func tableView(tableView: UITableView, titleForDeleteConfirmationButtonForRowAtIndexPath indexPath: NSIndexPath) -> String? {
|
|
return "Unlink"
|
|
}
|
|
|
|
// Swipe to delete
|
|
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
|
|
if editingStyle == .Delete {
|
|
let providerID = FIRAuth.auth()?.currentUser?.providerData[indexPath.row].providerID
|
|
showSpinner({
|
|
// [START unlink_provider]
|
|
FIRAuth.auth()?.currentUser?.unlinkFromProvider(providerID!) { (user, error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
tableView.reloadData()
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END unlink_provider]
|
|
})
|
|
}
|
|
}
|
|
|
|
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
|
|
if indexPath.section == kSectionUser {
|
|
return 200
|
|
}
|
|
return 44
|
|
}
|
|
|
|
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
|
return 4
|
|
}
|
|
|
|
@IBAction func didTokenRefresh(sender: AnyObject) {
|
|
let action: FIRAuthTokenCallback = {(token, error) in
|
|
let okAction = UIAlertAction.init(title: self.kOKButtonText, style: .Default)
|
|
{action in print(self.kOKButtonText)}
|
|
if let error = error {
|
|
let alertController = UIAlertController.init(title: self.kTokenRefreshErrorAlertTitle,
|
|
message: error.localizedDescription, preferredStyle: .Alert)
|
|
alertController.addAction(okAction)
|
|
self.presentViewController(alertController, animated: true, completion: nil)
|
|
return
|
|
}
|
|
|
|
// Log token refresh event to Scion.
|
|
FIRAnalytics.logEventWithName("tokenrefresh", parameters: nil)
|
|
|
|
let alertController = UIAlertController.init(title: self.kTokenRefreshedAlertTitle,
|
|
message: token, preferredStyle: .Alert)
|
|
alertController.addAction(okAction)
|
|
self.presentViewController(alertController, animated: true, completion: nil)
|
|
}
|
|
// [START token_refresh]
|
|
FIRAuth.auth()?.currentUser?.getTokenForcingRefresh(true, completion: action)
|
|
// [END token_refresh]
|
|
}
|
|
|
|
/** @fn setDisplayName
|
|
@brief Changes the display name of the current user.
|
|
*/
|
|
@IBAction func didSetDisplayName(sender: AnyObject) {
|
|
showTextInputPromptWithMessage("Display Name:") { (userPressedOK, userInput) in
|
|
if let userInput = userInput {
|
|
self.showSpinner({
|
|
// [START profile_change]
|
|
let changeRequest = FIRAuth.auth()?.currentUser?.profileChangeRequest()
|
|
changeRequest?.displayName = userInput
|
|
changeRequest?.commitChangesWithCompletion() { (error) in
|
|
// [END profile_change]
|
|
self.hideSpinner({
|
|
self.showTypicalUIForUserUpdateResultsWithTitle(self.kSetDisplayNameTitle, error: error)
|
|
self.setTitleDisplay(FIRAuth.auth()?.currentUser)
|
|
})
|
|
}
|
|
})
|
|
} else {
|
|
self.showMessagePrompt("displayname can't be empty")
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @fn requestVerifyEmail
|
|
@brief Requests a "verify email" email be sent.
|
|
*/
|
|
@IBAction func didRequestVerifyEmail(sender: AnyObject) {
|
|
showSpinner({
|
|
// [START send_verification_email]
|
|
FIRAuth.auth()?.currentUser?.sendEmailVerificationWithCompletion({ (error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
if let error = error {
|
|
self.showMessagePrompt(error.localizedDescription)
|
|
return
|
|
}
|
|
self.showMessagePrompt("Sent")
|
|
})
|
|
// [END_EXCLUDE]
|
|
})
|
|
// [END send_verification_email]
|
|
})
|
|
}
|
|
|
|
/** @fn changeEmail
|
|
@brief Changes the email address of the current user.
|
|
*/
|
|
@IBAction func didChangeEmail(sender: AnyObject) {
|
|
showTextInputPromptWithMessage("Email Address:") { (userPressedOK, userInput) in
|
|
if let userInput = userInput {
|
|
self.showSpinner({
|
|
// [START change_email]
|
|
FIRAuth.auth()?.currentUser?.updateEmail(userInput) { (error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
self.showTypicalUIForUserUpdateResultsWithTitle(self.kChangeEmailText, error:error)
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END change_email]
|
|
})
|
|
} else {
|
|
self.showMessagePrompt("email can't be empty")
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @fn changePassword
|
|
@brief Changes the password of the current user.
|
|
*/
|
|
@IBAction func didChangePassword(sender: AnyObject) {
|
|
showTextInputPromptWithMessage("New Password:") { (userPressedOK, userInput) in
|
|
if let userInput = userInput {
|
|
self.showSpinner({
|
|
// [START change_password]
|
|
FIRAuth.auth()?.currentUser?.updatePassword(userInput) { (error) in
|
|
// [START_EXCLUDE]
|
|
self.hideSpinner({
|
|
self.showTypicalUIForUserUpdateResultsWithTitle(self.kChangePasswordText, error:error)
|
|
})
|
|
// [END_EXCLUDE]
|
|
}
|
|
// [END change_password]
|
|
})
|
|
} else {
|
|
self.showMessagePrompt("password can't be empty")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
/** @fn showTypicalUIForUserUpdateResultsWithTitle:error:
|
|
@brief Shows a @c UIAlertView if error is non-nil with the localized description of the error.
|
|
@param resultsTitle The title of the @c UIAlertView
|
|
@param error The error details to display if non-nil.
|
|
*/
|
|
func showTypicalUIForUserUpdateResultsWithTitle(resultsTitle: String, error: NSError?) {
|
|
if let error = error {
|
|
let message = "\(error.domain) (\(error.code))\n\(error.localizedDescription)"
|
|
let okAction = UIAlertAction.init(title: self.kOKButtonText, style: .Default)
|
|
{action in print(self.kOKButtonText)}
|
|
let alertController = UIAlertController.init(title: resultsTitle,
|
|
message: message, preferredStyle: .Alert)
|
|
alertController.addAction(okAction)
|
|
self.presentViewController(alertController, animated: true, completion: nil)
|
|
return
|
|
}
|
|
tableView.reloadData()
|
|
}
|
|
|
|
}
|