Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table view headers and footers in Settings. #5011

Merged
merged 8 commits into from
Oct 21, 2021
2 changes: 1 addition & 1 deletion DesignKit/Source/FontsUIkit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions Riot/Assets/en.lproj/Vector.strings
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -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" = ".";
Expand Down
12 changes: 8 additions & 4 deletions Riot/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down
3 changes: 0 additions & 3 deletions Riot/Managers/Settings/RiotSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
30 changes: 29 additions & 1 deletion Riot/Modules/Common/Models/Section.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,35 @@ final class Section: NSObject {

let tag: Int
var rows: [Row]
var headerTitle: String?
var attributedHeaderTitle: NSAttributedString?
var attributedFooterTitle: NSAttributedString?
pixlwave marked this conversation as resolved.
Show resolved Hide resolved

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
Expand Down
76 changes: 76 additions & 0 deletions Riot/Modules/Common/SectionFooters/SectionFooterView.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
40 changes: 40 additions & 0 deletions Riot/Modules/Common/SectionFooters/SectionFooterView.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="SectionFooterView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="210"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tZ9-SU-Yp2">
<rect key="frame" x="20" y="50" width="374" height="148"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="tZ9-SU-Yp2" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="6" id="6jE-ua-fKl"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="tZ9-SU-Yp2" secondAttribute="trailing" constant="20" id="OMT-ZP-qap"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="tZ9-SU-Yp2" secondAttribute="bottom" constant="12" id="Yrv-I1-gG1"/>
<constraint firstItem="tZ9-SU-Yp2" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="k4h-Zl-arh"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="footerLabel" destination="tZ9-SU-Yp2" id="V24-Xh-sz0"/>
<outlet property="footerLabelLeadingConstraint" destination="k4h-Zl-arh" id="TjX-h5-vJJ"/>
</connections>
<point key="canvasLocation" x="131.8840579710145" y="-170.08928571428569"/>
</view>
</objects>
</document>
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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!
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -183,6 +161,10 @@ private enum DiscoverySectionRows {

private func updateRows() {

// reset the footer
attributedFooterTitle = nil
footerShouldScrollToUserSettings = false

let discoveryRows: [DiscoverySectionRows]

switch self.viewState {
Expand All @@ -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
Expand All @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ enum SettingsDiscoveryViewAction {
case load
case acceptTerms
case select(threePid: MX3PID)
case tapUserSettingsLink
}
Loading