diff --git a/DesignKit/Source/FontsUIkit.swift b/DesignKit/Source/FontsUIkit.swift index b39f15f1b3..3067d03a1d 100644 --- a/DesignKit/Source/FontsUIkit.swift +++ b/DesignKit/Source/FontsUIkit.swift @@ -20,7 +20,7 @@ import UIKit /** ObjC class for holding fonts for use in UIKit. */ -@objc public class FontsUIKit: NSObject, Fonts { +@objcMembers public class FontsUIKit: NSObject, Fonts { public var largeTitle: UIFont diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 90551f97a5..8446263626 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -457,7 +457,6 @@ Tap the + to start adding people."; "settings_report_bug" = "Report bug"; "settings_clear_cache" = "Clear cache"; "settings_config_home_server" = "Homeserver is %@"; -"settings_config_identity_server" = "Identity server is %@"; "settings_config_user_id" = "Logged in as %@"; "settings_user_settings" = "USER SETTINGS"; @@ -473,7 +472,7 @@ Tap the + to start adding people."; "settings_contacts" = "DEVICE CONTACTS"; "settings_phone_contacts" = "PHONE CONTACTS"; "settings_advanced" = "ADVANCED"; -"settings_other" = "OTHER"; +"settings_about" = "ABOUT"; "settings_labs" = "LABS"; "settings_flair" = "Show flair where allowed"; "settings_devices" = "SESSIONS"; @@ -629,6 +628,7 @@ Tap the + to start adding people."; "settings_discovery_no_identity_server" = "You are not currently using an identity server. To be discoverable by existing contacts you known, add one."; "settings_discovery_terms_not_signed" = "Agree to the identity server (%@) Terms of Service to allow yourself to be discoverable by email address or phone number."; +"settings_discovery_accept_terms" = "Accept Identity Server Terms"; "settings_discovery_three_pids_management_information_part1" = "Manage which email addresses or phone numbers other users can use to discover you and use to invite you to rooms. Add or remove email addresses or phone numbers from this list in "; "settings_discovery_three_pids_management_information_part2" = "User Settings"; "settings_discovery_three_pids_management_information_part3" = "."; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 2801397ab0..54ca11b35d 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4087,6 +4087,10 @@ public class VectorL10n: NSObject { public static var serviceTermsModalTitleMessage: String { return VectorL10n.tr("Vector", "service_terms_modal_title_message") } + /// ABOUT + public static var settingsAbout: String { + return VectorL10n.tr("Vector", "settings_about") + } /// Invalid credentials public static var settingsAdd3pidInvalidPasswordMessage: String { return VectorL10n.tr("Vector", "settings_add_3pid_invalid_password_message") @@ -4147,10 +4151,6 @@ public class VectorL10n: NSObject { public static func settingsConfigHomeServer(_ p1: String) -> String { return VectorL10n.tr("Vector", "settings_config_home_server", p1) } - /// Identity server is %@ - public static func settingsConfigIdentityServer(_ p1: String) -> String { - return VectorL10n.tr("Vector", "settings_config_identity_server", p1) - } /// No build info public static var settingsConfigNoBuildInfo: String { return VectorL10n.tr("Vector", "settings_config_no_build_info") @@ -4243,6 +4243,10 @@ public class VectorL10n: NSObject { public static var settingsDirectMessages: String { return VectorL10n.tr("Vector", "settings_direct_messages") } + /// Accept Identity Server Terms + public static var settingsDiscoveryAcceptTerms: String { + return VectorL10n.tr("Vector", "settings_discovery_accept_terms") + } /// An error occured. Please retry. public static var settingsDiscoveryErrorMessage: String { return VectorL10n.tr("Vector", "settings_discovery_error_message") diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 7f4adf16c5..9e1ccd05ba 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -233,9 +233,6 @@ final class RiotSettings: NSObject { @UserDefault(key: "settingsScreenShowChangePassword", defaultValue: BuildSettings.settingsScreenShowChangePassword, storage: defaults) var settingsScreenShowChangePassword - @UserDefault(key: "settingsScreenShowInviteFriends", defaultValue: BuildSettings.settingsScreenShowInviteFriends, storage: defaults) - var settingsScreenShowInviteFriends - @UserDefault(key: "settingsScreenShowEnableStunServerFallback", defaultValue: BuildSettings.settingsScreenShowEnableStunServerFallback, storage: defaults) var settingsScreenShowEnableStunServerFallback diff --git a/Riot/Modules/Common/Models/Section.swift b/Riot/Modules/Common/Models/Section.swift index 29eb405005..8b7131208b 100644 --- a/Riot/Modules/Common/Models/Section.swift +++ b/Riot/Modules/Common/Models/Section.swift @@ -21,7 +21,35 @@ final class Section: NSObject { let tag: Int var rows: [Row] - var headerTitle: String? + var attributedHeaderTitle: NSAttributedString? + var attributedFooterTitle: NSAttributedString? + + var headerTitle: String? { + get { + attributedHeaderTitle?.string + } + set { + guard let newValue = newValue else { + attributedHeaderTitle = nil + return + } + + attributedHeaderTitle = NSAttributedString(string: newValue) + } + } + var footerTitle: String? { + get { + attributedFooterTitle?.string + } + set { + guard let newValue = newValue else { + attributedFooterTitle = nil + return + } + + attributedFooterTitle = NSAttributedString(string: newValue) + } + } init(withTag tag: Int) { self.tag = tag diff --git a/Riot/Modules/Common/SectionFooters/SectionFooterView.swift b/Riot/Modules/Common/SectionFooters/SectionFooterView.swift new file mode 100644 index 0000000000..92c36e88cf --- /dev/null +++ b/Riot/Modules/Common/SectionFooters/SectionFooterView.swift @@ -0,0 +1,76 @@ +// +// Copyright 2021 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 + +/// A subclass of `UITableViewHeaderFooterView` that conforms to `Themable` +/// to create a consistent looking custom footer inside of the app. If using gesture +/// recognizers on the view, be aware that these will be automatically removed on reuse. +@objcMembers +class SectionFooterView: UITableViewHeaderFooterView, NibLoadable, Themable { + + // MARK: - Properties + + static var defaultReuseIdentifier: String { + String(describing: Self.self) + } + + static var nib: UINib { + // Copy paste from NibReusable in order to expose to ObjC + UINib(nibName: String(describing: self), bundle: Bundle(for: self)) + } + + /// The amount to inset the footer label on its leading side, relative to the safe area insets. + var leadingInset: CGFloat { + get { footerLabelLeadingConstraint.constant } + set { footerLabelLeadingConstraint.constant = newValue } + } + + /// The text label added in the xib file. Using our own label was necessary due to the behaviour + /// on iOS 12-14 where any customisation to the existing text label is wiped out after being + /// set in `tableView:viewForFooterInSection`. This behaviour is fixed in iOS 15. + @IBOutlet private weak var footerLabel: UILabel! + /// The label's leading constraint, relative to the safe area insets. + @IBOutlet private weak var footerLabelLeadingConstraint: NSLayoutConstraint! + + // MARK: - Public + + override func prepareForReuse() { + super.prepareForReuse() + + for recognizer in gestureRecognizers ?? [] { + removeGestureRecognizer(recognizer) + } + } + + func update(theme: Theme) { + footerLabel.textColor = theme.colors.secondaryContent + footerLabel.font = theme.fonts.subheadline + footerLabel.numberOfLines = 0 + } + + /// Update the footer with new text. + func update(withText text: String) { + footerLabel.text = text + } + + /// Update the footer with attributed text. Be sure to call this after calling `update(theme:)` + /// otherwise any color or font attributes will be wiped out by the theme. + func update(withAttributedText attributedText: NSAttributedString) { + footerLabel.attributedText = attributedText + } +} diff --git a/Riot/Modules/Common/SectionFooters/SectionFooterView.xib b/Riot/Modules/Common/SectionFooters/SectionFooterView.xib new file mode 100644 index 0000000000..1dbf29848d --- /dev/null +++ b/Riot/Modules/Common/SectionFooters/SectionFooterView.xib @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Settings/Discovery/SettingsDiscoveryTableViewSection.swift b/Riot/Modules/Settings/Discovery/SettingsDiscoveryTableViewSection.swift index 6bee0aebe4..64e96878f3 100644 --- a/Riot/Modules/Settings/Discovery/SettingsDiscoveryTableViewSection.swift +++ b/Riot/Modules/Settings/Discovery/SettingsDiscoveryTableViewSection.swift @@ -23,8 +23,6 @@ import Foundation } private enum DiscoverySectionRows { - case info(text: String) - case attributedInfo(attributedText: NSAttributedString) case button(title: String, action: () -> Void) case threePid(threePid: MX3PID) } @@ -41,6 +39,9 @@ private enum DiscoverySectionRows { @objc weak var delegate: SettingsDiscoveryTableViewSectionDelegate? + @objc var attributedFooterTitle: NSAttributedString? + @objc var footerShouldScrollToUserSettings = false + // MARK: Private private var theme: Theme! @@ -89,20 +90,6 @@ private enum DiscoverySectionRows { } switch discoveryRow { - case .info(let infoText): - if let infoCell: MXKTableViewCell = self.cellType(at: row) { - infoCell.textLabel?.numberOfLines = 0 - infoCell.textLabel?.text = infoText - infoCell.selectionStyle = .none - cell = infoCell - } - case .attributedInfo(attributedText: let infoText): - if let infoCell: MXKTableViewCell = self.cellType(at: row) { - infoCell.textLabel?.numberOfLines = 0 - infoCell.textLabel?.attributedText = infoText - infoCell.selectionStyle = .none - cell = infoCell - } case .button(title: let title, action: let action): if let buttonCell: MXKTableViewCellWithButton = self.cellType(at: row) { buttonCell.mxkButton.setTitle(title, for: .normal) @@ -145,15 +132,6 @@ private enum DiscoverySectionRows { switch discoveryRow { case .threePid(threePid: let threePid): self.viewModel.process(viewAction: .select(threePid: threePid)) - case .attributedInfo(attributedText: _): - if case let .loaded(displayMode) = self.viewState { - switch displayMode { - case .noThreePidsAdded, .threePidsAdded: - self.viewModel.process(viewAction: .tapUserSettingsLink) - default: - break - } - } default: break } @@ -183,6 +161,10 @@ private enum DiscoverySectionRows { private func updateRows() { + // reset the footer + attributedFooterTitle = nil + footerShouldScrollToUserSettings = false + let discoveryRows: [DiscoverySectionRows] switch self.viewState { @@ -191,20 +173,21 @@ private enum DiscoverySectionRows { case .loaded(let displayMode): switch displayMode { case .noIdentityServer: - discoveryRows = [ - .info(text: VectorL10n.settingsDiscoveryNoIdentityServer) - ] + discoveryRows = [] + attributedFooterTitle = NSAttributedString(string: VectorL10n.settingsDiscoveryNoIdentityServer) case .termsNotSigned(let host): discoveryRows = [ - .info(text: VectorL10n.settingsDiscoveryTermsNotSigned(host)), - .button(title: VectorL10n.accept, action: { [weak self] in + .button(title: VectorL10n.settingsDiscoveryAcceptTerms, action: { [weak self] in self?.viewModel.process(viewAction: .acceptTerms) }) ] + + attributedFooterTitle = NSAttributedString(string: VectorL10n.settingsDiscoveryTermsNotSigned(host)) case .noThreePidsAdded: - discoveryRows = [ - .attributedInfo(attributedText: self.threePidsManagementInfoAttributedString()) - ] + discoveryRows = [] + + attributedFooterTitle = threePidsManagementInfoAttributedString() + footerShouldScrollToUserSettings = true case .threePidsAdded(let emails, let phoneNumbers): let emailThreePids = emails.map { (email) -> DiscoverySectionRows in @@ -215,32 +198,28 @@ private enum DiscoverySectionRows { return .threePid(threePid: phoneNumber) } - var threePidsRows: [DiscoverySectionRows] = [] - threePidsRows.append(contentsOf: emailThreePids) - threePidsRows.append(contentsOf: phoneNumbersThreePids) - threePidsRows.append(.attributedInfo(attributedText: self.threePidsManagementInfoAttributedString())) + discoveryRows = emailThreePids + phoneNumbersThreePids - discoveryRows = threePidsRows + attributedFooterTitle = threePidsManagementInfoAttributedString() + footerShouldScrollToUserSettings = true } case .error: discoveryRows = [ - .info(text: VectorL10n.settingsDiscoveryErrorMessage), .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, - attributes: [.foregroundColor: self.theme.textPrimaryColor, .font: Constants.defaultFont]) + let attributedInfoString = NSMutableAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart1) attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart2, - attributes: [.foregroundColor: self.theme.tintColor, .font: Constants.defaultFont])) - attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart3, - attributes: [.foregroundColor: self.theme.tintColor, .font: Constants.defaultFont])) + attributes: [.foregroundColor: self.theme.tintColor])) + attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart3)) return attributedInfoString } } diff --git a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewAction.swift b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewAction.swift index 2122ee1755..d51ddba177 100644 --- a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewAction.swift +++ b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewAction.swift @@ -21,5 +21,4 @@ enum SettingsDiscoveryViewAction { case load case acceptTerms case select(threePid: MX3PID) - case tapUserSettingsLink } diff --git a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModel.swift b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModel.swift index b512992bec..c0e3749a7e 100644 --- a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModel.swift +++ b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModel.swift @@ -54,13 +54,11 @@ import Foundation func process(viewAction: SettingsDiscoveryViewAction) { switch viewAction { case .load: - self.checkTerms() + checkTerms() case .acceptTerms: - self.acceptTerms() + coordinatorDelegate?.settingsDiscoveryViewModelDidTapAcceptIdentityServerTerms(self) case .select(threePid: let threePid): - self.coordinatorDelegate?.settingsDiscoveryViewModel(self, didSelectThreePidWith: threePid.medium.identifier, and: threePid.address) - case .tapUserSettingsLink: - self.coordinatorDelegate?.settingsDiscoveryViewModelDidTapUserSettingsLink(self) + coordinatorDelegate?.settingsDiscoveryViewModel(self, didSelectThreePidWith: threePid.medium.identifier, and: threePid.address) } } @@ -116,28 +114,6 @@ import Foundation }) } - private func acceptTerms() { - guard let identityService = self.identityService else { - self.update(viewState: .loaded(displayMode: .noIdentityServer)) - return - } - - // Launch an identity server request to trigger terms modal apparition - identityService.account { (response) in - switch response { - case .success: - // Display three pids if presents - self.updateViewStateFromCurrentThreePids() - case .failure(let error): - if MXError(nsError: error)?.errcode == kMXErrCodeStringTermsNotSigned { - // Identity terms modal should appear - } else { - self.update(viewState: .error(error)) - } - } - } - } - private func canCheckTerms() -> Bool { guard let viewState = self.viewState else { return true diff --git a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModelType.swift b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModelType.swift index 0435a5eb58..8dfbbec347 100644 --- a/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModelType.swift +++ b/Riot/Modules/Settings/Discovery/SettingsDiscoveryViewModelType.swift @@ -22,7 +22,7 @@ protocol SettingsDiscoveryViewModelViewDelegate: AnyObject { @objc protocol SettingsDiscoveryViewModelCoordinatorDelegate: AnyObject { func settingsDiscoveryViewModel(_ viewModel: SettingsDiscoveryViewModel, didSelectThreePidWith medium: String, and address: String) - func settingsDiscoveryViewModelDidTapUserSettingsLink(_ viewModel: SettingsDiscoveryViewModel) + func settingsDiscoveryViewModelDidTapAcceptIdentityServerTerms(_ viewModel: SettingsDiscoveryViewModel) } protocol SettingsDiscoveryViewModelType { diff --git a/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m b/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m index b38d68892b..930ab58999 100644 --- a/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m +++ b/Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m @@ -399,19 +399,6 @@ - (MXKTableViewCell*)trustCellWithDevice:(MXDevice*)device forTableView:(UITable return cell; } -- (MXKTableViewCell*)descriptionCellForTableView:(UITableView*)tableView withText:(NSString*)text -{ - MXKTableViewCell *cell = [self getDefaultTableViewCell:tableView]; - cell.textLabel.text = text; - cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - cell.textLabel.numberOfLines = 0; - cell.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - - return cell; -} - - - (MXKTableViewCellWithTextView*)textViewCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath { MXKTableViewCellWithTextView *textViewCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier] forIndexPath:indexPath]; @@ -516,8 +503,8 @@ - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view { // Customize label style UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view; - tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - tableViewHeaderFooterView.textLabel.font = [UIFont systemFontOfSize:15]; + tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent; + tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote; } } diff --git a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift index cc23c878c7..ffeed21214 100644 --- a/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift +++ b/Riot/Modules/Settings/Security/SecureBackup/SettingsSecureBackupTableViewSection.swift @@ -21,7 +21,6 @@ import UIKit func settingsSecureBackupTableViewSectionDidUpdate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection) func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, textCellForRow: Int) -> MXKTableViewCellWithTextView - func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, descriptionCellForRow: Int) -> MXKTableViewCell func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, buttonCellForRow: Int) -> MXKTableViewCellWithButton // Secure backup @@ -39,7 +38,6 @@ import UIKit private enum BackupRows { case info(text: String) - case description(text: String) case createSecureBackupAction case resetSecureBackupAction case createKeyBackupAction @@ -96,8 +94,6 @@ private enum BackupRows { switch backupRow { case .info(let text): cell = self.textCell(atRow: row, text: text) - case .description(let text): - cell = self.descriptionCell(atRow: row, text: text) case .createSecureBackupAction: cell = self.buttonCellForCreateSecureBackup(atRow: row) case .resetSecureBackupAction: @@ -130,8 +126,7 @@ private enum BackupRows { switch self.viewState { case .loading: backupRows = [ - .info(text: VectorL10n.securitySettingsSecureBackupInfoChecking), - .description(text: VectorL10n.securitySettingsSecureBackupDescription) + .info(text: VectorL10n.securitySettingsSecureBackupInfoChecking) ] case .noSecureBackup(let keyBackupState): @@ -143,16 +138,14 @@ private enum BackupRows { backupRows = [ .info(text: infoText), - .createSecureBackupAction, - .description(text: VectorL10n.securitySettingsSecureBackupDescription) + .createSecureBackupAction ] case .keyBackup(let keyBackupVersion, _, _), .keyBackupNotTrusted(let keyBackupVersion, _): // Manage the key backup in the same way for the moment backupRows = [ .info(text: VectorL10n.securitySettingsSecureBackupInfoValid), .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore), - .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion), - .description(text: VectorL10n.securitySettingsSecureBackupDescription) + .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion) ] } case .secureBackup(let keyBackupState): @@ -165,8 +158,7 @@ private enum BackupRows { backupRows = [ .info(text: infoText), .createKeyBackupAction, - .resetSecureBackupAction, - .description(text: VectorL10n.securitySettingsSecureBackupDescription) + .resetSecureBackupAction ] case .keyBackup(let keyBackupVersion, _, _), .keyBackupNotTrusted(let keyBackupVersion, _): // Manage the key backup in the same way for the moment @@ -174,8 +166,7 @@ private enum BackupRows { .info(text: VectorL10n.securitySettingsSecureBackupInfoValid), .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore), .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion), - .resetSecureBackupAction, - .description(text: VectorL10n.securitySettingsSecureBackupDescription) + .resetSecureBackupAction ] } } @@ -194,16 +185,6 @@ private enum BackupRows { return cell } - private func descriptionCell(atRow row: Int, text: String) -> UITableViewCell { - guard let delegate = self.delegate else { - return UITableViewCell() - } - - let cell = delegate.settingsSecureBackupTableViewSection(self, descriptionCellForRow: row) - cell.textLabel?.text = text - return cell - } - // MARK: - Button cells private func buttonCellForCreateSecureBackup(atRow row: Int) -> UITableViewCell { diff --git a/Riot/Modules/Settings/Security/SecurityViewController.m b/Riot/Modules/Settings/Security/SecurityViewController.m index c77a2f23b5..fce6d5c9b0 100644 --- a/Riot/Modules/Settings/Security/SecurityViewController.m +++ b/Riot/Modules/Settings/Security/SecurityViewController.m @@ -53,7 +53,6 @@ enum { PIN_CODE_SETTING, - PIN_CODE_DESCRIPTION, PIN_CODE_CHANGE, PIN_CODE_BIOMETRICS, PIN_CODE_COUNT @@ -67,7 +66,6 @@ enum { ADVANCED_BLACKLIST_UNVERIFIED_DEVICES, - ADVANCED_BLACKLIST_UNVERIFIED_DEVICES_DESCRIPTION, ADVANCED_COUNT }; @@ -161,10 +159,13 @@ - (void)viewDidLoad [self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]]; [self.tableView registerNib:MXKTableViewCellWithTextView.nib forCellReuseIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]]; [self.tableView registerNib:MXKTableViewCellWithButton.nib forCellReuseIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; + [self.tableView registerNib:SectionFooterView.nib forHeaderFooterViewReuseIdentifier:[SectionFooterView defaultReuseIdentifier]]; - // Enable self sizing cells + // Enable self sizing cells and footers self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 50; + self.tableView.sectionFooterHeight = UITableViewAutomaticDimension; + self.tableView.estimatedSectionFooterHeight = 50; if (self.mainSession.crypto.backup) { @@ -291,17 +292,20 @@ - (void)updateSections Section *pinCodeSection = [Section sectionWithTag:SECTION_PIN_CODE]; - // Header title + // Header and footer if ([PinCodePreferences shared].isBiometricsAvailable) { pinCodeSection.headerTitle = [VectorL10n pinProtectionSettingsSectionHeaderWithBiometrics:[PinCodePreferences shared].localizedBiometricsName]; } else { pinCodeSection.headerTitle = [VectorL10n pinProtectionSettingsSectionHeader]; } + if (PinCodePreferences.shared.isPinSet) + { + pinCodeSection.footerTitle = VectorL10n.pinProtectionSettingsSectionFooter; + } // Rows [pinCodeSection addRowWithTag:PIN_CODE_SETTING]; - [pinCodeSection addRowWithTag:PIN_CODE_DESCRIPTION]; if ([PinCodePreferences shared].isPinSet) { @@ -322,19 +326,16 @@ - (void)updateSections Section *sessionsSection = [Section sectionWithTag:SECTION_CRYPTO_SESSIONS]; sessionsSection.headerTitle = [VectorL10n securitySettingsCryptoSessions]; - - NSUInteger sessionsSectionRowsCount; if (self.showLoadingDevicesInformation) { - sessionsSectionRowsCount = 2; + sessionsSection.footerTitle = VectorL10n.securitySettingsCryptoSessionsLoading; } else { - sessionsSectionRowsCount = devicesArray.count + 1; + sessionsSection.footerTitle = VectorL10n.securitySettingsCryptoSessionsDescription2; + [sessionsSection addRowsWithCount:devicesArray.count]; } - - [sessionsSection addRowsWithCount:sessionsSectionRowsCount]; [sections addObject:sessionsSection]; } @@ -343,6 +344,7 @@ - (void)updateSections Section *secureBackupSection = [Section sectionWithTag:SECTION_SECURE_BACKUP]; secureBackupSection.headerTitle = [VectorL10n securitySettingsSecureBackup]; + secureBackupSection.footerTitle = VectorL10n.securitySettingsSecureBackupDescription; [secureBackupSection addRowsWithCount:self->secureBackupSection.numberOfRows]; @@ -392,17 +394,13 @@ - (void)updateSections // Advanced - Section *advancedSection = [Section sectionWithTag:SECTION_ADVANCED]; - advancedSection.headerTitle = [VectorL10n securitySettingsAdvanced]; - if (RiotSettings.shared.settingsSecurityScreenShowAdvancedUnverifiedDevices) { + Section *advancedSection = [Section sectionWithTag:SECTION_ADVANCED]; + advancedSection.headerTitle = VectorL10n.securitySettingsAdvanced; + advancedSection.footerTitle = VectorL10n.securitySettingsBlacklistUnverifiedDevicesDescription; + [advancedSection addRowWithTag:ADVANCED_BLACKLIST_UNVERIFIED_DEVICES]; - [advancedSection addRowWithTag:ADVANCED_BLACKLIST_UNVERIFIED_DEVICES_DESCRIPTION]; - } - - if (advancedSection.rows.count) - { [sections addObject:advancedSection]; } @@ -1107,20 +1105,6 @@ - (UIImage*)shieldImageForDevice:(NSString*)deviceId return shieldImageForDevice; } - -- (MXKTableViewCell*)descriptionCellForTableView:(UITableView*)tableView withText:(NSString*)text -{ - MXKTableViewCell *cell = [self getDefaultTableViewCell:tableView]; - cell.textLabel.text = text; - cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - cell.textLabel.numberOfLines = 0; - cell.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - - return cell; -} - - - (MXKTableViewCellWithTextView*)textViewCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath { MXKTableViewCellWithTextView *textViewCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier] forIndexPath:indexPath]; @@ -1135,17 +1119,6 @@ - (MXKTableViewCellWithTextView*)textViewCellForTableView:(UITableView*)tableVie return textViewCell; } -- (MXKTableViewCell*)descriptionCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath -{ - MXKTableViewCell *cell = [self getDefaultTableViewCell:tableView]; - cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - cell.textLabel.numberOfLines = 0; - cell.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - - return cell; -} - - (MXKTableViewCellWithButton *)buttonCellForTableView:(UITableView*)tableView atIndexPath:(NSIndexPath *)indexPath { MXKTableViewCellWithButton *cell = [self.tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath]; @@ -1218,18 +1191,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.selectionStyle = UITableViewCellSelectionStyleNone; } - else if (rowTag == PIN_CODE_DESCRIPTION) - { - if ([PinCodePreferences shared].isPinSet) - { - cell = [self descriptionCellForTableView:tableView - withText:[VectorL10n pinProtectionSettingsSectionFooter]]; - } - else - { - cell = [self descriptionCellForTableView:tableView withText:nil]; - } - } else if (rowTag == PIN_CODE_CHANGE) { cell = [self buttonCellWithTitle:[VectorL10n pinProtectionSettingsChangePin] action:@selector(changePinCode:) forTableView:tableView atIndexPath:indexPath]; @@ -1248,32 +1209,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (sectionTag == SECTION_CRYPTO_SESSIONS) { - if (self.showLoadingDevicesInformation) - { - if (rowTag == 0) - { - cell = [self descriptionCellForTableView:tableView - withText:[VectorL10n securitySettingsCryptoSessionsLoading]]; - } - else - { - cell = [self descriptionCellForTableView:tableView - withText:[VectorL10n securitySettingsCryptoSessionsDescription2]]; - } - } - else - { - if (rowTag < devicesArray.count) - { - cell = [self deviceCellWithDevice:devicesArray[rowTag] forTableView:tableView]; - } - else if (rowTag == devicesArray.count) - { - cell = [self descriptionCellForTableView:tableView - withText:[VectorL10n securitySettingsCryptoSessionsDescription2]]; - - } - } + cell = [self deviceCellWithDevice:devicesArray[rowTag] forTableView:tableView]; } else if (sectionTag == SECTION_SECURE_BACKUP) { @@ -1343,13 +1279,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; break; } - case ADVANCED_BLACKLIST_UNVERIFIED_DEVICES_DESCRIPTION: - { - cell = [self descriptionCellForTableView:tableView - withText:[VectorL10n securitySettingsBlacklistUnverifiedDevicesDescription]]; - - break; - } } } @@ -1368,11 +1297,27 @@ - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view { // Customize label style UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view; - tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - tableViewHeaderFooterView.textLabel.font = [UIFont systemFontOfSize:15]; + tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent; + tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote; } } +- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section +{ + NSString *footerTitle = [_tableViewSections sectionAtIndex:section].footerTitle; + + if (!footerTitle) + { + return nil; + } + + SectionFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionFooterView.defaultReuseIdentifier]; + [view updateWithTheme:ThemeService.shared.theme]; + view.leadingInset = tableView.vc_separatorInset.left; + [view updateWithText:footerTitle]; + + return view; +} #pragma mark - UITableView delegate @@ -1402,20 +1347,6 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce } } -- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section -{ - if (section == SECTION_CRYPTO_SESSIONS) - { - return 44; - } - return 24; -} - -- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section -{ - return 24; -} - - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (self.tableView == tableView) @@ -1620,20 +1551,6 @@ - (MXKTableViewCellWithTextView *)settingsSecureBackupTableViewSection:(Settings return cell; } -- (MXKTableViewCell *)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection descriptionCellForRow:(NSInteger)textCellForRow -{ - MXKTableViewCell *cell; - - NSIndexPath *indexPath = [self.tableViewSections exactIndexPathForRowTag:textCellForRow sectionTag:SECTION_SECURE_BACKUP]; - - if (indexPath) - { - cell = [self descriptionCellForTableView:self.tableView atIndexPath:indexPath]; - } - - return cell; -} - - (MXKTableViewCellWithButton *)settingsSecureBackupTableViewSection:(SettingsSecureBackupTableViewSection *)settingsSecureBackupTableViewSection buttonCellForRow:(NSInteger)buttonCellForRow { MXKTableViewCellWithButton *cell; diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 6d91b43577..0a5acf57c3 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -63,7 +63,7 @@ SECTION_TAG_INTEGRATIONS, SECTION_TAG_USER_INTERFACE, SECTION_TAG_ADVANCED, - SECTION_TAG_OTHER, + SECTION_TAG_ABOUT, SECTION_TAG_LABS, SECTION_TAG_FLAIR, SECTION_TAG_DEACTIVATE_ACCOUNT @@ -77,9 +77,7 @@ USER_SETTINGS_FIRST_NAME_INDEX, USER_SETTINGS_SURNAME_INDEX, USER_SETTINGS_ADD_EMAIL_INDEX, - USER_SETTINGS_ADD_PHONENUMBER_INDEX, - USER_SETTINGS_THREEPIDS_INFORMATION_INDEX, - USER_SETTINGS_INVITE_FRIENDS_INDEX + USER_SETTINGS_ADD_PHONENUMBER_INDEX }; enum @@ -90,8 +88,7 @@ enum { - SENDING_MEDIA_CONFIRM_SIZE = 0, - SENDING_MEDIA_CONFIRM_SIZE_DESCRIPTION, + SENDING_MEDIA_CONFIRM_SIZE = 0 }; enum @@ -105,7 +102,6 @@ NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0, NOTIFICATION_SETTINGS_SYSTEM_SETTINGS, NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT, - NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX, NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX, NOTIFICATION_SETTINGS_PIN_UNREAD_INDEX, NOTIFICATION_SETTINGS_DEFAULT_SETTINGS_INDEX, @@ -115,20 +111,17 @@ enum { - CALLS_ENABLE_STUN_SERVER_FALLBACK_INDEX=0, - CALLS_STUN_SERVER_FALLBACK_DESCRIPTION_INDEX, + CALLS_ENABLE_STUN_SERVER_FALLBACK_INDEX = 0 }; enum { - INTEGRATIONS_INDEX, - INTEGRATIONS_DESCRIPTION_INDEX, + INTEGRATIONS_INDEX }; enum { LOCAL_CONTACTS_SYNC_INDEX, - LOCAL_CONTACTS_PHONEBOOK_COUNTRY_INDEX, - LOCAL_CONTACTS_SYNC_DESCRIPTION_INDEX + LOCAL_CONTACTS_PHONEBOOK_COUNTRY_INDEX }; enum @@ -139,24 +132,25 @@ enum { - IDENTITY_SERVER_INDEX, - IDENTITY_SERVER_DESCRIPTION_INDEX, + IDENTITY_SERVER_INDEX }; enum { - OTHER_VERSION_INDEX = 0, - OTHER_OLM_VERSION_INDEX, - OTHER_COPYRIGHT_INDEX, - OTHER_TERM_CONDITIONS_INDEX, - OTHER_PRIVACY_INDEX, - OTHER_THIRD_PARTY_INDEX, - OTHER_SHOW_NSFW_ROOMS_INDEX, - OTHER_CRASH_REPORT_INDEX, - OTHER_ENABLE_RAGESHAKE_INDEX, - OTHER_MARK_ALL_AS_READ_INDEX, - OTHER_CLEAR_CACHE_INDEX, - OTHER_REPORT_BUG_INDEX, + ADVANCED_SHOW_NSFW_ROOMS_INDEX = 0, + ADVANCED_CRASH_REPORT_INDEX, + ADVANCED_ENABLE_RAGESHAKE_INDEX, + ADVANCED_MARK_ALL_AS_READ_INDEX, + ADVANCED_CLEAR_CACHE_INDEX, + ADVANCED_REPORT_BUG_INDEX, +}; + +enum +{ + ABOUT_COPYRIGHT_INDEX = 0, + ABOUT_TERM_CONDITIONS_INDEX, + ABOUT_PRIVACY_INDEX, + ABOUT_THIRD_PARTY_INDEX, }; enum @@ -274,14 +268,18 @@ @interface SettingsViewController () 0) + { + NSIndexPath *discoveryIndexPath = [_tableViewSections exactIndexPathForRowTag:0 sectionTag:SECTION_TAG_DISCOVERY]; + if (discoveryIndexPath) + { + [self.tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; + } + } + else + { + // this won't be precise in scroll location, but seems the best option for now + NSIndexPath *discoveryIndexPath = [_tableViewSections nearestIndexPathForRowTag:0 sectionTag:SECTION_TAG_DISCOVERY]; + if (discoveryIndexPath) + { + [self.tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; + } + } +} + +- (void)scrollToUserSettingsSection +{ + NSIndexPath *discoveryIndexPath = [_tableViewSections exactIndexPathForRowTag:USER_SETTINGS_ADD_EMAIL_INDEX + sectionTag:SECTION_TAG_USER_SETTINGS]; + if (discoveryIndexPath) + { + [self.tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; + } +} + #pragma mark - 3Pid Add - (void)showAuthenticationIfNeededForAdding:(MX3PIDMedium)medium withSession:(MXSession*)session completion:(void (^)(NSDictionary* authParams))completion @@ -1826,33 +1865,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = newPhoneCell; } } - else if (row == USER_SETTINGS_THREEPIDS_INFORMATION_INDEX) - { - MXKTableViewCell *threePidsInformationCell = [self getDefaultTableViewCell:self.tableView]; - - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart1] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.textPrimaryColor}]; - [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart2] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.tintColor}]]; - [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart3] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.textPrimaryColor}]]; - - threePidsInformationCell.textLabel.attributedText = attributedString; - threePidsInformationCell.textLabel.numberOfLines = 0; - - threePidsInformationCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = threePidsInformationCell; - } - else if (row == USER_SETTINGS_INVITE_FRIENDS_INDEX) - { - MXKTableViewCell *inviteFriendsCell = [self getDefaultTableViewCell:tableView]; - - inviteFriendsCell.textLabel.text = [VectorL10n inviteFriendsAction:BuildSettings.bundleDisplayName]; - - UIImage *shareActionImage = [[UIImage imageNamed:@"share_action_button"] vc_tintedImageUsingColor:ThemeService.shared.theme.tintColor]; - UIImageView *accessoryView = [[UIImageView alloc] initWithImage:shareActionImage]; - inviteFriendsCell.accessoryView = accessoryView; - - cell = inviteFriendsCell; - } else if (row == USER_SETTINGS_CHANGE_PASSWORD_INDEX) { MXKTableViewCellWithLabelAndTextField *passwordCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; @@ -1879,15 +1891,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; } - else if (row == SENDING_MEDIA_CONFIRM_SIZE_DESCRIPTION) - { - MXKTableViewCell *infoCell = [self getDefaultTableViewCell:tableView]; - infoCell.textLabel.text = [VectorL10n settingsConfirmMediaSizeDescription]; - infoCell.textLabel.numberOfLines = 0; - infoCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = infoCell; - } } else if (section == SECTION_TAG_LINKS) { @@ -1966,19 +1969,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; } - else if (row == NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX) - { - MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView]; - - NSString *appDisplayName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"]; - - globalInfoCell.textLabel.text = [VectorL10n settingsGlobalSettingsInfo:appDisplayName]; - globalInfoCell.textLabel.numberOfLines = 0; - - globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = globalInfoCell; - } else if (row == NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX) { MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -2034,19 +2024,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; } - else if (row == CALLS_STUN_SERVER_FALLBACK_DESCRIPTION_INDEX) - { - NSString *stunFallbackHost = BuildSettings.stunServerFallbackUrlString; - // Remove "stun:" - stunFallbackHost = [stunFallbackHost componentsSeparatedByString:@":"].lastObject; - - MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView]; - globalInfoCell.textLabel.text = [VectorL10n settingsCallsStunServerFallbackDescription:stunFallbackHost]; - globalInfoCell.textLabel.numberOfLines = 0; - globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = globalInfoCell; - } } else if (section == SECTION_TAG_DISCOVERY) { @@ -2073,25 +2050,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N break; } - case IDENTITY_SERVER_DESCRIPTION_INDEX: - { - MXKTableViewCell *descriptionCell = [self getDefaultTableViewCell:tableView]; - - if (account.mxSession.identityService.identityServer) - { - descriptionCell.textLabel.text = [VectorL10n settingsIdentityServerDescription]; - } - else - { - descriptionCell.textLabel.text = [VectorL10n settingsIdentityServerNoIsDescription]; - } - descriptionCell.textLabel.numberOfLines = 0; - descriptionCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = descriptionCell; - break; - } - default: break; } @@ -2114,22 +2072,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N break; } - case INTEGRATIONS_DESCRIPTION_INDEX: - { - MXKTableViewCell *descriptionCell = [self getDefaultTableViewCell:tableView]; - - NSString *integrationManager = [WidgetManager.sharedManager configForUser:session.myUser.userId].apiUrl; - NSString *integrationManagerDomain = [NSURL URLWithString:integrationManager].host; - - NSString *description = [VectorL10n settingsIntegrationsAllowDescription:integrationManagerDomain]; - descriptionCell.textLabel.text = description; - descriptionCell.textLabel.numberOfLines = 0; - descriptionCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = descriptionCell; - break; - } - default: break; } @@ -2233,91 +2175,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [cell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; cell.selectionStyle = UITableViewCellSelectionStyleDefault; } - else if (row == LOCAL_CONTACTS_SYNC_DESCRIPTION_INDEX) - { - MXKTableViewCell *descriptionCell = [self getDefaultTableViewCell:tableView]; - descriptionCell.textLabel.text = VectorL10n.settingsContactsEnableSyncDescription; - descriptionCell.textLabel.numberOfLines = 0; - descriptionCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = descriptionCell; - } } else if (section == SECTION_TAG_ADVANCED) { - MXKTableViewCellWithTextView *configCell = [self textViewCellForTableView:tableView atIndexPath:indexPath]; - - configCell.mxkTextView.text = [NSString stringWithFormat:@"%@\n%@\n%@", [MatrixKitL10n settingsConfigUserId:account.mxCredentials.userId], [MatrixKitL10n settingsConfigHomeServer:account.mxCredentials.homeServer], [MatrixKitL10n settingsConfigIdentityServer:account.identityServerURL]]; - configCell.mxkTextView.accessibilityIdentifier=@"SettingsVCConfigStaticText"; - - cell = configCell; - } - else if (section == SECTION_TAG_OTHER) - { - if (row == OTHER_VERSION_INDEX) - { - MXKTableViewCell *versionCell = [self getDefaultTableViewCell:tableView]; - - NSString* appVersion = [AppDelegate theDelegate].appVersion; - NSString* build = [AppDelegate theDelegate].build; - - versionCell.textLabel.text = [VectorL10n settingsVersion:[NSString stringWithFormat:@"%@ %@", appVersion, build]]; - - versionCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = versionCell; - } - else if (row == OTHER_OLM_VERSION_INDEX) - { - MXKTableViewCell *versionCell = [self getDefaultTableViewCell:tableView]; - - versionCell.textLabel.text = [VectorL10n settingsOlmVersion:[OLMKit versionString]]; - - versionCell.selectionStyle = UITableViewCellSelectionStyleNone; - - cell = versionCell; - } - else if (row == OTHER_TERM_CONDITIONS_INDEX) - { - MXKTableViewCell *termAndConditionCell = [self getDefaultTableViewCell:tableView]; - - termAndConditionCell.textLabel.text = [VectorL10n settingsTermConditions]; - - [termAndConditionCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; - - cell = termAndConditionCell; - } - else if (row == OTHER_COPYRIGHT_INDEX) - { - MXKTableViewCell *copyrightCell = [self getDefaultTableViewCell:tableView]; - - copyrightCell.textLabel.text = [VectorL10n settingsCopyright]; - - [copyrightCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; - - cell = copyrightCell; - } - else if (row == OTHER_PRIVACY_INDEX) - { - MXKTableViewCell *privacyPolicyCell = [self getDefaultTableViewCell:tableView]; - - privacyPolicyCell.textLabel.text = [VectorL10n settingsPrivacyPolicy]; - - [privacyPolicyCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; - - cell = privacyPolicyCell; - } - else if (row == OTHER_THIRD_PARTY_INDEX) - { - MXKTableViewCell *thirdPartyCell = [self getDefaultTableViewCell:tableView]; - - thirdPartyCell.textLabel.text = [VectorL10n settingsThirdPartyNotices]; - - [thirdPartyCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; - - cell = thirdPartyCell; - } - else if (row == OTHER_SHOW_NSFW_ROOMS_INDEX) + if (row == ADVANCED_SHOW_NSFW_ROOMS_INDEX) { MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -2330,7 +2191,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; } - else if (row == OTHER_CRASH_REPORT_INDEX) + else if (row == ADVANCED_CRASH_REPORT_INDEX) { MXKTableViewCellWithLabelAndSwitch* sendCrashReportCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -2342,7 +2203,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = sendCrashReportCell; } - else if (row == OTHER_ENABLE_RAGESHAKE_INDEX) + else if (row == ADVANCED_ENABLE_RAGESHAKE_INDEX) { MXKTableViewCellWithLabelAndSwitch* enableRageShakeCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -2354,7 +2215,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = enableRageShakeCell; } - else if (row == OTHER_MARK_ALL_AS_READ_INDEX) + else if (row == ADVANCED_MARK_ALL_AS_READ_INDEX) { MXKTableViewCellWithButton *markAllBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; if (!markAllBtnCell) @@ -2379,7 +2240,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = markAllBtnCell; } - else if (row == OTHER_CLEAR_CACHE_INDEX) + else if (row == ADVANCED_CLEAR_CACHE_INDEX) { MXKTableViewCellWithButton *clearCacheBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; if (!clearCacheBtnCell) @@ -2404,7 +2265,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = clearCacheBtnCell; } - else if (row == OTHER_REPORT_BUG_INDEX) + else if (row == ADVANCED_REPORT_BUG_INDEX) { MXKTableViewCellWithButton *reportBugBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; if (!reportBugBtnCell) @@ -2430,6 +2291,49 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = reportBugBtnCell; } } + else if (section == SECTION_TAG_ABOUT) + { + if (row == ABOUT_TERM_CONDITIONS_INDEX) + { + MXKTableViewCell *termAndConditionCell = [self getDefaultTableViewCell:tableView]; + + termAndConditionCell.textLabel.text = [VectorL10n settingsTermConditions]; + + [termAndConditionCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; + + cell = termAndConditionCell; + } + else if (row == ABOUT_COPYRIGHT_INDEX) + { + MXKTableViewCell *copyrightCell = [self getDefaultTableViewCell:tableView]; + + copyrightCell.textLabel.text = [VectorL10n settingsCopyright]; + + [copyrightCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; + + cell = copyrightCell; + } + else if (row == ABOUT_PRIVACY_INDEX) + { + MXKTableViewCell *privacyPolicyCell = [self getDefaultTableViewCell:tableView]; + + privacyPolicyCell.textLabel.text = [VectorL10n settingsPrivacyPolicy]; + + [privacyPolicyCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; + + cell = privacyPolicyCell; + } + else if (row == ABOUT_THIRD_PARTY_INDEX) + { + MXKTableViewCell *thirdPartyCell = [self getDefaultTableViewCell:tableView]; + + thirdPartyCell.textLabel.text = [VectorL10n settingsThirdPartyNotices]; + + [thirdPartyCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; + + cell = thirdPartyCell; + } + } else if (section == SECTION_TAG_LABS) { if (row == LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX) @@ -2524,11 +2428,39 @@ - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view { // Customize label style UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view; - tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - tableViewHeaderFooterView.textLabel.font = [UIFont systemFontOfSize:15]; + tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent; + tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote; } } +- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section +{ + NSAttributedString *attributedFooterTitle = [_tableViewSections sectionAtIndex:section].attributedFooterTitle; + + if (!attributedFooterTitle) + { + return nil; + } + + SectionFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionFooterView.defaultReuseIdentifier]; + [view updateWithTheme:ThemeService.shared.theme]; + view.leadingInset = tableView.vc_separatorInset.left; + [view updateWithAttributedText:attributedFooterTitle]; + + if (section == SECTION_TAG_USER_SETTINGS) + { + UIGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollToDiscoverySection)]; + [view addGestureRecognizer:recognizer]; + } + else if (section == SECTION_TAG_DISCOVERY && self.settingsDiscoveryTableViewSection.footerShouldScrollToUserSettings) + { + UIGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollToUserSettingsSection)]; + [view addGestureRecognizer:recognizer]; + } + + return view; +} + - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath]; @@ -2575,16 +2507,6 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)ce } } -- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section -{ - return 24; -} - -- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section -{ - return 24; -} - - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath]; @@ -2641,32 +2563,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self showThemePicker]; } } - else if (section == SECTION_TAG_USER_SETTINGS && row == USER_SETTINGS_THREEPIDS_INFORMATION_INDEX) - { - // settingsDiscoveryTableViewSection is a dynamic section, so check number of rows before scroll to avoid crashes - if (self.settingsDiscoveryTableViewSection.numberOfRows > 0) - { - NSIndexPath *discoveryIndexPath = [_tableViewSections exactIndexPathForRowTag:0 sectionTag:SECTION_TAG_DISCOVERY]; - if (discoveryIndexPath) - { - [tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; - } - } - else - { - // this won't be precise in scroll location, but seems the best option for now - NSIndexPath *discoveryIndexPath = [_tableViewSections nearestIndexPathForRowTag:0 sectionTag:SECTION_TAG_DISCOVERY]; - if (discoveryIndexPath) - { - [tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; - } - } - } - else if (section == SECTION_TAG_USER_SETTINGS && row == USER_SETTINGS_INVITE_FRIENDS_INDEX) - { - UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath]; - [self showInviteFriendsFromSourceView:selectedCell]; - } else if (section == SECTION_TAG_NOTIFICATIONS && row == NOTIFICATION_SETTINGS_SYSTEM_SETTINGS) { [self openSystemSettingsApp]; @@ -2745,9 +2641,9 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self presentViewController:currentAlert animated:YES completion:nil]; } } - else if (section == SECTION_TAG_OTHER) + else if (section == SECTION_TAG_ABOUT) { - if (row == OTHER_COPYRIGHT_INDEX) + if (row == ABOUT_COPYRIGHT_INDEX) { WebViewViewController *webViewViewController = [[WebViewViewController alloc] initWithURL:BuildSettings.applicationCopyrightUrlString]; @@ -2755,7 +2651,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self pushViewController:webViewViewController]; } - else if (row == OTHER_TERM_CONDITIONS_INDEX) + else if (row == ABOUT_TERM_CONDITIONS_INDEX) { WebViewViewController *webViewViewController = [[WebViewViewController alloc] initWithURL:BuildSettings.applicationTermsConditionsUrlString]; @@ -2763,7 +2659,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self pushViewController:webViewViewController]; } - else if (row == OTHER_PRIVACY_INDEX) + else if (row == ABOUT_PRIVACY_INDEX) { WebViewViewController *webViewViewController = [[WebViewViewController alloc] initWithURL:BuildSettings.applicationPrivacyPolicyUrlString]; @@ -2771,7 +2667,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self pushViewController:webViewViewController]; } - else if (row == OTHER_THIRD_PARTY_INDEX) + else if (row == ABOUT_THIRD_PARTY_INDEX) { NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"third_party_licenses" ofType:@"html" inDirectory:nil]; @@ -3129,37 +3025,7 @@ - (void)toggleLocalContactsSync:(UISwitch *)sender } else { - MXWeakify(self); - - // The preparation can take some time so indicate this to the user - [self startActivityIndicator]; - - [session prepareIdentityServiceForTermsWithDefault:RiotSettings.shared.identityServerUrlString - success:^(MXSession *session, NSString *baseURL, NSString *accessToken) { - MXStrongifyAndReturnIfNil(self); - - [self stopActivityIndicator]; - - // Present the terms of the identity server. - [self presentIdentityServerTermsWithSession:session baseURL:baseURL andAccessToken:accessToken]; - } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - - [self stopActivityIndicator]; - - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:VectorL10n.findYourContactsIdentityServiceError - message:nil - preferredStyle:UIAlertControllerStyleAlert]; - - [alertController addAction:[UIAlertAction actionWithTitle:MatrixKitL10n.ok - style:UIAlertActionStyleDefault - handler:nil]]; - - [self presentViewController:alertController animated:YES completion:nil]; - - [MXKAppSettings standardAppSettings].syncLocalContacts = NO; - [self updateSections]; - }]; + [self prepareIdentityServiceAndPresentTermsWithSession:session checkingAccessForContactsOnAccept:YES]; } } else @@ -3886,21 +3752,6 @@ - (void)deactivateAccountAction self.deactivateAccountViewController = deactivateAccountViewController; } -- (void)showInviteFriendsFromSourceView:(UIView*)sourceView -{ - if (!self.inviteFriendsPresenter) - { - self.inviteFriendsPresenter = [InviteFriendsPresenter new]; - } - - NSString *userId = self.mainSession.myUser.userId; - - [self.inviteFriendsPresenter presentFor:userId - from:self - sourceView:sourceView - animated:YES]; -} - - (void)toggleNSFWPublicRoomsFiltering:(UISwitch *)sender { RiotSettings.shared.showNSFWPublicRooms = sender.isOn; @@ -4499,13 +4350,12 @@ - (void)settingsDiscoveryViewModel:(SettingsDiscoveryViewModel *)viewModel didSe self.discoveryThreePidDetailsPresenter = discoveryThreePidDetailsPresenter; } -- (void)settingsDiscoveryViewModelDidTapUserSettingsLink:(SettingsDiscoveryViewModel *)viewModel +- (void)settingsDiscoveryViewModelDidTapAcceptIdentityServerTerms:(SettingsDiscoveryViewModel *)viewModel { - NSIndexPath *discoveryIndexPath = [_tableViewSections exactIndexPathForRowTag:USER_SETTINGS_ADD_EMAIL_INDEX - sectionTag:SECTION_TAG_USER_SETTINGS]; - if (discoveryIndexPath) + MXSession *session = self.mainSession; + if (!session.identityService.areAllTermsAgreed) { - [self.tableView scrollToRowAtIndexPath:discoveryIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; + [self prepareIdentityServiceAndPresentTermsWithSession:session checkingAccessForContactsOnAccept:NO]; } } @@ -4542,6 +4392,52 @@ - (void)showIdentityServerSettingsScreen identityServerSettingsCoordinatorBridgePresenter.delegate = self; } +- (void)prepareIdentityServiceAndPresentTermsWithSession:(MXSession *)session + checkingAccessForContactsOnAccept:(BOOL)checkAccessForContacts +{ + if (self.isPreparingIdentityService) + { + return; + } + + self.isPreparingIdentityService = YES; + self.serviceTermsModalShouldCheckAccessForContactsOnAccept = checkAccessForContacts; + + MXWeakify(self); + + // The preparation can take some time so indicate this to the user + [self startActivityIndicator]; + + [session prepareIdentityServiceForTermsWithDefault:RiotSettings.shared.identityServerUrlString + success:^(MXSession *session, NSString *baseURL, NSString *accessToken) { + MXStrongifyAndReturnIfNil(self); + + [self stopActivityIndicator]; + self.isPreparingIdentityService = NO; + + // Present the terms of the identity server. + [self presentIdentityServerTermsWithSession:session baseURL:baseURL andAccessToken:accessToken]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + + [self stopActivityIndicator]; + self.isPreparingIdentityService = NO; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:VectorL10n.findYourContactsIdentityServiceError + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + [alertController addAction:[UIAlertAction actionWithTitle:MatrixKitL10n.ok + style:UIAlertActionStyleDefault + handler:nil]]; + + [self presentViewController:alertController animated:YES completion:nil]; + + [MXKAppSettings standardAppSettings].syncLocalContacts = NO; + [self updateSections]; + }]; +} + - (void)presentIdentityServerTermsWithSession:(MXSession*)mxSession baseURL:(NSString*)baseURL andAccessToken:(NSString*)accessToken { if (!mxSession || !baseURL || !accessToken || self.serviceTermsModalCoordinatorBridgePresenter.isPresenting) @@ -4549,15 +4445,13 @@ - (void)presentIdentityServerTermsWithSession:(MXSession*)mxSession baseURL:(NSS return; } - ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter = [[ServiceTermsModalCoordinatorBridgePresenter alloc] initWithSession:mxSession - baseUrl:baseURL - serviceType:MXServiceTypeIdentityService - accessToken:accessToken]; - - serviceTermsModalCoordinatorBridgePresenter.delegate = self; + self.serviceTermsModalCoordinatorBridgePresenter = [[ServiceTermsModalCoordinatorBridgePresenter alloc] initWithSession:mxSession + baseUrl:baseURL + serviceType:MXServiceTypeIdentityService + accessToken:accessToken]; - [serviceTermsModalCoordinatorBridgePresenter presentFrom:self animated:YES]; - self.serviceTermsModalCoordinatorBridgePresenter = serviceTermsModalCoordinatorBridgePresenter; + self.serviceTermsModalCoordinatorBridgePresenter.delegate = self; + [self.serviceTermsModalCoordinatorBridgePresenter presentFrom:self animated:YES]; } #pragma mark SettingsIdentityServerCoordinatorBridgePresenterDelegate @@ -4573,15 +4467,20 @@ - (void)settingsIdentityServerCoordinatorBridgePresenterDelegateDidComplete:(Set - (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidAccept:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter { [coordinatorBridgePresenter dismissWithAnimated:YES completion:^{ - [self checkAccessForContacts]; + [self.settingsDiscoveryTableViewSection reload]; + if (self.serviceTermsModalShouldCheckAccessForContactsOnAccept) + { + [self checkAccessForContacts]; + } }]; self.serviceTermsModalCoordinatorBridgePresenter = nil; } - (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidDecline:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter session:(MXSession *)session { - // Disable the contacts toggle as the terms weren't accepted. + // Terms weren't accepted: disable contacts toggle and refresh discovery [self updateSections]; + [self.settingsDiscoveryTableViewSection reload]; [coordinatorBridgePresenter dismissWithAnimated:YES completion:nil]; self.serviceTermsModalCoordinatorBridgePresenter = nil; @@ -4589,7 +4488,10 @@ - (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidDecline:(ServiceTe - (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidClose:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter { - [self updateSections]; // Disables the contacts toggle as the terms weren't accepted. + // Terms weren't accepted: disable contacts toggle and refresh discovery + [self updateSections]; + [self.settingsDiscoveryTableViewSection reload]; + self.serviceTermsModalCoordinatorBridgePresenter = nil; } diff --git a/Riot/Modules/Spaces/BetaAnnounceCell.swift b/Riot/Modules/Spaces/BetaAnnounceCell.swift index 9897c9417f..08485e91ae 100644 --- a/Riot/Modules/Spaces/BetaAnnounceCell.swift +++ b/Riot/Modules/Spaces/BetaAnnounceCell.swift @@ -82,7 +82,7 @@ final class BetaAnnounceCell: UITableViewCell, Themable { } } -// Copy past from NibReusable in order to expose these methods to ObjC +// Copy paste from NibReusable in order to expose these methods to ObjC extension BetaAnnounceCell { @objc static var reuseIdentifier: String { return String(describing: self) diff --git a/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift b/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift index 190a397f65..9518e0b518 100644 --- a/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift +++ b/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift @@ -28,7 +28,7 @@ struct FormSectionFooter: View { .padding(.top) .padding(.leading) .padding(.trailing) - .font(theme.fonts.callout) + .font(theme.fonts.subheadline) } } diff --git a/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift b/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift index 54bd4def25..a82afd1de8 100644 --- a/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift +++ b/RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift @@ -28,7 +28,7 @@ struct FormSectionHeader: View { .padding(.top, 32) .padding(.leading) .padding(.bottom, 8) - .font(theme.fonts.subheadline) + .font(theme.fonts.footnote) .textCase(.uppercase) .frame(maxWidth: .infinity, alignment: .leading) } diff --git a/changelog.d/pr-5011.change b/changelog.d/pr-5011.change new file mode 100644 index 0000000000..3dfc602c1c --- /dev/null +++ b/changelog.d/pr-5011.change @@ -0,0 +1 @@ +Settings: Refresh the appearance of headers and footers, with a few minor tweaks to the organisation. \ No newline at end of file