// // Copyright 2020 New Vector Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import UIKit import Reusable @objc protocol SocialLoginListViewDelegate: class { func socialLoginListView(_ socialLoginListView: SocialLoginListView, didTapSocialButtonWithIdentifier identifier: String) } /// SocialLoginListView displays a list of social login buttons according to a given array of SSO Identity Providers. @objcMembers final class SocialLoginListView: UIView, NibLoadable { // MARK: - Constants private static let sizingView = SocialLoginListView.instantiate() private enum Constants { static let buttonHeight: CGFloat = 44.0 } // MARK: - Properties // MARK: Outlets @IBOutlet private weak var titleLabel: UILabel! @IBOutlet private weak var buttonsStackView: UIStackView! // MARK: Private private let socialButtonFactory: SocialLoginButtonFactory = SocialLoginButtonFactory() private var theme: Theme! private var buttons: [SocialLoginButton] = [] private(set) var mode: SocialLoginButtonMode = .continue // MARK: Public weak var delegate: SocialLoginListViewDelegate? // MARK: - Setup static func instantiate() -> SocialLoginListView { let view = SocialLoginListView.loadFromNib() view.theme = ThemeService.shared().theme return view } // MARK: - Public func update(with identityProviders: [MXLoginSSOIdentityProvider], mode: SocialLoginButtonMode) { self.mode = mode let title: String switch mode { case .continue: title = VectorL10n.socialLoginListTitleContinue case .signIn: title = VectorL10n.socialLoginListTitleSignIn case .signUp: title = VectorL10n.socialLoginListTitleSignUp } self.titleLabel.text = title self.removeButtons() let buttons = self.socialLoginButtons(for: identityProviders, mode: mode) for button in buttons { button.translatesAutoresizingMaskIntoConstraints = false button.heightAnchor.constraint(equalToConstant: Constants.buttonHeight).isActive = true self.buttonsStackView.addArrangedSubview(button) } self.buttons = buttons } static func contentViewHeight(identityProviders: [MXLoginSSOIdentityProvider], mode: SocialLoginButtonMode, fitting width: CGFloat) -> CGFloat { let sizingView = self.sizingView sizingView.frame = CGRect(x: 0, y: 0, width: width, height: 1) sizingView.update(with: identityProviders, mode: mode) sizingView.setNeedsLayout() sizingView.layoutIfNeeded() let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height) return sizingView.systemLayoutSizeFitting(fittingSize).height } // MARK: - Private private func removeButtons() { self.buttonsStackView.vc_removeAllSubviews() self.buttons = [] } private func socialLoginButtons(for identityProviders: [MXLoginSSOIdentityProvider], mode: SocialLoginButtonMode) -> [SocialLoginButton] { var buttons: [SocialLoginButton] = [] // Order alphabeticaly by Identity Provider identifier let sortedIdentityProviders = identityProviders.sorted { (firstIdentityProvider, secondIdentityProvider) -> Bool in firstIdentityProvider.identifier < secondIdentityProvider.identifier } for identityProvider in sortedIdentityProviders { let socialLoginButton = self.socialButtonFactory.build(with: identityProvider, mode: mode) socialLoginButton.update(theme: self.theme) socialLoginButton.addTarget(self, action: #selector(socialButtonAction(_:)), for: .touchUpInside) buttons.append(socialLoginButton) } return buttons } // MARK: - Action @objc private func socialButtonAction(_ socialLoginButton: SocialLoginButton) { guard let identifier = socialLoginButton.identifier else { return } self.delegate?.socialLoginListView(self, didTapSocialButtonWithIdentifier: identifier) } } // MARK: - Themable extension SocialLoginListView: Themable { func update(theme: Theme) { self.theme = theme self.titleLabel.textColor = theme.textSecondaryColor for button in self.buttons { button.update(theme: theme) } } }