OtherAuthViewController.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. 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. // unlimited line breaks
  99. label.numberOfLines = 0
  100. label.text = text
  101. label.alpha = UIDevice.current.orientation.isLandscape ? 0 : 1
  102. label.translatesAutoresizingMaskIntoConstraints = false
  103. view.addSubview(label)
  104. NSLayoutConstraint.activate([
  105. label.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 5),
  106. label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 15),
  107. label.trailingAnchor.constraint(
  108. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  109. constant: -15
  110. ),
  111. ])
  112. textFieldInputLabel = label
  113. }
  114. private func configureButton() {
  115. button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
  116. button.translatesAutoresizingMaskIntoConstraints = false
  117. view.addSubview(button)
  118. NSLayoutConstraint.activate([
  119. button.leadingAnchor.constraint(
  120. equalTo: view.safeAreaLayoutGuide.leadingAnchor,
  121. constant: 15
  122. ),
  123. button.trailingAnchor.constraint(
  124. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  125. constant: -15
  126. ),
  127. button.heightAnchor.constraint(equalToConstant: 45),
  128. ])
  129. let constant: CGFloat = UIDevice.current.orientation.isLandscape ? 15 : 110
  130. buttonTopConstraint = button.topAnchor.constraint(
  131. equalTo: textField.bottomAnchor,
  132. constant: constant
  133. )
  134. buttonTopConstraint.isActive = true
  135. }
  136. private func configureInfoLabel() {
  137. infoLabel = UILabel()
  138. infoLabel.textColor = .secondaryLabel
  139. infoLabel.numberOfLines = 15
  140. infoLabel.translatesAutoresizingMaskIntoConstraints = false
  141. view.addSubview(infoLabel)
  142. NSLayoutConstraint.activate([
  143. infoLabel.topAnchor.constraint(equalTo: view.centerYAnchor, constant: 10),
  144. infoLabel.leadingAnchor.constraint(
  145. equalTo: view.safeAreaLayoutGuide.leadingAnchor,
  146. constant: 35
  147. ),
  148. infoLabel.trailingAnchor.constraint(
  149. equalTo: view.safeAreaLayoutGuide.trailingAnchor,
  150. constant: -15
  151. ),
  152. ])
  153. let infoSymbol = UIImageView(systemImageName: "info.circle", tintColor: .systemOrange)
  154. infoSymbol.contentMode = .center
  155. infoSymbol.preferredSymbolConfiguration = UIImage.SymbolConfiguration(pointSize: 17)
  156. infoSymbol.translatesAutoresizingMaskIntoConstraints = false
  157. view.addSubview(infoSymbol)
  158. NSLayoutConstraint.activate([
  159. infoSymbol.topAnchor.constraint(equalTo: infoLabel.topAnchor),
  160. infoSymbol.trailingAnchor.constraint(
  161. equalTo: infoLabel.safeAreaLayoutGuide.leadingAnchor,
  162. constant: -5
  163. ),
  164. ])
  165. }
  166. override func viewWillTransition(to size: CGSize,
  167. with coordinator: any UIViewControllerTransitionCoordinator) {
  168. super.viewWillTransition(to: size, with: coordinator)
  169. textFieldTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 10 : 60
  170. buttonTopConstraint.constant = UIDevice.current.orientation.isLandscape ? 15 : 110
  171. textFieldInputLabel?.alpha = UIDevice.current.orientation.isLandscape ? 0 : 1
  172. }
  173. }
  174. // MARK: - UITextFieldDelegate
  175. extension OtherAuthViewController: UITextFieldDelegate {
  176. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  177. textField.resignFirstResponder()
  178. return true
  179. }
  180. }