From 5a1886be8fb69a3c96af7319e85265976a6538f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Hu=CC=88hne?= Date: Fri, 8 Jan 2021 16:09:10 +0100 Subject: [PATCH 1/2] #861 better support for right to left text support. Adapting views, which were not designed for right to left text support. --- .../Server List/ServerListBookmarkCell.swift | 12 +++++----- .../User Interface/ClientItemCell.swift | 22 +++++++++---------- .../Client/User Interface/SortBar.swift | 10 ++++----- .../User Interface/More/MoreViewHeader.swift | 22 +++++++++---------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ownCloud/Server List/ServerListBookmarkCell.swift b/ownCloud/Server List/ServerListBookmarkCell.swift index c834489b7..8bd7271e9 100644 --- a/ownCloud/Server List/ServerListBookmarkCell.swift +++ b/ownCloud/Server List/ServerListBookmarkCell.swift @@ -67,20 +67,20 @@ class ServerListBookmarkCell : ThemeTableViewCell { iconView.widthAnchor.constraint(equalToConstant: 40), iconView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - iconView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), - iconView.rightAnchor.constraint(equalTo: titleLabel.leftAnchor, constant: -25), - iconView.rightAnchor.constraint(equalTo: detailLabel.leftAnchor, constant: -25), + iconView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20), + iconView.trailingAnchor.constraint(equalTo: titleLabel.leadingAnchor, constant: -25), + iconView.trailingAnchor.constraint(equalTo: detailLabel.leadingAnchor, constant: -25), - titleLabel.rightAnchor.constraint(equalTo: infoView.leftAnchor), + titleLabel.trailingAnchor.constraint(equalTo: infoView.leadingAnchor), titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20), titleLabel.bottomAnchor.constraint(equalTo: detailLabel.topAnchor, constant: -5), - detailLabel.rightAnchor.constraint(equalTo: infoView.leftAnchor), + detailLabel.trailingAnchor.constraint(equalTo: infoView.leadingAnchor), detailLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20), infoView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20), infoView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20), - infoView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20) + infoView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20) ]) infoView.setContentHuggingPriority(.required, for: .horizontal) diff --git a/ownCloudAppShared/Client/User Interface/ClientItemCell.swift b/ownCloudAppShared/Client/User Interface/ClientItemCell.swift index dfea6f9c0..346090205 100644 --- a/ownCloudAppShared/Client/User Interface/ClientItemCell.swift +++ b/ownCloudAppShared/Client/User Interface/ClientItemCell.swift @@ -208,25 +208,25 @@ open class ClientItemCell: ThemeTableViewCell, ItemContainer { sharedStatusIconViewZeroWidthConstraint = sharedStatusIconView.widthAnchor.constraint(equalToConstant: 0) publicLinkStatusIconViewZeroWidthConstraint = publicLinkStatusIconView.widthAnchor.constraint(equalToConstant: 0) - cloudStatusIconViewRightMarginConstraint = sharedStatusIconView.leftAnchor.constraint(equalTo: cloudStatusIconView.rightAnchor) - sharedStatusIconViewRightMarginConstraint = publicLinkStatusIconView.leftAnchor.constraint(equalTo: sharedStatusIconView.rightAnchor) - publicLinkStatusIconViewRightMarginConstraint = detailLabel.leftAnchor.constraint(equalTo: publicLinkStatusIconView.rightAnchor) + cloudStatusIconViewRightMarginConstraint = sharedStatusIconView.leadingAnchor.constraint(equalTo: cloudStatusIconView.trailingAnchor) + sharedStatusIconViewRightMarginConstraint = publicLinkStatusIconView.leadingAnchor.constraint(equalTo: sharedStatusIconView.trailingAnchor) + publicLinkStatusIconViewRightMarginConstraint = detailLabel.leadingAnchor.constraint(equalTo: publicLinkStatusIconView.trailingAnchor) NSLayoutConstraint.activate([ - iconView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: horizontalMargin), - iconView.rightAnchor.constraint(equalTo: titleLabel.leftAnchor, constant: -spacing), + iconView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: horizontalMargin), + iconView.trailingAnchor.constraint(equalTo: titleLabel.leadingAnchor, constant: -spacing), iconView.widthAnchor.constraint(equalToConstant: iconViewWidth), iconView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: verticalIconMargin), iconView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -verticalIconMargin), - titleLabel.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: 0), - detailLabel.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: 0), + titleLabel.trailingAnchor.constraint(equalTo: moreButton.leadingAnchor, constant: 0), + detailLabel.trailingAnchor.constraint(equalTo: moreButton.leadingAnchor, constant: 0), cloudStatusIconViewZeroWidthConstraint!, sharedStatusIconViewZeroWidthConstraint!, publicLinkStatusIconViewZeroWidthConstraint!, - cloudStatusIconView.leftAnchor.constraint(equalTo: iconView.rightAnchor, constant: spacing), + cloudStatusIconView.leadingAnchor.constraint(equalTo: iconView.trailingAnchor, constant: spacing), cloudStatusIconViewRightMarginConstraint!, sharedStatusIconViewRightMarginConstraint!, publicLinkStatusIconViewRightMarginConstraint!, @@ -248,10 +248,10 @@ open class ClientItemCell: ThemeTableViewCell, ItemContainer { moreButton.topAnchor.constraint(equalTo: self.contentView.topAnchor), moreButton.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor), moreButtonWidthConstraint!, - moreButton.rightAnchor.constraint(equalTo: self.contentView.rightAnchor), + moreButton.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor), - messageButton.leftAnchor.constraint(equalTo: moreButton.leftAnchor), - messageButton.rightAnchor.constraint(equalTo: moreButton.rightAnchor), + messageButton.leadingAnchor.constraint(equalTo: moreButton.leadingAnchor), + messageButton.trailingAnchor.constraint(equalTo: moreButton.trailingAnchor), messageButton.topAnchor.constraint(equalTo: moreButton.topAnchor), messageButton.bottomAnchor.constraint(equalTo: moreButton.bottomAnchor) ]) diff --git a/ownCloudAppShared/Client/User Interface/SortBar.swift b/ownCloudAppShared/Client/User Interface/SortBar.swift index 32fb85260..6dd3b7224 100644 --- a/ownCloudAppShared/Client/User Interface/SortBar.swift +++ b/ownCloudAppShared/Client/User Interface/SortBar.swift @@ -135,8 +135,8 @@ public class SortBar: UIView, Themeable, UIPopoverPresentationControllerDelegate sortSegmentedControl.topAnchor.constraint(equalTo: self.topAnchor, constant: topPadding), sortSegmentedControl.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -bottomPadding), sortSegmentedControl.centerXAnchor.constraint(equalTo: self.centerXAnchor), - sortSegmentedControl.leftAnchor.constraint(greaterThanOrEqualTo: self.leftAnchor, constant: leftPadding), - sortSegmentedControl.rightAnchor.constraint(lessThanOrEqualTo: self.rightAnchor, constant: -rightPadding) + sortSegmentedControl.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: leftPadding), + sortSegmentedControl.trailingAnchor.constraint(lessThanOrEqualTo: self.trailingAnchor, constant: -rightPadding) ]) var longestTitleWidth : CGFloat = 0.0 @@ -172,8 +172,8 @@ public class SortBar: UIView, Themeable, UIPopoverPresentationControllerDelegate NSLayoutConstraint.activate([ sortButton.topAnchor.constraint(equalTo: self.topAnchor, constant: topPadding), sortButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -bottomPadding), - sortButton.leftAnchor.constraint(equalTo: self.leftAnchor, constant: leftPadding), - sortButton.rightAnchor.constraint(lessThanOrEqualTo: self.rightAnchor, constant: -rightPadding) + sortButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: leftPadding), + sortButton.trailingAnchor.constraint(lessThanOrEqualTo: self.trailingAnchor, constant: -rightPadding) ]) sortButton.isHidden = true @@ -191,7 +191,7 @@ public class SortBar: UIView, Themeable, UIPopoverPresentationControllerDelegate NSLayoutConstraint.activate([ selectButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), - selectButton.rightAnchor.constraint(lessThanOrEqualTo: self.safeAreaLayoutGuide.rightAnchor, constant: -rightPadding), + selectButton.trailingAnchor.constraint(lessThanOrEqualTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -rightPadding), selectButton.heightAnchor.constraint(equalToConstant: sideButtonsSize.height), selectButton.widthAnchor.constraint(equalToConstant: sideButtonsSize.width) ]) diff --git a/ownCloudAppShared/User Interface/More/MoreViewHeader.swift b/ownCloudAppShared/User Interface/More/MoreViewHeader.swift index c7974ee31..620506617 100644 --- a/ownCloudAppShared/User Interface/More/MoreViewHeader.swift +++ b/ownCloudAppShared/User Interface/More/MoreViewHeader.swift @@ -109,12 +109,12 @@ open class MoreViewHeader: UIView { labelContainerView.setContentCompressionResistancePriority(.required, for: .vertical) NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: labelContainerView.leftAnchor), - titleLabel.rightAnchor.constraint(equalTo: labelContainerView.rightAnchor), + titleLabel.leadingAnchor.constraint(equalTo: labelContainerView.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: labelContainerView.trailingAnchor), titleLabel.topAnchor.constraint(equalTo: labelContainerView.topAnchor), - detailLabel.leftAnchor.constraint(equalTo: labelContainerView.leftAnchor), - detailLabel.rightAnchor.constraint(equalTo: labelContainerView.rightAnchor), + detailLabel.leadingAnchor.constraint(equalTo: labelContainerView.leadingAnchor), + detailLabel.trailingAnchor.constraint(equalTo: labelContainerView.trailingAnchor), detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5), detailLabel.bottomAnchor.constraint(equalTo: labelContainerView.bottomAnchor) ]) @@ -126,11 +126,11 @@ open class MoreViewHeader: UIView { iconView.widthAnchor.constraint(equalToConstant: thumbnailSize.width), iconView.heightAnchor.constraint(equalToConstant: thumbnailSize.height), - iconView.leftAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leftAnchor, constant: 20), + iconView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 20), iconView.topAnchor.constraint(equalTo: self.topAnchor, constant: 20), iconView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -20).with(priority: .defaultHigh), - labelContainerView.leftAnchor.constraint(equalTo: iconView.rightAnchor, constant: 15), + labelContainerView.leadingAnchor.constraint(equalTo: iconView.trailingAnchor, constant: 15), labelContainerView.centerYAnchor.constraint(equalTo: self.centerYAnchor), labelContainerView.topAnchor.constraint(greaterThanOrEqualTo: self.topAnchor, constant: 20), labelContainerView.bottomAnchor.constraint(lessThanOrEqualTo: self.bottomAnchor, constant: -20).with(priority: .defaultHigh) @@ -147,21 +147,21 @@ open class MoreViewHeader: UIView { NSLayoutConstraint.activate([ favoriteButton.widthAnchor.constraint(equalToConstant: favoriteSize.width), favoriteButton.heightAnchor.constraint(equalToConstant: favoriteSize.height), - favoriteButton.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: -15), + favoriteButton.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -15), favoriteButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), - favoriteButton.leftAnchor.constraint(equalTo: labelContainerView.rightAnchor, constant: 10) + favoriteButton.leadingAnchor.constraint(equalTo: labelContainerView.trailingAnchor, constant: 10) ]) } else if showActivityIndicator { self.addSubview(activityIndicator) NSLayoutConstraint.activate([ activityIndicator.centerYAnchor.constraint(equalTo: self.centerYAnchor), - activityIndicator.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: -15), - activityIndicator.leftAnchor.constraint(equalTo: labelContainerView.rightAnchor, constant: 10) + activityIndicator.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -15), + activityIndicator.leadingAnchor.constraint(equalTo: labelContainerView.trailingAnchor, constant: 10) ]) } else { NSLayoutConstraint.activate([ - labelContainerView.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: -20) + labelContainerView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -20) ]) } From 745ee8877decfaa516f6720d9aa5d53c9b9454dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Hu=CC=88hne?= Date: Tue, 12 Jan 2021 10:11:59 +0100 Subject: [PATCH 2/2] - workaround for table view cells for style .default to support Right-to-Left UI support - changed some missing views to support RTL support - moved icons in the 'More Action View' from the left to the right side, which is equal to the UIMenu UI element - adapted push transition animation for RTL --- .../Client/Actions/Action+UserInterface.swift | 8 +++---- ownCloudAppShared/Client/Actions/Action.swift | 2 +- .../User Interface/More/MoreViewHeader.swift | 2 +- .../PushTransition.swift | 23 +++++++++++++++---- .../Theme/UI/ThemeTableViewCell.swift | 8 ++++++- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/ownCloud/Client/Actions/Action+UserInterface.swift b/ownCloud/Client/Actions/Action+UserInterface.swift index 03986b644..1e10bbe29 100644 --- a/ownCloud/Client/Actions/Action+UserInterface.swift +++ b/ownCloud/Client/Actions/Action+UserInterface.swift @@ -177,7 +177,7 @@ private extension Action { self.dismiss(presentingController: presentingController, andPresent: sharingViewController, on: context.viewController) } - }, title: userTitle, style: .plain, image: UIImage(named: "group"), imageWidth: Action.staticRowImageWidth, alignment: .left, accessoryType: .disclosureIndicator) + }, title: userTitle, style: .plain, image: nil, imageWidth: nil, alignment: .left, accessoryType: .disclosureIndicator) shareRows.append(addGroupRow) } else if item.isShareable { shareRows.append(self.shareAsGroupRow(item: item, presentingController: presentingController, context: context)) @@ -191,7 +191,7 @@ private extension Action { self.dismiss(presentingController: presentingController, andPresent: sharingViewController, on: context.viewController) } - }, title: linkTitle, style: .plain, image: UIImage(named: "link"), imageWidth: Action.staticRowImageWidth, alignment: .left, accessoryType: .disclosureIndicator) + }, title: linkTitle, style: .plain, image: nil, imageWidth: nil, alignment: .left, accessoryType: .disclosureIndicator) shareRows.append(addGroupRow) } else if let publicLinkRow = self.shareAsPublicLinkRow(item: item, presentingController: presentingController, context: context) { shareRows.append(publicLinkRow) @@ -218,7 +218,7 @@ private extension Action { andPresent: GroupSharingTableViewController(core: core, item: item), on: context.viewController) } - }, title: title, style: .plain, image: UIImage(named: "group"), imageWidth: Action.staticRowImageWidth, alignment: .left, identifier: "share-add-group") + }, title: title, style: .plain, image: nil, imageWidth:nil, imageTintColorKey: nil, alignment: .left, identifier: "share-add-group", accessoryView: UIImageView(image: UIImage(named: "group"))) return addGroupRow } @@ -230,7 +230,7 @@ private extension Action { andPresent: PublicLinkTableViewController(core: core, item: item), on: context.viewController) } - }, title: "Links".localized, style: .plain, image: UIImage(named: "link"), imageWidth: Action.staticRowImageWidth, alignment: .left, identifier: "share-add-group") + }, title: "Links".localized, style: .plain, image: nil, imageWidth: nil, alignment: .left, identifier: "share-add-group", accessoryView: UIImageView(image: UIImage(named: "link"))) return addGroupRow } diff --git a/ownCloudAppShared/Client/Actions/Action.swift b/ownCloudAppShared/Client/Actions/Action.swift index c78fc04e3..1e679c5ac 100644 --- a/ownCloudAppShared/Client/Actions/Action.swift +++ b/ownCloudAppShared/Client/Actions/Action.swift @@ -415,7 +415,7 @@ open class Action : NSObject { return StaticTableViewRow(buttonWithAction: { (_ row, _ sender) in self.perform() - }, title: name, style: actionExtension.category == .destructive ? .destructive : .plain, image: self.icon, imageWidth: Action.staticRowImageWidth, alignment: .left, identifier: actionExtension.identifier.rawValue) + }, title: name, style: actionExtension.category == .destructive ? .destructive : .plain, image: nil, imageWidth: nil, alignment: .left, identifier: actionExtension.identifier.rawValue, accessoryView: UIImageView(image: self.icon)) } open func provideContextualAction() -> UIContextualAction? { diff --git a/ownCloudAppShared/User Interface/More/MoreViewHeader.swift b/ownCloudAppShared/User Interface/More/MoreViewHeader.swift index 620506617..27994c82c 100644 --- a/ownCloudAppShared/User Interface/More/MoreViewHeader.swift +++ b/ownCloudAppShared/User Interface/More/MoreViewHeader.swift @@ -147,7 +147,7 @@ open class MoreViewHeader: UIView { NSLayoutConstraint.activate([ favoriteButton.widthAnchor.constraint(equalToConstant: favoriteSize.width), favoriteButton.heightAnchor.constraint(equalToConstant: favoriteSize.height), - favoriteButton.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -15), + favoriteButton.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: -10), favoriteButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), favoriteButton.leadingAnchor.constraint(equalTo: labelContainerView.trailingAnchor, constant: 10) ]) diff --git a/ownCloudAppShared/User Interface/Push Presentation Controller/PushTransition.swift b/ownCloudAppShared/User Interface/Push Presentation Controller/PushTransition.swift index 5ace84843..972464c76 100644 --- a/ownCloudAppShared/User Interface/Push Presentation Controller/PushTransition.swift +++ b/ownCloudAppShared/User Interface/Push Presentation Controller/PushTransition.swift @@ -38,16 +38,24 @@ public class PushTransition: NSObject, UIViewControllerAnimatedTransitioning { let toViewController = transitionContext.viewController(forKey: .to) { if dismissTransition { + var toViewControllerTranslationXMultiplier : CGFloat = -0.5 + var fromViewControllerTranslationXMultiplier : CGFloat = 1 + if fromViewController.view.effectiveUserInterfaceLayoutDirection == .rightToLeft { + toViewControllerTranslationXMultiplier = 1 + fromViewControllerTranslationXMultiplier = -0.5 + } + fromViewController.view.frame = transitionContext.initialFrame(for: fromViewController) toViewController.view.frame = transitionContext.finalFrame(for: toViewController) transitionContext.containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view) fromViewController.view.transform = .identity - toViewController.view.transform = CGAffineTransform(translationX: -0.5 * toViewController.view.frame.size.width, y: 0) + + toViewController.view.transform = CGAffineTransform(translationX: toViewControllerTranslationXMultiplier * toViewController.view.frame.size.width, y: 0) UIView.animate(withDuration: self.transitionDuration(using: transitionContext), delay: 0, options: [ .curveEaseInOut ], animations: { - fromViewController.view.transform = CGAffineTransform(translationX: fromViewController.view.frame.size.width, y: 0) + fromViewController.view.transform = CGAffineTransform(translationX: fromViewControllerTranslationXMultiplier * fromViewController.view.frame.size.width, y: 0) toViewController.view.transform = .identity }, completion: { _ in let window = fromViewController.view.window @@ -67,15 +75,22 @@ public class PushTransition: NSObject, UIViewControllerAnimatedTransitioning { } }) } else { + var toViewControllerTranslationXMultiplier : CGFloat = 1 + var fromViewControllerTranslationXMultiplier : CGFloat = -0.5 + if fromViewController.view.effectiveUserInterfaceLayoutDirection == .rightToLeft { + toViewControllerTranslationXMultiplier = -0.5 + fromViewControllerTranslationXMultiplier = 1 + } + fromViewController.view.frame = transitionContext.finalFrame(for: fromViewController) toViewController.view.frame = transitionContext.finalFrame(for: toViewController) transitionContext.containerView.insertSubview(toViewController.view, aboveSubview: fromViewController.view) - toViewController.view.transform = CGAffineTransform(translationX: toViewController.view.frame.size.width, y: 0) + toViewController.view.transform = CGAffineTransform(translationX: toViewControllerTranslationXMultiplier * toViewController.view.frame.size.width, y: 0) UIView.animate(withDuration: self.transitionDuration(using: transitionContext), delay: 0, options: [ .curveEaseInOut ], animations: { - fromViewController.view.transform = CGAffineTransform(translationX: -0.5 * fromViewController.view.frame.size.width, y: 0) + fromViewController.view.transform = CGAffineTransform(translationX: fromViewControllerTranslationXMultiplier * fromViewController.view.frame.size.width, y: 0) toViewController.view.transform = .identity }, completion: { _ in fromViewController.view.transform = .identity diff --git a/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift b/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift index 6c4f304f8..9bf4c7664 100644 --- a/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift +++ b/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift @@ -24,11 +24,17 @@ open class ThemeTableViewCell: UITableViewCell, Themeable { var updateLabelColors : Bool = true override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) + if style == .default { + // This is a workaround, because some cells with style .default does not support automatically Right-to-Left UI support. When switching to style .subtitle, the style will be kept, if no subtitle was set ant the RtL support will work on this cells + super.init(style: .subtitle, reuseIdentifier: reuseIdentifier) + } else { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } } convenience public init(withLabelColorUpdates labelColorUpdates: Bool, style: UITableViewCell.CellStyle = .default, reuseIdentifier: String? = nil) { self.init(style: style, reuseIdentifier: reuseIdentifier) + updateLabelColors = labelColorUpdates }