228 lines
8.1 KiB
Swift
228 lines
8.1 KiB
Swift
/*
|
|
Copyright 2019-2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import Foundation
|
|
|
|
@objc protocol SettingsDiscoveryTableViewSectionDelegate: AnyObject {
|
|
|
|
func settingsDiscoveryTableViewSection(_ settingsDiscoveryTableViewSection: SettingsDiscoveryTableViewSection, tableViewCellClass: MXKTableViewCell.Type, forRow: Int) -> MXKTableViewCell
|
|
func settingsDiscoveryTableViewSectionDidUpdate(_ settingsDiscoveryTableViewSection: SettingsDiscoveryTableViewSection)
|
|
}
|
|
|
|
private enum DiscoverySectionRows {
|
|
case button(title: String, action: () -> Void)
|
|
case threePid(threePid: MX3PID)
|
|
}
|
|
|
|
@objc final class SettingsDiscoveryTableViewSection: NSObject, Themable {
|
|
|
|
// MARK: - Constants
|
|
|
|
private enum Constants {
|
|
static let defaultFont = UIFont.systemFont(ofSize: 17.0)
|
|
}
|
|
|
|
// MARK: - Properties
|
|
|
|
@objc weak var delegate: SettingsDiscoveryTableViewSectionDelegate?
|
|
|
|
@objc var attributedFooterTitle: NSAttributedString?
|
|
@objc var footerShouldScrollToUserSettings = false
|
|
|
|
// MARK: Private
|
|
|
|
private var theme: Theme!
|
|
private var viewModel: SettingsDiscoveryViewModel
|
|
|
|
// Need to know the state to make `cellForRow` deliver cells accordingly
|
|
private var viewState: SettingsDiscoveryViewState = .loading {
|
|
didSet {
|
|
self.updateRows()
|
|
}
|
|
}
|
|
|
|
private var discoveryRows: [DiscoverySectionRows] = []
|
|
|
|
// MARK: - Setup
|
|
|
|
@objc init(viewModel: SettingsDiscoveryViewModel) {
|
|
self.theme = ThemeService.shared().theme
|
|
self.viewModel = viewModel
|
|
super.init()
|
|
self.viewModel.viewDelegate = self
|
|
|
|
self.viewModel.process(viewAction: .load)
|
|
|
|
self.registerThemeServiceDidChangeThemeNotification()
|
|
}
|
|
|
|
// MARK: - Public
|
|
|
|
@objc func numberOfRows() -> Int {
|
|
return self.discoveryRows.count
|
|
}
|
|
|
|
@objc func cellForRow(atRow row: Int) -> UITableViewCell {
|
|
|
|
let discoveryRow = self.discoveryRows[row]
|
|
|
|
var cell: UITableViewCell?
|
|
|
|
let enableInteraction: Bool
|
|
|
|
if case .loading = self.viewState {
|
|
enableInteraction = false
|
|
} else {
|
|
enableInteraction = true
|
|
}
|
|
|
|
switch discoveryRow {
|
|
case .button(title: let title, action: let action):
|
|
if let buttonCell: MXKTableViewCellWithButton = self.cellType(at: row) {
|
|
buttonCell.mxkButton.setTitle(title, for: .normal)
|
|
buttonCell.mxkButton.setTitle(title, for: .highlighted)
|
|
buttonCell.mxkButton.vc_addAction(action: action)
|
|
buttonCell.mxkButton.isEnabled = enableInteraction
|
|
cell = buttonCell
|
|
}
|
|
case .threePid(let threePid):
|
|
if let detailCell: MXKTableViewCell = self.cellType(at: row) {
|
|
detailCell.vc_setAccessoryDisclosureIndicator(withTheme: self.theme)
|
|
|
|
let formattedThreePid: String?
|
|
|
|
switch threePid.medium {
|
|
case .email:
|
|
formattedThreePid = threePid.address
|
|
case .msisdn:
|
|
formattedThreePid = MXKTools.readableMSISDN(threePid.address)
|
|
default:
|
|
formattedThreePid = nil
|
|
}
|
|
|
|
detailCell.textLabel?.text = formattedThreePid
|
|
detailCell.isUserInteractionEnabled = enableInteraction
|
|
cell = detailCell
|
|
}
|
|
}
|
|
|
|
return cell ?? UITableViewCell()
|
|
}
|
|
|
|
@objc func reload() {
|
|
self.viewModel.process(viewAction: .load)
|
|
}
|
|
|
|
@objc func selectRow(_ row: Int) {
|
|
let discoveryRow = self.discoveryRows[row]
|
|
|
|
switch discoveryRow {
|
|
case .threePid(threePid: let threePid):
|
|
self.viewModel.process(viewAction: .select(threePid: threePid))
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func update(theme: Theme) {
|
|
self.theme = theme
|
|
|
|
self.updateRows()
|
|
}
|
|
|
|
// 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 cellType<T: MXKTableViewCell>(at row: Int) -> T? {
|
|
let klass: T.Type = T.self
|
|
let tableViewCell = delegate?.settingsDiscoveryTableViewSection(self, tableViewCellClass: klass, forRow: row)
|
|
return tableViewCell as? T
|
|
}
|
|
|
|
private func updateRows() {
|
|
|
|
// reset the footer
|
|
attributedFooterTitle = nil
|
|
footerShouldScrollToUserSettings = false
|
|
|
|
let discoveryRows: [DiscoverySectionRows]
|
|
|
|
switch self.viewState {
|
|
case .loading:
|
|
discoveryRows = self.discoveryRows
|
|
case .loaded(let displayMode):
|
|
switch displayMode {
|
|
case .noIdentityServer:
|
|
discoveryRows = []
|
|
attributedFooterTitle = NSAttributedString(string: VectorL10n.settingsDiscoveryNoIdentityServer)
|
|
case .termsNotSigned(let host):
|
|
discoveryRows = [
|
|
.button(title: VectorL10n.settingsDiscoveryAcceptTerms, action: { [weak self] in
|
|
self?.viewModel.process(viewAction: .acceptTerms)
|
|
})
|
|
]
|
|
|
|
attributedFooterTitle = NSAttributedString(string: VectorL10n.settingsDiscoveryTermsNotSigned(host))
|
|
case .noThreePidsAdded:
|
|
discoveryRows = []
|
|
|
|
attributedFooterTitle = threePidsManagementInfoAttributedString()
|
|
footerShouldScrollToUserSettings = true
|
|
case .threePidsAdded(let emails, let phoneNumbers):
|
|
|
|
let emailThreePids = emails.map { (email) -> DiscoverySectionRows in
|
|
return .threePid(threePid: email)
|
|
}
|
|
|
|
let phoneNumbersThreePids = phoneNumbers.map { (phoneNumber) -> DiscoverySectionRows in
|
|
return .threePid(threePid: phoneNumber)
|
|
}
|
|
|
|
discoveryRows = emailThreePids + phoneNumbersThreePids
|
|
|
|
attributedFooterTitle = threePidsManagementInfoAttributedString()
|
|
footerShouldScrollToUserSettings = true
|
|
}
|
|
case .error:
|
|
discoveryRows = [
|
|
.button(title: VectorL10n.retry, action: { [weak self] in
|
|
self?.viewModel.process(viewAction: .load)
|
|
})
|
|
]
|
|
attributedFooterTitle = NSAttributedString(string: VectorL10n.settingsDiscoveryErrorMessage)
|
|
}
|
|
|
|
self.discoveryRows = discoveryRows
|
|
}
|
|
|
|
private func threePidsManagementInfoAttributedString() -> NSAttributedString {
|
|
let attributedInfoString = NSMutableAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart1)
|
|
attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart2,
|
|
attributes: [.foregroundColor: self.theme.tintColor]))
|
|
attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart3))
|
|
return attributedInfoString
|
|
}
|
|
}
|
|
|
|
// MARK: - SettingsDiscoveryViewModelViewDelegate
|
|
extension SettingsDiscoveryTableViewSection: SettingsDiscoveryViewModelViewDelegate {
|
|
|
|
func settingsDiscoveryViewModel(_ viewModel: SettingsDiscoveryViewModelType, didUpdateViewState viewState: SettingsDiscoveryViewState) {
|
|
self.viewState = viewState
|
|
|
|
// The tableview datasource will call `self.cellForRow()`
|
|
self.delegate?.settingsDiscoveryTableViewSectionDidUpdate(self)
|
|
}
|
|
}
|