frenzy-ios/Reader/Screens/Login/LoginViewController.swift

140 lines
5.4 KiB
Swift
Raw Normal View History

2021-12-08 02:58:02 +00:00
//
// LoginViewController.swift
// Reader
//
// Created by Shadowfacts on 11/25/21.
//
@preconcurrency import Foundation
2021-12-08 02:58:02 +00:00
import UIKit
import AuthenticationServices
import Fervor
2022-01-12 18:30:49 +00:00
@MainActor
2021-12-08 02:58:02 +00:00
protocol LoginViewControllerDelegate: AnyObject {
func didLogin(with controller: FervorController)
}
class LoginViewController: UIViewController {
weak var delegate: LoginViewControllerDelegate?
private var textField: UITextField!
2022-01-12 18:30:49 +00:00
private var activityIndicator: UIActivityIndicatorView!
2021-12-08 02:58:02 +00:00
private var authSession: ASWebAuthenticationSession?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.borderStyle = .roundedRect
textField.backgroundColor = .secondarySystemBackground
textField.keyboardType = .URL
textField.returnKeyType = .next
textField.autocorrectionType = .no
textField.autocapitalizationType = .none
textField.placeholder = "example.com"
textField.addTarget(self, action: #selector(doEnteredURL), for: .primaryActionTriggered)
view.addSubview(textField)
2022-01-12 18:30:49 +00:00
activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
2021-12-08 02:58:02 +00:00
NSLayoutConstraint.activate([
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.75),
2022-01-12 18:30:49 +00:00
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),
activityIndicator.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 8),
2021-12-08 02:58:02 +00:00
])
}
@objc private func doEnteredURL() {
Task {
await enteredURL()
}
}
@MainActor
private func enteredURL() async {
guard let text = textField.text,
let components = URLComponents(string: text) else {
let alert = UIAlertController(title: "Invalid URL", message: nil, preferredStyle: .alert)
self.present(alert, animated: true)
return
}
2022-01-12 18:30:49 +00:00
textField.isEnabled = false
activityIndicator.startAnimating()
let controller = await FervorController(instanceURL: components.url!, account: nil)
2021-12-08 02:58:02 +00:00
let registration: ClientRegistration
do {
registration = try await controller.register()
} catch {
2022-01-12 18:30:49 +00:00
let alert = UIAlertController(title: "Unable to register client", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
2021-12-08 02:58:02 +00:00
present(alert, animated: true)
2022-01-12 18:30:49 +00:00
textField.isEnabled = true
activityIndicator.stopAnimating()
2021-12-08 02:58:02 +00:00
return
}
var authorizeComponents = components
authorizeComponents.path = "/oauth/authorize"
authorizeComponents.queryItems = [
URLQueryItem(name: "response_type", value: "code"),
URLQueryItem(name: "client_id", value: registration.clientID),
URLQueryItem(name: "redirect_uri", value: FervorController.oauthRedirectURI.absoluteString),
]
authSession = ASWebAuthenticationSession(url: authorizeComponents.url!, callbackURLScheme: "frenzy") { (callbackURL, error) in
let components = URLComponents(url: callbackURL!, resolvingAgainstBaseURL: false)
guard let codeItem = components?.queryItems?.first(where: { $0.name == "code" }),
let codeValue = codeItem.value else {
Task { @MainActor in
let alert = UIAlertController(title: "Unable to retrieve authorization code", message: error?.localizedDescription ?? "Unknown Error", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true)
self.textField.isEnabled = true
self.activityIndicator.stopAnimating()
}
return
}
2022-01-12 18:30:49 +00:00
Task { @MainActor in
do {
try await controller.getToken(authCode: codeValue)
} catch {
let alert = UIAlertController(title: "Unable to retrieve access token", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true)
self.textField.isEnabled = true
self.activityIndicator.stopAnimating()
return
2021-12-08 02:58:02 +00:00
}
2022-01-12 18:30:49 +00:00
self.delegate?.didLogin(with: controller)
2021-12-08 02:58:02 +00:00
}
}
self.authSession!.presentationContextProvider = self
self.authSession!.start()
}
}
extension LoginViewController: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return self.view.window!
}
}