QrViewController.swift 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import Foundation
  2. import UIKit
  3. import DcCore
  4. class QrViewController: UIViewController {
  5. private let dcContext: DcContext
  6. var onDismissed: (() -> Void)?
  7. private lazy var scrollView: UIScrollView = {
  8. let scrollView = UIScrollView()
  9. scrollView.showsVerticalScrollIndicator = false
  10. return scrollView
  11. }()
  12. private lazy var qrContentView: QrViewContentView = {
  13. let qrCode = dcContext.getSecurejoinQr(chatId: chatId)
  14. let view = QrViewContentView(qrCode: qrCode, hint: qrCodeHint)
  15. view.translatesAutoresizingMaskIntoConstraints = false
  16. return view
  17. }()
  18. var qrCodeHint: String {
  19. willSet {
  20. let qrCode = dcContext.getSecurejoinQr(chatId: chatId)
  21. qrContentView.update(qrCode: qrCode, hint: newValue)
  22. }
  23. }
  24. private let chatId: Int
  25. init(dcContext: DcContext, chatId: Int? = 0, qrCodeHint: String?) {
  26. self.dcContext = dcContext
  27. self.chatId = chatId ?? 0
  28. self.qrCodeHint = qrCodeHint ?? ""
  29. super.init(nibName: nil, bundle: nil)
  30. }
  31. required init?(coder _: NSCoder) {
  32. fatalError("init(coder:) has not been implemented")
  33. }
  34. // MARK: - lifecycle
  35. override func viewDidLoad() {
  36. super.viewDidLoad()
  37. title = String.localized("qrshow_title")
  38. setupSubviews()
  39. view.backgroundColor = DcColors.defaultBackgroundColor
  40. }
  41. override func viewDidLayoutSubviews() {
  42. super.viewDidLayoutSubviews()
  43. qrContentView.minContainerHeight = view.frame.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom)
  44. }
  45. override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
  46. super.viewWillTransition(to: size, with: coordinator)
  47. qrContentView.minContainerHeight = size.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom)
  48. scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
  49. }
  50. override func viewDidDisappear(_ animated: Bool) {
  51. onDismissed?()
  52. }
  53. // MARK: - setup
  54. private func setupSubviews() {
  55. view.addSubview(scrollView)
  56. scrollView.translatesAutoresizingMaskIntoConstraints = false
  57. scrollView.addSubview(qrContentView)
  58. let frameGuide = scrollView.frameLayoutGuide
  59. let contentGuide = scrollView.contentLayoutGuide
  60. frameGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
  61. frameGuide.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
  62. frameGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
  63. frameGuide.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
  64. contentGuide.leadingAnchor.constraint(equalTo: qrContentView.leadingAnchor).isActive = true
  65. contentGuide.topAnchor.constraint(equalTo: qrContentView.topAnchor).isActive = true
  66. contentGuide.trailingAnchor.constraint(equalTo: qrContentView.trailingAnchor).isActive = true
  67. contentGuide.bottomAnchor.constraint(equalTo: qrContentView.bottomAnchor).isActive = true
  68. // this enables vertical scrolling
  69. frameGuide.widthAnchor.constraint(equalTo: contentGuide.widthAnchor).isActive = true
  70. }
  71. }
  72. // MARK: - QrViewContentView
  73. class QrViewContentView: UIView {
  74. private var qrCodeView: QRCodeView = {
  75. let view = QRCodeView(frame: .zero)
  76. return view
  77. }()
  78. private lazy var hintLabel: UILabel = {
  79. let label = UILabel.init()
  80. label.lineBreakMode = .byWordWrapping
  81. label.numberOfLines = 0
  82. label.textAlignment = .center
  83. label.font = .preferredFont(forTextStyle: .subheadline)
  84. label.adjustsFontForContentSizeCategory = true
  85. return label
  86. }()
  87. private let container = UIView()
  88. var minContainerHeight: CGFloat = 0 {
  89. didSet {
  90. containerMinHeightConstraint.constant = minContainerHeight
  91. }
  92. }
  93. private lazy var containerMinHeightConstraint: NSLayoutConstraint = {
  94. return container.heightAnchor.constraint(greaterThanOrEqualToConstant: 0)
  95. }()
  96. init(qrCode: String?, hint: String) {
  97. super.init(frame: .zero)
  98. update(qrCode: qrCode, hint: hint)
  99. setupSubviews()
  100. }
  101. required init?(coder: NSCoder) {
  102. fatalError("init(coder:) has not been implemented")
  103. }
  104. // MARK: - update
  105. func update(qrCode: String?, hint: String?) {
  106. if let qrCode = qrCode {
  107. qrCodeView.generateCode(
  108. qrCode,
  109. foregroundColor: .darkText,
  110. backgroundColor: .white
  111. )
  112. }
  113. hintLabel.text = hint
  114. }
  115. private func setupSubviews() {
  116. addSubview(container)
  117. container.translatesAutoresizingMaskIntoConstraints = false
  118. container.topAnchor.constraint(equalTo: topAnchor).isActive = true
  119. container.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
  120. container.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.75).isActive = true
  121. container.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
  122. containerMinHeightConstraint.isActive = true
  123. let stackView = UIStackView(arrangedSubviews: [qrCodeView, hintLabel])
  124. stackView.axis = .vertical
  125. stackView.spacing = 10
  126. stackView.translatesAutoresizingMaskIntoConstraints = false
  127. container.addSubview(stackView)
  128. stackView.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
  129. stackView.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
  130. qrCodeView.translatesAutoresizingMaskIntoConstraints = false
  131. let qrCodeMinWidth = stackView.widthAnchor.constraint(lessThanOrEqualToConstant: 260)
  132. qrCodeMinWidth.priority = UILayoutPriority(rawValue: 1000)
  133. qrCodeMinWidth.isActive = true
  134. let qrCodeDefaultWidth = stackView.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 1)
  135. qrCodeDefaultWidth.priority = UILayoutPriority(500)
  136. qrCodeDefaultWidth.isActive = true
  137. qrCodeView.heightAnchor.constraint(equalTo: qrCodeView.widthAnchor, multiplier: 1).isActive = true
  138. hintLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
  139. let stackTopAnchor = stackView.topAnchor.constraint(equalTo: container.layoutMarginsGuide.topAnchor)
  140. stackTopAnchor.priority = .defaultLow
  141. stackTopAnchor.isActive = true
  142. let stackBottomAnchor = stackView.bottomAnchor.constraint(equalTo: container.layoutMarginsGuide.bottomAnchor)
  143. stackBottomAnchor.priority = .defaultLow
  144. stackBottomAnchor.isActive = true
  145. }
  146. }