Update fonts, add attributed strings and add tap gestures back.

Footers use subheadline. Headers use footnote.
This commit is contained in:
Doug
2021-10-15 14:37:55 +01:00
parent d46642bd84
commit 7bbe49febf
12 changed files with 152 additions and 103 deletions

View File

@@ -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

View File

@@ -22,7 +22,21 @@ final class Section: NSObject {
let tag: Int
var rows: [Row]
var headerTitle: String?
var footerTitle: String?
var attributedFooterTitle: NSAttributedString?
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

View File

@@ -0,0 +1,41 @@
//
// 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
/// A subclass of `UITableViewHeaderFooterView` that conforms `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, Themable {
static var defaultReuseIdentifier: String {
String(describing: Self.self)
}
override func prepareForReuse() {
super.prepareForReuse()
for recognizer in gestureRecognizers ?? [] {
removeGestureRecognizer(recognizer)
}
}
func update(theme: Theme) {
textLabel?.textColor = theme.colors.secondaryContent
textLabel?.font = theme.fonts.subheadline
textLabel?.numberOfLines = 0
}
}

View File

@@ -24,7 +24,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 +40,12 @@ private enum DiscoverySectionRows {
@objc weak var delegate: SettingsDiscoveryTableViewSectionDelegate?
@objc var attributedFooterTitle: NSAttributedString?
@objc var footerShouldScrollToUserSettings: Bool {
attributedFooterTitle != nil
}
// MARK: Private
private var theme: Theme!
@@ -96,13 +101,6 @@ private enum DiscoverySectionRows {
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 +143,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 +172,7 @@ private enum DiscoverySectionRows {
private func updateRows() {
attributedFooterTitle = nil;
let discoveryRows: [DiscoverySectionRows]
switch self.viewState {
@@ -202,9 +192,8 @@ private enum DiscoverySectionRows {
})
]
case .noThreePidsAdded:
discoveryRows = [
.attributedInfo(attributedText: self.threePidsManagementInfoAttributedString())
]
discoveryRows = []
attributedFooterTitle = self.threePidsManagementInfoAttributedString()
case .threePidsAdded(let emails, let phoneNumbers):
let emailThreePids = emails.map { (email) -> DiscoverySectionRows in
@@ -218,7 +207,7 @@ private enum DiscoverySectionRows {
var threePidsRows: [DiscoverySectionRows] = []
threePidsRows.append(contentsOf: emailThreePids)
threePidsRows.append(contentsOf: phoneNumbersThreePids)
threePidsRows.append(.attributedInfo(attributedText: self.threePidsManagementInfoAttributedString()))
attributedFooterTitle = self.threePidsManagementInfoAttributedString()
discoveryRows = threePidsRows
}
@@ -236,11 +225,11 @@ private enum DiscoverySectionRows {
private func threePidsManagementInfoAttributedString() -> NSAttributedString {
let attributedInfoString = NSMutableAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart1,
attributes: [.foregroundColor: self.theme.textPrimaryColor, .font: Constants.defaultFont])
attributes: [:])
attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart2,
attributes: [.foregroundColor: self.theme.tintColor, .font: Constants.defaultFont]))
attributes: [.foregroundColor: self.theme.tintColor]))
attributedInfoString.append(NSAttributedString(string: VectorL10n.settingsDiscoveryThreePidsManagementInformationPart3,
attributes: [.foregroundColor: self.theme.tintColor, .font: Constants.defaultFont]))
attributes: [:]))
return attributedInfoString
}
}

View File

@@ -21,5 +21,4 @@ enum SettingsDiscoveryViewAction {
case load
case acceptTerms
case select(threePid: MX3PID)
case tapUserSettingsLink
}

View File

@@ -59,8 +59,6 @@ import Foundation
self.acceptTerms()
case .select(threePid: let threePid):
self.coordinatorDelegate?.settingsDiscoveryViewModel(self, didSelectThreePidWith: threePid.medium.identifier, and: threePid.address)
case .tapUserSettingsLink:
self.coordinatorDelegate?.settingsDiscoveryViewModelDidTapUserSettingsLink(self)
}
}

View File

@@ -22,7 +22,6 @@ protocol SettingsDiscoveryViewModelViewDelegate: AnyObject {
@objc protocol SettingsDiscoveryViewModelCoordinatorDelegate: AnyObject {
func settingsDiscoveryViewModel(_ viewModel: SettingsDiscoveryViewModel, didSelectThreePidWith medium: String, and address: String)
func settingsDiscoveryViewModelDidTapUserSettingsLink(_ viewModel: SettingsDiscoveryViewModel)
}
protocol SettingsDiscoveryViewModelType {

View File

@@ -504,6 +504,7 @@ enum {
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote;
}
}

View File

@@ -159,10 +159,13 @@ TableViewSectionsDelegate>
[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 registerClass:SectionFooterView.class 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)
{
@@ -1295,26 +1298,26 @@ TableViewSectionsDelegate>
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
Section *tableSection = [self.tableViewSections sectionAtIndex:section];
return tableSection.footerTitle;
}
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section
{
if ([view isKindOfClass:UITableViewHeaderFooterView.class])
NSString *footerTitle = [_tableViewSections sectionAtIndex:section].footerTitle;
if (!footerTitle)
{
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
return nil;
}
SectionFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionFooterView.defaultReuseIdentifier];
[view updateWithTheme:ThemeService.shared.theme];
view.textLabel.text = footerTitle;
return view;
}
#pragma mark - UITableView delegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

View File

@@ -78,7 +78,6 @@ enum
USER_SETTINGS_SURNAME_INDEX,
USER_SETTINGS_ADD_EMAIL_INDEX,
USER_SETTINGS_ADD_PHONENUMBER_INDEX,
USER_SETTINGS_THREEPIDS_INFORMATION_INDEX,
USER_SETTINGS_INVITE_FRIENDS_INDEX
};
@@ -356,11 +355,10 @@ TableViewSectionsDelegate>
}
if (BuildSettings.settingsScreenShowThreepidExplanatory)
{
#warning implement attributed string footers
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart1] attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.textPrimaryColor}];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart1] attributes:@{}];
[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}]];
sectionUserSettings.footerTitle = attributedString.string;
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[VectorL10n settingsThreePidsManagementInformationPart3] attributes:@{}]];
sectionUserSettings.attributedFooterTitle = attributedString;
}
if (RiotSettings.shared.settingsScreenShowInviteFriends)
{
@@ -440,6 +438,7 @@ TableViewSectionsDelegate>
[sectionDiscovery addRowWithTag:index];
}
sectionDiscovery.headerTitle = [VectorL10n settingsDiscoverySettings];
sectionDiscovery.attributedFooterTitle = self.settingsDiscoveryTableViewSection.attributedFooterTitle;
[tmpSections addObject:sectionDiscovery];
}
@@ -597,10 +596,13 @@ TableViewSectionsDelegate>
[self.tableView registerClass:TableViewCellWithPhoneNumberTextField.class forCellReuseIdentifier:[TableViewCellWithPhoneNumberTextField defaultReuseIdentifier]];
[self.tableView registerClass:GroupTableViewCellWithSwitch.class forCellReuseIdentifier:[GroupTableViewCellWithSwitch defaultReuseIdentifier]];
[self.tableView registerNib:MXKTableViewCellWithTextView.nib forCellReuseIdentifier:[MXKTableViewCellWithTextView defaultReuseIdentifier]];
[self.tableView registerClass:SectionFooterView.class 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;
// Add observer to handle removed accounts
removedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
@@ -1354,6 +1356,38 @@ TableViewSectionsDelegate>
return userInteractiveAuthenticationService;
}
- (void)scrollToDiscoverySection
{
// 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)
{
[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
@@ -2428,23 +2462,35 @@ TableViewSectionsDelegate>
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
tableViewHeaderFooterView.textLabel.font = ThemeService.shared.theme.fonts.footnote;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
Section *sectionObj = [_tableViewSections sectionAtIndex:section];
return sectionObj.footerTitle;
}
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section
{
if ([view isKindOfClass:UITableViewHeaderFooterView.class])
NSAttributedString *attributedFooterTitle = [_tableViewSections sectionAtIndex:section].attributedFooterTitle;
if (!attributedFooterTitle)
{
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.colors.secondaryContent;
return nil;
}
SectionFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionFooterView.defaultReuseIdentifier];
[view updateWithTheme:ThemeService.shared.theme];
view.textLabel.attributedText = 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
@@ -2493,16 +2539,6 @@ TableViewSectionsDelegate>
}
}
//- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
//{
// return 24;
//}
//
//- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
//{
// return [_tableViewSections sectionAtIndex:section].footerTitle ? UITableViewAutomaticDimension : 24;
//}
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
@@ -2559,27 +2595,6 @@ TableViewSectionsDelegate>
[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];
@@ -4417,16 +4432,6 @@ TableViewSectionsDelegate>
self.discoveryThreePidDetailsPresenter = discoveryThreePidDetailsPresenter;
}
- (void)settingsDiscoveryViewModelDidTapUserSettingsLink:(SettingsDiscoveryViewModel *)viewModel
{
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 - Local Contacts Sync
- (void)checkAccessForContacts

View File

@@ -28,7 +28,7 @@ struct FormSectionFooter: View {
.padding(.top)
.padding(.leading)
.padding(.trailing)
.font(theme.fonts.callout)
.font(theme.fonts.subheadline)
}
}

View File

@@ -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)
}