diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index ac4781afb..eb7b36ad8 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -294,6 +294,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: ThreadListViewController.self) } + internal enum ThreadsBetaViewController: StoryboardType { + internal static let storyboardName = "ThreadsBetaViewController" + + internal static let initialScene = InitialSceneType(storyboard: ThreadsBetaViewController.self) + } internal enum ThreadsNoticeViewController: StoryboardType { internal static let storyboardName = "ThreadsNoticeViewController" diff --git a/Riot/Modules/Threads/Beta/ThreadsBetaViewController.storyboard b/Riot/Modules/Threads/Beta/ThreadsBetaViewController.storyboard new file mode 100644 index 000000000..3bf11bb2d --- /dev/null +++ b/Riot/Modules/Threads/Beta/ThreadsBetaViewController.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Keep discussions organised with threads. + +Threads help keep your conversations on-topic and easy to track. Learn more. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Threads/Beta/ThreadsBetaViewController.swift b/Riot/Modules/Threads/Beta/ThreadsBetaViewController.swift new file mode 100644 index 000000000..3a177fb63 --- /dev/null +++ b/Riot/Modules/Threads/Beta/ThreadsBetaViewController.swift @@ -0,0 +1,178 @@ +// +// Copyright 2022 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 + +class ThreadsBetaViewController: UIViewController { + + // MARK: Constants + + private enum Constants { + static let learnMoreLink = "https://element.io" + } + + // MARK: Outlets + + @IBOutlet private weak var titleLabel: UILabel! + @IBOutlet private weak var separatorLineView: UIView! + @IBOutlet private weak var informationTextView: UITextView! { + didSet { + informationTextView.contentInset = .zero + informationTextView.textContainerInset = .zero + informationTextView.textContainer.lineFragmentPadding = 0 + informationTextView.scrollsToTop = false + informationTextView.showsVerticalScrollIndicator = false + informationTextView.showsHorizontalScrollIndicator = false + informationTextView.isEditable = false + informationTextView.isScrollEnabled = false + } + } + @IBOutlet private weak var enableButton: UIButton! + @IBOutlet private weak var cancelButton: UIButton! + + // MARK: Private + + private var theme: Theme! + + // MARK: Public + + @objc var didTapEnableButton: (() -> Void)? + @objc var didTapCancelButton: (() -> Void)? + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + self.setupViews() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Hide back button + self.navigationItem.setHidesBackButton(true, animated: animated) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Setup + + @objc class func instantiate() -> ThreadsBetaViewController { + let viewController = StoryboardScene.ThreadsBetaViewController.initialScene.instantiate() + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Private + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, + selector: #selector(themeDidChange), + name: .themeServiceDidChangeTheme, + object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + self.vc_removeBackTitle() + + self.enableButton.setTitle(VectorL10n.threadsBetaEnable, for: .normal) + self.cancelButton.setTitle(VectorL10n.threadsBetaCancel, for: .normal) + + self.titleLabel.text = VectorL10n.threadsBetaTitle + guard let font = self.informationTextView.font else { + return + } + let attributedString = NSMutableAttributedString(string: VectorL10n.threadsBetaInformation, + attributes: [.font: font]) + let link = NSAttributedString(string: VectorL10n.threadsBetaInformationLink, + attributes: [.link: Constants.learnMoreLink, + .font: font]) + attributedString.append(link) + self.informationTextView.attributedText = attributedString + } + + // MARK: - Actions + + @IBAction private func enableButtonAction(_ sender: UIButton) { + self.didTapEnableButton?() + } + + @IBAction private func cancelButtonAction(_ sender: UIButton) { + self.didTapCancelButton?() + } + +} + +// MARK: - Themable + +extension ThreadsBetaViewController: Themable { + + func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.colors.background + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + self.titleLabel.textColor = theme.textPrimaryColor + self.separatorLineView.backgroundColor = theme.colors.system + self.informationTextView.textColor = theme.textPrimaryColor + + self.enableButton.vc_setBackgroundColor(theme.tintColor, for: .normal) + self.enableButton.setTitleColor(theme.baseTextPrimaryColor, for: .normal) + self.cancelButton.vc_setBackgroundColor(.clear, for: .normal) + self.cancelButton.setTitleColor(theme.tintColor, for: .normal) + } + +} + +// MARK: - SlidingModalPresentable + +extension ThreadsBetaViewController: SlidingModalPresentable { + + func allowsDismissOnBackgroundTap() -> Bool { + return false + } + + func layoutHeightFittingWidth(_ width: CGFloat) -> CGFloat { + guard let view = ThreadsNoticeViewController.instantiate().view else { + return 0 + } + + view.widthAnchor.constraint(equalToConstant: width).isActive = true + view.setNeedsLayout() + view.layoutIfNeeded() + + let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height) + + return view.systemLayoutSizeFitting(fittingSize).height + + UIWindow().safeAreaInsets.top + + UIWindow().safeAreaInsets.bottom + } + +}