Merge branch 'charlesmchen/contactCellViewAccessories'

This commit is contained in:
Matthew Chen 2021-05-05 17:10:53 -03:00
commit e93d13ac49
11 changed files with 142 additions and 61 deletions

View File

@ -8,11 +8,11 @@ public typealias CVStackViewConfig = OWSStackView.Config
// MARK: -
class CVStackView {
public extension UIStackView {
public static func measure(config: CVStackViewConfig,
subviewSizes: [CGSize],
verboseLogging: Bool = false) -> CGSize {
static func measure(config: CVStackViewConfig,
subviewSizes: [CGSize],
verboseLogging: Bool = false) -> CGSize {
let spacingCount = max(0, subviewSizes.count - 1)
@ -56,6 +56,21 @@ class CVStackView {
}
return size
}
func apply(config: CVStackViewConfig) {
if self.axis != config.axis {
self.axis = config.axis
}
if self.alignment != config.alignment {
self.alignment = config.alignment
}
if self.spacing != config.spacing {
self.spacing = config.spacing
}
if self.layoutMargins != config.layoutMargins {
self.layoutMargins = config.layoutMargins
}
}
}
// MARK: -

View File

@ -380,25 +380,38 @@ class MessageDetailViewController: OWSTableViewController2 {
private func buildAccessoryView(text: String,
displayUDIndicator: Bool,
transaction: SDSAnyReadTransaction) -> UIView {
let label = UILabel()
label.textColor = Theme.ternaryTextColor
label.text = text
transaction: SDSAnyReadTransaction) -> ContactCellAccessoryView {
let label = CVLabel()
label.textAlignment = .right
label.font = .ows_dynamicTypeFootnoteClamped
let labelConfig = CVLabelConfig(text: text,
font: .ows_dynamicTypeFootnoteClamped,
textColor: Theme.ternaryTextColor)
labelConfig.applyForRendering(label: label)
let labelSize = CVText.measureLabel(config: labelConfig, maxWidth: .greatestFiniteMagnitude)
let shouldShowUD = preferences.shouldShowUnidentifiedDeliveryIndicators(transaction: transaction)
guard displayUDIndicator && shouldShowUD else { return label }
guard displayUDIndicator && shouldShowUD else {
return ContactCellAccessoryView(accessoryView: label, size: labelSize)
}
let imageView = UIImageView()
let imageView = CVImageView()
imageView.setTemplateImageName(Theme.iconName(.sealedSenderIndicator), tintColor: Theme.ternaryTextColor)
let imageSize = CGSize.square(20)
let hStack = UIStackView(arrangedSubviews: [imageView, label])
hStack.axis = .horizontal
hStack.spacing = 8
return hStack
let hStack = ManualStackView(name: "hStack")
let hStackConfig = CVStackViewConfig(axis: .horizontal,
alignment: .center,
spacing: 8,
layoutMargins: .zero)
let hStackMeasurement = hStack.configure(config: hStackConfig,
subviews: [imageView, label],
subviewInfos: [
imageSize.asManualSubviewInfo(hasFixedSize: true),
labelSize.asManualSubviewInfo
])
let hStackSize = hStackMeasurement.measuredSize
return ContactCellAccessoryView(accessoryView: hStack, size: hStackSize)
}
private func buildValueLabel(name: String, value: String) -> UILabel {

View File

@ -530,7 +530,7 @@ extension BaseGroupMemberViewController: RecipientPickerDelegate {
func recipientPicker(_ recipientPickerViewController: RecipientPickerViewController,
accessoryViewForRecipient recipient: PickedRecipient,
transaction: SDSAnyReadTransaction) -> UIView? {
transaction: SDSAnyReadTransaction) -> ContactCellAccessoryView? {
guard let address = recipient.address else {
owsFailDebug("Missing address.")
return nil
@ -549,7 +549,7 @@ extension BaseGroupMemberViewController: RecipientPickerDelegate {
let isPreExistingMember = groupMemberViewDelegate.groupMemberViewIsPreExistingMember(recipient,
transaction: transaction)
let imageView = UIImageView()
let imageView = CVImageView()
if isPreExistingMember {
imageView.setTemplateImageName("check-circle-solid-24", tintColor: Theme.washColor)
} else if isCurrentMember {
@ -560,17 +560,13 @@ extension BaseGroupMemberViewController: RecipientPickerDelegate {
} else {
imageView.setTemplateImageName("empty-circle-outline-24", tintColor: .ows_gray25)
}
return imageView
return ContactCellAccessoryView(accessoryView: imageView, size: .square(24))
}
func recipientPicker(_ recipientPickerViewController: RecipientPickerViewController,
attributedSubtitleForRecipient recipient: PickedRecipient,
transaction: SDSAnyReadTransaction) -> NSAttributedString? {
guard let groupMemberViewDelegate = groupMemberViewDelegate else {
owsFailDebug("Missing delegate.")
return nil
}
guard let address = recipient.address else {
owsFailDebug("Recipient missing address.")
return nil

View File

@ -40,7 +40,7 @@ protocol RecipientPickerDelegate: AnyObject {
@objc
optional func recipientPicker(_ recipientPickerViewController: RecipientPickerViewController,
accessoryViewForRecipient recipient: PickedRecipient,
transaction: SDSAnyReadTransaction) -> UIView?
transaction: SDSAnyReadTransaction) -> ContactCellAccessoryView?
@objc
optional func recipientPicker(_ recipientPickerViewController: RecipientPickerViewController,
@ -172,7 +172,7 @@ extension RecipientPickerViewController {
func item(forRecipient recipient: PickedRecipient) -> OWSTableItem {
let tableView = self.tableView
switch recipient.identifier {
case .address(let address):
return OWSTableItem(

View File

@ -510,7 +510,10 @@ private class SafetyNumberCell: ContactTableViewCell {
configuration.forceDarkAppearance = (theme == .translucentDark)
configuration.accessoryView = button
let buttonSize = button.sizeThatFits(.square(.greatestFiniteMagnitude))
let buttonWrapper = ManualLayoutView.wrapSubviewUsingIOSAutoLayout(button)
configuration.accessoryView = ContactCellAccessoryView(accessoryView: buttonWrapper,
size: buttonSize)
if let verificationState = item.verificationState, verificationState == .noLongerVerified {
let previouslyVerified = NSMutableAttributedString()

View File

@ -181,11 +181,10 @@ public class GroupMemberRequestsAndInvitesViewController: OWSTableViewController
contents.addSection(section)
}
private func buildMemberRequestButtons(address: SignalServiceAddress) -> UIView {
private func buildMemberRequestButtons(address: SignalServiceAddress) -> ContactCellAccessoryView {
let buttonHeight: CGFloat = 28
let denyButton = OWSButton()
denyButton.autoSetDimensions(to: CGSize(square: buttonHeight))
denyButton.layer.cornerRadius = buttonHeight / 2
denyButton.clipsToBounds = true
denyButton.setBackgroundImage(UIImage(color: Theme.secondaryBackgroundColor), for: .normal)
@ -196,7 +195,6 @@ public class GroupMemberRequestsAndInvitesViewController: OWSTableViewController
}
let approveButton = OWSButton()
approveButton.autoSetDimensions(to: CGSize(square: buttonHeight))
approveButton.layer.cornerRadius = buttonHeight / 2
approveButton.clipsToBounds = true
approveButton.setBackgroundImage(UIImage(color: Theme.secondaryBackgroundColor), for: .normal)
@ -206,10 +204,25 @@ public class GroupMemberRequestsAndInvitesViewController: OWSTableViewController
self?.approveMemberRequest(address: address)
}
let stackView = UIStackView(arrangedSubviews: [denyButton, approveButton])
stackView.axis = .horizontal
stackView.spacing = 16
return stackView
let denyWrapper = ManualLayoutView.wrapSubviewUsingIOSAutoLayout(denyButton)
let approveWrapper = ManualLayoutView.wrapSubviewUsingIOSAutoLayout(approveButton)
let denyButtonSize = CGSize.square(buttonHeight)
let approveButtonSize = CGSize.square(buttonHeight)
let stackView = ManualStackView(name: "stackView")
let stackConfig = CVStackViewConfig(axis: .horizontal,
alignment: .center,
spacing: 16,
layoutMargins: .zero)
let stackMeasurement = stackView.configure(config: stackConfig,
subviews: [denyWrapper, approveWrapper],
subviewInfos: [
denyButtonSize.asManualSubviewInfo,
approveButtonSize.asManualSubviewInfo
])
let stackSize = stackMeasurement.measuredSize
return ContactCellAccessoryView(accessoryView: stackView, size: stackSize)
}
private func approveMemberRequest(address: SignalServiceAddress) {

View File

@ -62,9 +62,9 @@ class ReplaceAdminViewController: OWSTableViewController2 {
localUserDisplayMode: .asUser,
transaction: transaction)
let imageView = UIImageView()
let imageView = CVImageView()
imageView.setTemplateImageName("empty-circle-outline-24", tintColor: .ows_gray25)
configuration.accessoryView = imageView
configuration.accessoryView = ContactCellAccessoryView(accessoryView: imageView, size: .square(24))
cell.configure(configuration: configuration, transaction: transaction)
}

View File

@ -687,21 +687,33 @@ private class ConversationPickerCell: ContactTableViewCell {
return container
}()
func buildAccessoryView(disappearingMessagesConfig: OWSDisappearingMessagesConfiguration?) -> UIView {
func buildAccessoryView(disappearingMessagesConfig: OWSDisappearingMessagesConfiguration?) -> ContactCellAccessoryView {
let selectionWrapper = ManualLayoutView.wrapSubviewUsingIOSAutoLayout(selectionView)
guard let disappearingMessagesConfig = disappearingMessagesConfig,
disappearingMessagesConfig.isEnabled else {
return selectionView
return ContactCellAccessoryView(accessoryView: selectionWrapper,
size: selectionBadgeSize)
}
let timerView = DisappearingTimerConfigurationView(durationSeconds: disappearingMessagesConfig.durationSeconds)
timerView.tintColor = Theme.middleGrayColor
timerView.autoSetDimensions(to: CGSize(square: 44))
timerView.setCompressionResistanceHigh()
let timerSize = CGSize(square: 44)
let stackView = UIStackView(arrangedSubviews: [timerView, selectionView])
stackView.alignment = .center
stackView.setCompressionResistanceHigh()
return stackView
let stackView = ManualStackView(name: "stackView")
let stackConfig = OWSStackView.Config(axis: .horizontal,
alignment: .center,
spacing: 0,
layoutMargins: .zero)
let stackMeasurement = stackView.configure(config: stackConfig,
subviews: [timerView, selectionWrapper],
subviewInfos: [
timerSize.asManualSubviewInfo,
selectionBadgeSize.asManualSubviewInfo
])
let stackSize = stackMeasurement.measuredSize
return ContactCellAccessoryView(accessoryView: stackView, size: stackSize)
}
lazy var unselectedBadgeView: UIView = {

View File

@ -4,6 +4,19 @@
import Foundation
@objc
public class ContactCellAccessoryView: NSObject {
let accessoryView: UIView
let size: CGSize
public init(accessoryView: UIView, size: CGSize) {
self.accessoryView = accessoryView
self.size = size
}
}
// MARK: -
@objc
public class ContactCellConfiguration: NSObject {
public let content: ConversationContent
@ -24,7 +37,7 @@ public class ContactCellConfiguration: NSObject {
public var customName: String?
@objc
public var accessoryView: UIView?
public var accessoryView: ContactCellAccessoryView?
@objc
public var attributedSubtitle: NSAttributedString?
@ -184,24 +197,22 @@ public class ContactCellView: ManualStackView {
alignment: .leading,
spacing: 0,
layoutMargins: .zero)
let textStackMeasurement = ManualStackView.measure(config: textStackConfig,
subviewInfos: textStackSubviewInfos)
textStack.configure(config: textStackConfig,
measurement: textStackMeasurement,
subviews: textStackSubviews)
let textStackMeasurement = textStack.configure(config: textStackConfig,
subviews: textStackSubviews,
subviewInfos: textStackSubviewInfos)
rootStackSubviews.append(textStack)
rootStackSubviewInfos.append(textStackMeasurement.measuredSize.asManualSubviewInfo)
}
if let accessoryMessage = configuration.accessoryMessage {
accessoryLabel.text = accessoryMessage
owsAssertDebug(configuration.accessoryView == nil)
configuration.accessoryView = accessoryLabel
let labelSize = accessoryLabel.sizeThatFits(.square(.greatestFiniteMagnitude))
configuration.accessoryView = ContactCellAccessoryView(accessoryView: accessoryLabel,
size: labelSize)
}
if let accessoryView = configuration.accessoryView {
rootStackSubviews.append(accessoryView)
let accessorySize = accessoryView.sizeThatFits(.square(.greatestFiniteMagnitude))
rootStackSubviewInfos.append(accessorySize.asManualSubviewInfo(hasFixedSize: true))
rootStackSubviews.append(accessoryView.accessoryView)
rootStackSubviewInfos.append(accessoryView.size.asManualSubviewInfo(hasFixedSize: true))
}
let rootStackConfig = ManualStackView.Config(axis: .horizontal,

View File

@ -303,14 +303,17 @@ public class CVText {
}
let result: CGSize
switch mode {
case .layoutManager:
result = measureLabelUsingLayoutManager(config: config, maxWidth: maxWidth)
case .view:
result = measureLabelUsingView(config: config, maxWidth: maxWidth)
if config.text.stringValue.isEmpty {
result = .zero
} else {
switch mode {
case .layoutManager:
result = measureLabelUsingLayoutManager(config: config, maxWidth: maxWidth)
case .view:
result = measureLabelUsingView(config: config, maxWidth: maxWidth)
}
owsAssertDebug(result.isNonEmpty)
}
owsAssertDebug(result.width > 0)
owsAssertDebug(result.height > 0)
if cacheMeasurements {
labelCache.set(key: cacheKey, value: result.ceil)

View File

@ -703,3 +703,18 @@ public struct ManualStackMeasurement: Equatable {
ManualStackMeasurement(measuredSize: measuredSize, subviewInfos: [])
}
}
// MARK: -
public extension ManualStackView {
@discardableResult
func configure(
config: Config,
subviews: [UIView],
subviewInfos: [ManualStackSubviewInfo]
) -> Measurement {
let measurement = ManualStackView.measure(config: config, subviewInfos: subviewInfos)
self.configure(config: config, measurement: measurement, subviews: subviews)
return measurement
}
}