OtherAuthViewController.swift 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import UIKit
  15. /// Base UIViewController Class for presenting auth flows defined in
  16. /// [OtherAuthMethods](x-source-tag://OtherAuthMethods)
  17. class OtherAuthViewController: UIViewController {
  18. weak var delegate: (any LoginDelegate)?
  19. lazy var textField: UITextField = {
  20. let textField = UITextField()
  21. textField.backgroundColor = .secondarySystemBackground
  22. textField.tintColor = .systemOrange
  23. textField.layer.cornerRadius = 14
  24. return textField
  25. }()
  26. private var textFieldInputLabel: UILabel?
  27. private lazy var button: UIButton = {
  28. let button = UIButton()
  29. button.setTitleColor(.white, for: .normal)
  30. button.setTitleColor(.highlightedLabel, for: .highlighted)
  31. button.setBackgroundImage(UIColor.systemOrange.image, for: .normal)
  32. button.setBackgroundImage(UIColor.systemOrange.highlighted.image, for: .highlighted)
  33. button.clipsToBounds = true
  34. button.layer.cornerRadius = 14
  35. return button
  36. }()
  37. private var infoLabel: UILabel!
  38. private var textFieldTopConstraint: NSLayoutConstraint!
  39. private var buttonTopConstraint: NSLayoutConstraint!
  40. override func viewDidLoad() {
  41. super.viewDidLoad()
  42. view.backgroundColor = .systemBackground
  43. configureNavigationBar()
  44. configureTextField()
  45. configureButton()
  46. configureInfoLabel()
  47. }
  48. // Dismisses keyboard when view is tapped
  49. override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  50. super.touchesBegan(touches, with: event)
  51. view.endEditing(true)
  52. }
  53. // MARK: - Action Handlers
  54. @objc
  55. func buttonTapped() {
  56. print(#function)
  57. }
  58. // MARK: - UI Configuration
  59. /// Used by subclasses to configure the UI for given OtherAuthMethod
  60. /// - Parameter authMethod: Either the Passwordless, Phone Number, Custom Auth login flow
  61. public func configureUI(for authMethod: OtherAuthMethod) {
  62. navigationItem.title = authMethod.navigationTitle
  63. textField.setImage(UIImage(systemName: authMethod.textFieldIcon)!)
  64. textField.placeholder = authMethod.textFieldPlaceholder
  65. configureTextFieldInputLabel(with: authMethod.textFieldInputText)
  66. button.setTitle(authMethod.buttonTitle, for: .normal)
  67. infoLabel.text = authMethod.infoText
  68. if authMethod == .PhoneNumber {
  69. textField.keyboardType = .numberPad
  70. }
  71. }
  72. private func configureNavigationBar() {
  73. navigationController?.setTitleColor(.systemOrange)
  74. }
  75. private func configureTextField() {
  76. textField.delegate = self
  77. textField.translatesAutoresizingMaskIntoConstraints = false
  78. view.addSubview(textField)
  79. textField.leadingAnchor
  80. .constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 15).isActive = true
  81. textField.trailingAnchor.constraint(
  82. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  83. constant: -15
  84. ).isActive = true
  85. textField.heightAnchor.constraint(equalToConstant: 45).isActive = true
  86. let constant: CGFloat = UIDevice.current.orientation.isLandscape ? 10 : 60
  87. textFieldTopConstraint = textField.topAnchor.constraint(
  88. equalTo: view.safeAreaLayoutGuide.topAnchor,
  89. constant: constant
  90. )
  91. textFieldTopConstraint.isActive = true
  92. }
  93. private func configureTextFieldInputLabel(with text: String?) {
  94. guard let text = text else { return }
  95. let label = UILabel()
  96. label.font = .systemFont(ofSize: 12)
  97. label.textColor = .secondaryLabel
  98. label.text = text
  99. label.alpha = UIDevice.current.orientation.isLandscape ? 0 : 1
  100. label.translatesAutoresizingMaskIntoConstraints = false
  101. view.addSubview(label)
  102. NSLayoutConstraint.activate([
  103. label.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 5),
  104. label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 15),
  105. label.trailingAnchor.constraint(
  106. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  107. constant: -15
  108. ),
  109. ])
  110. textFieldInputLabel = label
  111. }
  112. private func configureButton() {
  113. button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
  114. button.translatesAutoresizingMaskIntoConstraints = false
  115. view.addSubview(button)
  116. NSLayoutConstraint.activate([
  117. button.leadingAnchor.constraint(
  118. equalTo: view.safeAreaLayoutGuide.leadingAnchor,
  119. constant: 15
  120. ),
  121. button.trailingAnchor.constraint(
  122. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  123. constant: -15
  124. ),
  125. button.heightAnchor.constraint(equalToConstant: 45),
  126. ])
  127. let constant: CGFloat = UIDevice.current.orientation.isLandscape ? 15 : 110
  128. buttonTopConstraint = button.topAnchor.constraint(
  129. equalTo: textField.bottomAnchor,
  130. constant: constant
  131. )
  132. buttonTopConstraint.isActive = true
  133. }
  134. private func configureInfoLabel() {
  135. infoLabel = UILabel()
  136. infoLabel.textColor = .secondaryLabel
  137. infoLabel.numberOfLines = 15
  138. infoLabel.translatesAutoresizingMaskIntoConstraints = false
  139. view.addSubview(infoLabel)
  140. NSLayoutConstraint.activate([
  141. infoLabel.topAnchor.constraint(equalTo: view.centerYAnchor, constant: 10),
  142. infoLabel.leadingAnchor.constraint(
  143. equalTo: view.safeAreaLayoutGuide.leadingAnchor,
  144. constant: 35
  145. ),
  146. infoLabel.trailingAnchor.constraint(
  147. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  148. constant: -15
  149. ),
  150. ])
  151. let infoSymbol = UIImageView(systemImageName: "info.circle", tintColor: .systemOrange)
  152. infoSymbol.contentMode = .center
  153. infoSymbol.preferredSymbolConfiguration = UIImage.SymbolConfiguration(pointSize: 17)
  154. infoSymbol.translatesAutoresizingMaskIntoConstraints = false
  155. view.addSubview(infoSymbol)
  156. NSLayoutConstraint.activate([
  157. infoSymbol.topAnchor.constraint(equalTo: infoLabel.topAnchor),
  158. infoSymbol.trailingAnchor.constraint(
  159. equalTo: infoLabel.safeAreaLayoutGuide.leadingAnchor,
  160. constant: -5
  161. ),
  162. ])
  163. }
  164. override func viewWillTransition(to size: CGSize,
  165. with coordinator: any UIViewControllerTransitionCoordinator) {
  166. super.viewWillTransition(to: size, with: coordinator)
  167. textFieldTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 10 : 60
  168. buttonTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 15 : 110
  169. textFieldInputLabel?.alpha = UIDevice.current.orientation.isLandscape ? 0 : 1
  170. }
  171. }
  172. // MARK: - UITextFieldDelegate
  173. extension OtherAuthViewController: UITextFieldDelegate {
  174. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  175. textField.resignFirstResponder()
  176. return true
  177. }
  178. }