//
|
// LoginVC.swift
|
// XWProject
|
//
|
// Created by alvin_y on 2020/5/20.
|
// Copyright © 2020 yangwang. All rights reserved.
|
//
|
|
import UIKit
|
import RxSwift
|
import RxCocoa
|
import TTTAttributedLabel
|
import SwiftDate
|
import FBSDKLoginKit
|
import FBSDKCoreKit
|
import TwitterAPIKit
|
import AuthenticationServices
|
|
let WechatLoginSuccess_Noti = Notification.Name.init("WechatLoginSuccess_Noti")
|
|
/// 登录注册
|
class LoginVC: YYViewController {
|
|
@IBOutlet weak var view_operations: UIView!
|
@IBOutlet weak var tf_opear: UITextField!
|
@IBOutlet weak var label_opear_title: UILabel!
|
|
/// 其他方式登录
|
@IBOutlet weak var label_otherLogin: UILabel!
|
|
/// 验证码图片
|
@IBOutlet weak var image_code: UIImageView!
|
|
@IBOutlet weak var label_phone: UILabel!
|
|
/// 验证码标题
|
@IBOutlet weak var label_code: UILabel!
|
|
/// 微信登录
|
@IBOutlet weak var button_weChat: UIButton!
|
|
@IBOutlet weak var button_twitter: UIButton!
|
|
@IBOutlet weak var button_face: UIButton!
|
|
/// 忘记密码
|
@IBOutlet weak var button_forgotPassword: UIButton!
|
|
/// 登录按钮
|
@IBOutlet weak var button_login: UIButton!
|
|
/// 获取验证码
|
@IBOutlet weak var button_getCode: UIButton!
|
|
/// 协议内容
|
@IBOutlet weak var label_agreement: TTTAttributedLabel!
|
|
/// 协议按钮
|
@IBOutlet weak var button_agreement: UIButton!
|
|
/// 验证码
|
@IBOutlet weak var textField_code: UITextField!
|
@IBOutlet weak var cons_codeCencerX: NSLayoutConstraint!
|
@IBOutlet weak var cons_codeHeight: NSLayoutConstraint!
|
|
/// 手机号
|
@IBOutlet weak var phoneInputView: PhoneInputView!
|
|
/// 密码登录
|
@IBOutlet weak var button_password: UIButton!
|
|
/// 验证码登录
|
@IBOutlet weak var button_code: UIButton!
|
@IBOutlet weak var button_forget: UIButton!
|
@IBOutlet weak var label_otherLoginType: UILabel!
|
|
/// 登录类型
|
let loginType = BehaviorRelay<LoginType>(value: .code)
|
|
/// 滑块
|
let view_slider: UIView = {
|
let view = UIView()
|
view.backgroundColor = ThemeColor
|
return view
|
}()
|
|
let viewModel = LoginViewModel()
|
|
let userInfoViewModel = MineInfoViewModel()
|
|
let agreeViewModel = AgreementViewModel()
|
|
var password = DisposeBag()
|
|
/// 验证按钮倒计时
|
var codeTimeTick: CodeTimeTick = CodeTimeTick()
|
|
private var env:Env?
|
|
override func viewDidLoad() {
|
super.viewDidLoad()
|
|
// Do any additional setup after loading the view.
|
yy_popBlock = { [unowned self] in
|
self.dismiss(animated: true, completion: nil)
|
}
|
agreeViewModel.type.accept(.userAgreement)
|
tf_opear.delegate = self
|
tf_opear.placeholder = localized("请选择运营商")
|
}
|
|
override func viewDidLayoutSubviews() {
|
super.viewDidLayoutSubviews()
|
button_login.setGradientBackground()
|
}
|
|
override func setuplocalization() {
|
title = localized("登录")
|
label_opear_title.text = localized("网络运营商")
|
button_login.setTitle(localized("登录"), for: .normal)
|
button_getCode.setTitle(localized("获取验证码"), for: .normal)
|
button_password.setTitle(localized("密码登录"), for: .normal)
|
button_code.setTitle(localized("验证码登录"), for: .normal)
|
label_phone.text = localized("手机号")
|
label_code.text = localized("验证码")
|
textField_code.placeholder = localized("请输入验证码")
|
label_otherLoginType.text = localized("其他方式登录")
|
|
if AppSettings.shared.language == .French{
|
cons_codeHeight.constant = 110
|
button_code.titleLabel?.font = UIFont.systemFont(ofSize: 11, weight: .medium)
|
button_password.titleLabel?.font = UIFont.systemFont(ofSize: 11, weight: .medium)
|
cons_codeCencerX.constant = 20
|
}
|
}
|
|
override func viewWillAppear(_ animated: Bool) {
|
super.viewWillAppear(animated)
|
yy_isHiddenNavBarLine = true
|
}
|
|
override func viewDidDisappear(_ animated: Bool) {
|
super.viewDidDisappear(animated)
|
codeTimeTick.close()
|
}
|
|
//MARK: - UI
|
override func setupViews() {
|
super.setupViews()
|
self.view.backgroundColor = UIColor.color(light: UIColor.white, dark: UIColor.color(hexString: "#191919"))
|
button_weChat.isHidden = !(UMSocialManager.default()?.isInstall(.wechatSession) ?? false)
|
// button_face.isHidden = !UMSocialManager.default().isInstall(.facebook)
|
// button_twitter.isHidden = !UMSocialManager.default().isInstall(.twitter)
|
// button_whatsApp.isHidden = UMSocialManager.default().isInstall(.whatsapp)
|
|
if UIApplication.shared.canOpenURL(URL(string: "fbapi://")!){
|
button_face.isHidden = false
|
}
|
|
// label_otherLogin.isHidden = (button_weChat.isHidden && button_face.isHidden && button_twitter.isHidden)
|
|
codeTimeTick.config(button: button_getCode, grayColor: UIColor.color(light: UIColor.color(hexString: "#333333",0.39), dark: UIColor.color(hexString: "#333333",0.39)))
|
button_forgotPassword.isHidden = true
|
textField_code.keyboardType = .numberPad
|
// constrainsTextInputLength(length: 11, textField: textField_phone).disposed(by: disposeBag)
|
constrainsTextInputLength(length: 4, textField: textField_code).disposed(by: password)
|
button_code.setTitleColor(ButtonGray, for: .normal)
|
button_code.setTitleColor(ThemeColor, for: .selected)
|
button_password.setTitleColor(ButtonGray, for: .normal)
|
button_password.setTitleColor(ThemeColor, for: .selected)
|
button_forgotPassword.setTitleColor(UIColor.color(light: UIColor.color(hexString: "#666666"), dark: UIColor.color(hexString: "#FFFFFF")), for: .normal)
|
view.addSubview(view_slider)
|
let paragraph1 = localized("我已阅读并同意")
|
|
|
|
let paragraph2 = String(format: "《%@》", localized("GOPOST出行用户服务协议"))
|
label_agreement.text = paragraph1 + paragraph2
|
label_agreement.textColor = UIColor.color(light: UIColor.color(hexString: "#333333"), dark: UIColor.color(hexString: "#FAFAFA"))
|
// label_otherLogin.textColor = UIColor.color(light: UIColor.color(hexString: "#666666"), dark: UIColor.color(hexString: "#FAFAFA"))
|
let color = UIColor.color(light: UIColor.ThemeColor, dark: UIColor.ThemeColor)
|
|
if AppSettings.shared.language == .Chinese{
|
label_agreement.linkAttributes = [NSAttributedString.Key.foregroundColor: color,NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]
|
}else{
|
label_agreement.linkAttributes = [NSAttributedString.Key.foregroundColor: color,NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 12)]
|
}
|
|
label_agreement.linkAttributes = [NSAttributedString.Key.foregroundColor: color,NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 12)]
|
label_agreement.activeLinkAttributes = [NSAttributedString.Key.foregroundColor: color,NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]
|
label_agreement.addLink(toTransitInformation: nil, with: NSRange(location: paragraph1.count, length: paragraph2.count))
|
label_agreement.delegate = self
|
|
#if DEBUG
|
textField_code.text = "1246"
|
#endif
|
|
}
|
|
//MARK: - Layouts
|
override func defineLayouts() {
|
super.defineLayouts()
|
view_slider.snp.makeConstraints { (make) in
|
make.bottom.equalTo(button_code.snp.bottom)
|
make.centerX.equalTo(button_code)
|
make.size.equalTo(CGSize(width: 115, height: 2))
|
}
|
}
|
|
//MARK: - Rx
|
override func bindRx() {
|
super.bindRx()
|
|
phoneInputView.areaCodeObservable
|
.map{$0.replacingOccurrences(of: "+", with: "")}
|
.bind(to: viewModel.areaCode)
|
.disposed(by: disposeBag)
|
|
phoneInputView.phoneTextField.rx.text.orEmpty
|
.bind(to: viewModel.phoneNumber)
|
.disposed(by: disposeBag)
|
|
textField_code.rx.text.orEmpty
|
.bind(to: viewModel.password)
|
.disposed(by: disposeBag)
|
|
loginType.bind(to: viewModel.type).disposed(by: disposeBag)
|
|
button_agreement.rx.observeWeakly(Bool.self, #keyPath(UIButton.isSelected))
|
.bind(to: viewModel.agreement)
|
.disposed(by: disposeBag)
|
|
|
loginType
|
.skip(1)
|
.subscribe(onNext: {[unowned self] (t) in
|
self.view.endEditing(true)
|
self.textField_code.text = nil
|
// self.view_operations.isHidden = t == .password
|
switch t{
|
case .code:
|
self.textField_code.isSecureTextEntry = false
|
self.password = DisposeBag()
|
constrainsTextInputLength(length: 4, textField: self.textField_code).disposed(by: self.password)
|
self.textField_code.keyboardType = .numberPad
|
self.button_code.isSelected = true
|
self.button_password.isSelected = false
|
self.label_code.text = localized("验证码")
|
self.image_code.image = UIImage.init(named: "icon_login_code")
|
self.textField_code.placeholder = localized("请输入验证码")
|
self.button_forgotPassword.isHidden = true
|
self.button_getCode.isHidden = false
|
UIView.animate(withDuration: 0.3) {
|
self.view_slider.snp.remakeConstraints { (make) in
|
make.bottom.equalTo(self.button_code.snp.bottom)
|
make.centerX.equalTo(self.button_code)
|
make.size.equalTo(CGSize(width: 115, height: 2))
|
}
|
self.view.layoutIfNeeded()
|
}
|
break
|
case .password:
|
self.password = DisposeBag()
|
self.textField_code.isSecureTextEntry = true
|
constrainsTextInputLength(length: 18, textField: self.textField_code).disposed(by: self.password)
|
self.textField_code.keyboardType = .default
|
self.button_code.isSelected = false
|
self.button_password.isSelected = true
|
self.button_forget.setTitle(String(format: "%@?", localized("忘记密码")), for: .normal)
|
self.label_code.text = localized("密码")
|
self.image_code.image = UIImage.init(named: "icon_login_password")
|
self.textField_code.placeholder = localized("请输入密码")
|
self.button_forgotPassword.isHidden = false
|
self.button_getCode.isHidden = true
|
UIView.animate(withDuration: 0.3) {
|
self.view_slider.snp.remakeConstraints { (make) in
|
make.bottom.equalTo(self.button_password.snp.bottom)
|
make.centerX.equalTo(self.button_password)
|
make.size.equalTo(CGSize(width: 115, height: 2))
|
}
|
self.view.layoutIfNeeded()
|
}
|
break
|
}
|
}).disposed(by: disposeBag)
|
|
/// 获取验证码
|
button_getCode.rx.tap.subscribe(onNext: {[unowned self] (_) in
|
if self.phoneInputView.phoneNumber.isEmpty{
|
alert(text: localized("请输入手机号"))
|
return
|
}
|
/*
|
let view = CodeImageView.loadView()
|
view.phone = self.textField_phone.text!
|
view.show()
|
view.callBackBlock = { (str) in
|
// self.textField_code.text = str
|
self.viewModel.sendSMSCode(type: 2,kaptcha: str)
|
}
|
*/
|
|
DispatchQueue.main.async { [self] in
|
// let recaptcha = RecaptchaVisual(
|
// viewController: self, siteKey: WEB_SITE_KEY, baseUrl: URL(string: WEB_BASE_URL)!)
|
// recaptcha.runCaptcha { (token: String?, error: Error?) in
|
// guard let token = token else {return}
|
// self.viewModel.token.accept(token)
|
self.viewModel.sendSMSCode(type: 2, kaptcha: "")
|
// }
|
}
|
|
}).disposed(by: disposeBag)
|
|
button_code.rx.tap
|
.subscribe(onNext: {[unowned self] (_) in
|
self.loginType.accept(.code)
|
}).disposed(by: disposeBag)
|
|
button_password.rx.tap
|
.subscribe(onNext: {[unowned self] (_) in
|
self.loginType.accept(.password)
|
}).disposed(by: disposeBag)
|
|
/// 登录
|
button_login.rx.tap
|
.subscribe(onNext: {[unowned self] (_) in
|
// if self.loginType.value == .code && self.viewModel.operations.value?.isEmpty ?? true{
|
// alert(text: tf_opear.placeholder ?? "");return
|
// }
|
self.viewModel.login()
|
}).disposed(by: disposeBag)
|
|
/// 登录处理
|
viewModel.loginSubject
|
.subscribeOn(MainScheduler.instance)
|
.subscribe(onNext: { [unowned self](status) in
|
switch status{
|
case .loading:
|
YYAlertKit.displayActivity()
|
break
|
case .success(_ ):
|
YYAlertKit.dismiss()
|
self.dismiss(animated: true, completion: nil)
|
break
|
case .error(let error):
|
YYAlertKit.display(message: error.localizedDescription)
|
break
|
}
|
}).disposed(by: disposeBag)
|
|
viewModel.twitterSubject.subscribe(onNext: {[unowned self]status in
|
switch status{
|
case .loading:
|
self.show()
|
break
|
case .success(let model):
|
self.hide()
|
if let data: LoginModel = model as? LoginModel{
|
// 是否有手机号码(1=否,2=是)
|
if data.phone == 1{
|
app.loginInfo.save(model: data)
|
let vc = BindPhoneVC()
|
self.yy_push(vc: vc)
|
}else{
|
app.loginInfo.save(model: data)
|
self.userInfoViewModel.queryUserInfo()
|
self.dismiss(animated: true, completion: nil)
|
}
|
}
|
break
|
case .error(let error):
|
self.hide()
|
alert(text: error.localizedDescription)
|
break
|
}
|
}) { error in
|
|
}.disposed(by: disposeBag)
|
|
|
/// 登录处理
|
viewModel.wxLoginSubject
|
.subscribeOn(MainScheduler.instance)
|
.subscribe(onNext: { [unowned self](status) in
|
switch status{
|
case .loading:
|
self.show()
|
break
|
case .success(let model):
|
self.hide()
|
if let data: LoginModel = model as? LoginModel{
|
// 是否有手机号码(1=否,2=是)
|
if data.phone == 1{
|
app.loginInfo.save(model: data)
|
let vc = BindPhoneVC()
|
self.yy_push(vc: vc)
|
}else{
|
app.loginInfo.save(model: data)
|
self.userInfoViewModel.queryUserInfo()
|
self.dismiss(animated: true, completion: nil)
|
}
|
}
|
|
break
|
case .error(let error):
|
self.hide()
|
alert(text: error.localizedDescription)
|
break
|
}
|
}).disposed(by: disposeBag)
|
|
|
viewModel.facebookSubject.subscribe { status in
|
switch status{
|
case .loading:
|
self.show()
|
break
|
case .success(let model):
|
self.hide()
|
if let data: LoginModel = model as? LoginModel{
|
// 是否有手机号码(1=否,2=是)
|
if data.phone == 1{
|
app.loginInfo.save(model: data)
|
let vc = BindPhoneVC()
|
self.yy_push(vc: vc)
|
}else{
|
app.loginInfo.save(model: data)
|
self.userInfoViewModel.queryUserInfo()
|
self.dismiss(animated: true, completion: nil)
|
}
|
}
|
|
break
|
case .error(let error):
|
self.hide()
|
alert(text: error.localizedDescription)
|
break
|
}
|
} onError: { error in
|
self.hide()
|
alert(text: error.localizedDescription)
|
}.disposed(by: disposeBag)
|
|
/// 发送验证码处理
|
viewModel.sendSMSCodeSubject
|
.subscribe(onNext: {[unowned self] (status) in
|
switch status{
|
case .loading:
|
YYAlertKit.displayActivity()
|
break
|
case .success(_ ):
|
YYAlertKit.dismiss()
|
// 倒计时
|
self.codeTimeTick.start()
|
break
|
case .error(let error):
|
YYAlertKit.display(message: error.localizedDescription)
|
break
|
}
|
}).disposed(by: disposeBag)
|
|
/// 忘记密码
|
button_forgotPassword.rx.tap
|
.subscribe(onNext: {[unowned self] (_) in
|
let vc = ForgotPasswordVC()
|
self.yy_push(vc: vc)
|
}).disposed(by: disposeBag)
|
|
/// 协议绑定
|
button_agreement.rx.tap.subscribe(onNext: { [unowned self](_) in
|
self.button_agreement.isSelected = !self.button_agreement.isSelected
|
}).disposed(by: disposeBag)
|
|
/// 微信登录
|
button_weChat.rx.tap.subscribe(onNext: {[unowned self] (_) in
|
do{
|
try self.viewModel.agreement.value?.checkAgreement(agreementName: localized("GOPOST出行用户服务协议"))
|
self.wxLogin()
|
}catch{
|
alert(text: error.localizedDescription)
|
}
|
}).disposed(by: disposeBag)
|
|
button_face.rx.tap.subscribe { (_) in
|
do{
|
try self.viewModel.agreement.value?.checkAgreement(agreementName: localized("GOPOST出行用户服务协议"))
|
self.facebookLogin()
|
}catch{
|
alert(text: error.localizedDescription)
|
}
|
}.disposed(by: disposeBag)
|
|
|
button_twitter.rx.tap.subscribe(onNext: {() in
|
do{
|
try self.viewModel.agreement.value?.checkAgreement(agreementName: localized("GOPOST出行用户服务协议"))
|
self.twitterLogin()
|
}catch{
|
alert(text: error.localizedDescription)
|
}
|
|
}).disposed(by: rx.disposeBag)
|
|
agreeViewModel.requestSubject
|
.subscribe(onNext: { (status) in
|
switch status{
|
case .loading:
|
self.show()
|
break
|
case .success(let model):
|
self.hide()
|
guard let data: SwitchCityModel = model as? SwitchCityModel else {return}
|
let vc = YYWebView()
|
vc.name = self.agreeViewModel.type.value.title()
|
vc.url = data.content
|
self.yy_push(vc: vc)
|
break
|
case .error(let error):
|
self.hide()
|
alert(text: error.localizedDescription)
|
break
|
}
|
}).disposed(by: rx.disposeBag)
|
|
NotificationCenter.default.rx.notification(WechatLoginSuccess_Noti).take(until: self.rx.deallocated).subscribe(onNext: { noti in
|
if let obj = noti.object as? WechatUserInfoModel{
|
DispatchQueue.main.async {
|
self.viewModel.wxLogin(avatar: obj.headimgurl, nickName: obj.nickname, sex: obj.sex, openid:obj.openid, unionid: obj.unionid, registAreaCode: YYLocationManager.shared.currentCityCode)
|
}
|
}
|
}).disposed(by: rx.disposeBag)
|
}
|
|
|
/// 微信登录
|
func wxLogin() {
|
WeChatTools.sendAuthRequest()
|
}
|
|
private func twitterLogin(){
|
env = Env()
|
app.client.auth.oauth10a.postOAuthRequestToken(.init(oauthCallback: "twitterkit-FBddBQ492ZHOkaDslZ075mhMr://")).responseObject { [weak self] response in
|
do {
|
let success = try response.result.get()
|
let url = app.client.auth.oauth10a.makeOAuthAuthorizeURL(.init(oauthToken: success.oauthToken))!
|
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: "twitterkit-FBddBQ492ZHOkaDslZ075mhMr") { url, error in
|
|
// url is "twitter-api-kit-ios-sample://?oauth_token=<string>&oauth_verifier=<string>"
|
guard let url = url else {
|
if let error = error {
|
//tdo
|
}
|
return
|
}
|
print("URL:", url)
|
|
let component = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
guard let oauthToken = component?.queryItems?.first(where: { $0.name == "oauth_token"} )?.value,
|
let oauthVerifier = component?.queryItems?.first(where: { $0.name == "oauth_verifier"})?.value else {
|
print("Invalid URL")
|
return
|
}
|
app.client.auth.oauth10a.postOAuthAccessToken(.init(oauthToken: oauthToken, oauthVerifier: oauthVerifier))
|
.responseObject { response in
|
do {
|
let token = try response.result.get()
|
let oauthToken = token.oauthToken
|
let oauthTokenSecret = token.oauthTokenSecret
|
|
self?.env?.oauthToken = oauthToken
|
self?.env?.oauthTokenSecret = oauthTokenSecret
|
self?.env?.store()
|
|
if let userId = try! response.result.get().userID{
|
self?.viewModel.twitterLogin(id: userId, name: try! response.result.get().screenName!)
|
}
|
} catch {
|
|
}
|
}
|
}
|
session.presentationContextProvider = self
|
session.prefersEphemeralWebBrowserSession = true
|
|
session.start()
|
|
} catch {
|
print(error.localizedDescription)
|
}
|
}
|
|
|
}
|
|
func facebookLogin(){
|
let fbLoginManager = LoginManager(defaultAudience: .onlyMe)
|
fbLoginManager.logIn(permissions: ["email","public_profile"], from: self) { result, error in
|
if error == nil{
|
if result?.grantedPermissions.contains("email") ?? false{
|
self.getFBUserData()
|
fbLoginManager.logOut()
|
|
}else{
|
alert(text:"登录失败")
|
}
|
}
|
}
|
}
|
|
func getFBUserData(){
|
if AccessToken.current != nil{
|
GraphRequest(graphPath: "me", parameters: ["fields": "id,name,first_name,last_name,picture.type(large),email"]).start { connect, result, error in
|
if error == nil{
|
print("获取facebook结果")
|
if let dict = result as? Dictionary<String, Any>{
|
if let m = FacebookLoginInfoModel.deserialize(from: dict){
|
self.viewModel.facebookLogin(id: m.id, name: m.name, registAreaCode: YYLocationManager.shared.currentCityCode)
|
}else{
|
alert(text:"登录失败")
|
}
|
}else{
|
alert(text:"登录失败")
|
}
|
}
|
}
|
}
|
|
// UMSocialManager.default().getUserInfo(with: .facebook, currentViewController: self) { result, error in
|
// if (error == nil) {
|
// let resp = result as? UMSocialUserInfoResponse
|
// guard let res = resp else {
|
// return
|
// }
|
// self.viewModel.facebookLogin(id: res.uid, name: res.name, registAreaCode: YYLocationManager.shared.currentCityCode)
|
// }else{
|
// alert(text: localized("登录失败"))
|
// }
|
// }
|
}
|
}
|
|
|
extension LoginVC: TTTAttributedLabelDelegate
|
{
|
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWithTransitInformation components: [AnyHashable : Any]!) {
|
agreeViewModel.agreement()
|
}
|
}
|
|
extension LoginVC:UITextFieldDelegate{
|
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
JQ_MenuView().show(self, tapView: textField, items: ["MTN","TIGO","TELECEL","AIRTEL"],tableWidth: 300, tableHei: 350) { index, str in
|
textField.text = str
|
self.viewModel.operations.accept(str)
|
}
|
return false
|
}
|
}
|
|
|
|
struct Env: Codable {
|
// MARK: - OAUTH 1.0a
|
var consumerKey: String?
|
var consumerSecret: String?
|
|
var oauthToken: String?
|
var oauthTokenSecret: String?
|
|
// MARK: - OAuth 2.0 Authorization Code Flow with PKCE
|
var clientID: String?
|
var clientSecret: String?
|
|
var token: TwitterAuthenticationMethod.OAuth20?
|
}
|
|
private var env: Env {
|
if let env = Env.restore() {
|
return env
|
}
|
return Env(
|
consumerKey: TwitterKey,
|
consumerSecret: TWitterSecret,
|
oauthToken: nil,
|
oauthTokenSecret: nil,
|
clientID: TwitterKey,
|
clientSecret: nil
|
)
|
}
|
|
extension Env {
|
func store(_ defaults: UserDefaults = .standard) {
|
let encoder = JSONEncoder()
|
let data = try! encoder.encode(self)
|
defaults.set(data, forKey: "Twitter.Env")
|
}
|
|
static func restore(_ defaults: UserDefaults = .standard) -> Self? {
|
guard let data = defaults.data(forKey: "Twitter.Env") else { return nil }
|
let decoder = JSONDecoder()
|
let env = try? decoder.decode(Self.self, from: data)
|
return env
|
}
|
|
static func reset(_ defaults: UserDefaults = .standard) {
|
defaults.removeObject(forKey: "Twitter.Env")
|
}
|
}
|
|
extension LoginVC: ASWebAuthenticationPresentationContextProviding {
|
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
return view.window!
|
}
|
}
|