feat: add authentication scene
This commit is contained in:
parent
71de1ed9be
commit
0f8ad0c444
|
@ -51,6 +51,7 @@
|
|||
DB8AF55725C137A8002E6C99 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF55625C137A8002E6C99 /* HomeViewController.swift */; };
|
||||
DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF55C25C138B7002E6C99 /* UIViewController.swift */; };
|
||||
DB8AF56825C13E2A002E6C99 /* HomeTimelineIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF56725C13E2A002E6C99 /* HomeTimelineIndex.swift */; };
|
||||
DB98334725C8056600AD9700 /* AuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98334625C8056600AD9700 /* AuthenticationViewModel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -161,6 +162,7 @@
|
|||
DB8AF55625C137A8002E6C99 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
|
||||
DB8AF55C25C138B7002E6C99 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
|
||||
DB8AF56725C13E2A002E6C99 /* HomeTimelineIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineIndex.swift; sourceTree = "<group>"; };
|
||||
DB98334625C8056600AD9700 /* AuthenticationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewModel.swift; sourceTree = "<group>"; };
|
||||
DBF53F5F25C14E88008AAC7B /* Mastodon.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = Mastodon.xctestplan; path = Mastodon/Mastodon.xctestplan; sourceTree = "<group>"; };
|
||||
DBF53F6025C14E9D008AAC7B /* MastodonSDK.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MastodonSDK.xctestplan; sourceTree = "<group>"; };
|
||||
EC6E707B68A67DB08EC288FA /* Pods-MastodonTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.debug.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
|
@ -241,6 +243,7 @@
|
|||
children = (
|
||||
DB0140A625C40C0900F9F3CF /* PinBased */,
|
||||
DB01409525C40B6700F9F3CF /* AuthenticationViewController.swift */,
|
||||
DB98334625C8056600AD9700 /* AuthenticationViewModel.swift */,
|
||||
);
|
||||
path = Authentication;
|
||||
sourceTree = "<group>";
|
||||
|
@ -791,6 +794,7 @@
|
|||
DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */,
|
||||
DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */,
|
||||
DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */,
|
||||
DB98334725C8056600AD9700 /* AuthenticationViewModel.swift in Sources */,
|
||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
||||
DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */,
|
||||
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */,
|
||||
|
|
|
@ -37,7 +37,7 @@ extension SceneCoordinator {
|
|||
}
|
||||
|
||||
enum Scene {
|
||||
|
||||
case authentication(viewModel: AuthenticationViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,8 +108,12 @@ private extension SceneCoordinator {
|
|||
func get(scene: Scene) -> UIViewController? {
|
||||
let viewController: UIViewController?
|
||||
|
||||
// TODO:
|
||||
viewController = nil
|
||||
switch scene {
|
||||
case .authentication(let viewModel):
|
||||
let _viewController = AuthenticationViewController()
|
||||
_viewController.viewModel = viewModel
|
||||
viewController = _viewController
|
||||
}
|
||||
|
||||
setupDependency(for: viewController as? NeedsDependency)
|
||||
|
||||
|
|
|
@ -5,6 +5,76 @@
|
|||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class AuthenticationViewController: UIViewController, NeedsDependency {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||
|
||||
var viewModel: AuthenticationViewModel!
|
||||
|
||||
let domainTextField: UITextField = {
|
||||
let textField = UITextField()
|
||||
textField.placeholder = "example.com"
|
||||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
textField.keyboardType = .URL
|
||||
return textField
|
||||
}()
|
||||
|
||||
private(set) lazy var signInBarButtonItem = UIBarButtonItem(title: "Sign In", style: .plain, target: self, action: #selector(AuthenticationViewController.signInBarButtonItemPressed(_:)))
|
||||
|
||||
}
|
||||
|
||||
extension AuthenticationViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
title = "Authentication"
|
||||
view.backgroundColor = .systemBackground
|
||||
navigationItem.rightBarButtonItem = signInBarButtonItem
|
||||
|
||||
domainTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(domainTextField)
|
||||
NSLayoutConstraint.activate([
|
||||
domainTextField.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor, constant: 8),
|
||||
domainTextField.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 8),
|
||||
domainTextField.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: 8),
|
||||
domainTextField.heightAnchor.constraint(equalToConstant: 44), // FIXME:
|
||||
])
|
||||
|
||||
NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: domainTextField)
|
||||
.compactMap { notification in
|
||||
guard let textField = notification.object as? UITextField? else { return nil }
|
||||
return textField?.text ?? ""
|
||||
}
|
||||
.assign(to: \.value, on: viewModel.input)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.isSignInButtonEnabled
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.isEnabled, on: signInBarButtonItem)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
domainTextField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AuthenticationViewController {
|
||||
|
||||
@objc private func signInBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// AuthenticationViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/2/1.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
final class AuthenticationViewModel {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
// input
|
||||
let input = CurrentValueSubject<String, Never>("")
|
||||
|
||||
// output
|
||||
let domain = CurrentValueSubject<String?, Never>(nil)
|
||||
let isSignInButtonEnabled = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
init() {
|
||||
input
|
||||
.map { input in
|
||||
let trimmed = input.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
guard !trimmed.isEmpty else { return nil }
|
||||
|
||||
let urlString = trimmed.hasPrefix("https://") ? trimmed : "https://" + trimmed
|
||||
guard let url = URL(string: urlString),
|
||||
let host = url.host else {
|
||||
return nil
|
||||
}
|
||||
let components = host.components(separatedBy: ".")
|
||||
guard (components.filter { !$0.isEmpty }).count >= 2 else { return nil }
|
||||
|
||||
return host
|
||||
}
|
||||
.assign(to: \.value, on: domain)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
domain
|
||||
.print()
|
||||
.map { $0 != nil }
|
||||
.assign(to: \.value, on: isSignInButtonEnabled)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,6 @@ final class HomeViewController: UIViewController, NeedsDependency {
|
|||
|
||||
}
|
||||
|
||||
|
||||
extension HomeViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
|
|
@ -24,6 +24,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
self.coordinator = sceneCoordinator
|
||||
|
||||
sceneCoordinator.setup()
|
||||
|
||||
#if DEBUG
|
||||
DispatchQueue.main.async {
|
||||
let authenticationViewModel = AuthenticationViewModel()
|
||||
sceneCoordinator.present(scene: .authentication(viewModel: authenticationViewModel), from: nil, transition: .modal(animated: false, completion: nil))
|
||||
}
|
||||
#endif
|
||||
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue