session-ios/Session/Signal/ContactCell.swift

163 lines
6.4 KiB
Swift

//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import UIKit
import Contacts
import SignalUtilitiesKit
class ContactCell: UITableViewCell {
public static let kSeparatorHInset: CGFloat = CGFloat(kAvatarDiameter) + 16 + 8
static let kAvatarSpacing: CGFloat = 6
static let kAvatarDiameter: UInt = 40
let contactImageView: AvatarImageView
let textStackView: UIStackView
let titleLabel: UILabel
var subtitleLabel: UILabel
var contact: Contact?
var showsWhenSelected: Bool = false
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
self.contactImageView = AvatarImageView()
self.textStackView = UIStackView()
self.titleLabel = UILabel()
self.titleLabel.font = UIFont.ows_dynamicTypeBody
self.subtitleLabel = UILabel()
self.subtitleLabel.font = UIFont.ows_dynamicTypeSubheadline
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = UITableViewCell.SelectionStyle.none
textStackView.axis = .vertical
textStackView.addArrangedSubview(titleLabel)
contactImageView.autoSetDimensions(to: CGSize(width: CGFloat(ContactCell.kAvatarDiameter), height: CGFloat(ContactCell.kAvatarDiameter)))
let contentColumns: UIStackView = UIStackView(arrangedSubviews: [contactImageView, textStackView])
contentColumns.axis = .horizontal
contentColumns.spacing = ContactCell.kAvatarSpacing
contentColumns.alignment = .center
self.contentView.addSubview(contentColumns)
contentColumns.autoPinEdgesToSuperviewMargins()
NotificationCenter.default.addObserver(self, selector: #selector(self.didChangePreferredContentSize), name: UIContentSizeCategory.didChangeNotification, object: nil)
}
required init?(coder aDecoder: NSCoder) {
notImplemented()
}
override func prepareForReuse() {
accessoryType = .none
self.subtitleLabel.removeFromSuperview()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if showsWhenSelected {
accessoryType = selected ? .checkmark : .none
}
}
@objc func didChangePreferredContentSize() {
self.titleLabel.font = UIFont.ows_dynamicTypeBody
self.subtitleLabel.font = UIFont.ows_dynamicTypeSubheadline
}
func configure(contact: Contact, subtitleType: SubtitleCellValue, showsWhenSelected: Bool, contactsManager: OWSContactsManager) {
OWSTableItem.configureCell(self)
self.contact = contact
self.showsWhenSelected = showsWhenSelected
self.titleLabel.textColor = Theme.primaryColor
self.subtitleLabel.textColor = Theme.secondaryColor
let cnContact = contactsManager.cnContact(withId: contact.cnContactId)
titleLabel.attributedText = cnContact?.formattedFullName(font: titleLabel.font)
updateSubtitle(subtitleType: subtitleType, contact: contact)
if let contactImage = contactsManager.avatarImage(forCNContactId: contact.cnContactId) {
contactImageView.image = contactImage
} else {
let contactIdForDeterminingBackgroundColor: String
if let signalId = contact.parsedPhoneNumbers.first?.toE164() {
contactIdForDeterminingBackgroundColor = signalId
} else {
contactIdForDeterminingBackgroundColor = contact.fullName
}
let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.fullName,
colorSeed: contactIdForDeterminingBackgroundColor,
diameter: ContactCell.kAvatarDiameter)
contactImageView.image = avatarBuilder.build()
}
}
func updateSubtitle(subtitleType: SubtitleCellValue, contact: Contact) {
switch subtitleType {
case .none:
assert(self.subtitleLabel.superview == nil)
break
case .phoneNumber:
self.textStackView.addArrangedSubview(self.subtitleLabel)
if let firstPhoneNumber = contact.userTextPhoneNumbers.first {
self.subtitleLabel.text = firstPhoneNumber
} else {
self.subtitleLabel.text = NSLocalizedString("CONTACT_PICKER_NO_PHONE_NUMBERS_AVAILABLE", comment: "table cell subtitle when contact card has no known phone number")
}
case .email:
self.textStackView.addArrangedSubview(self.subtitleLabel)
if let firstEmail = contact.emails.first {
self.subtitleLabel.text = firstEmail
} else {
self.subtitleLabel.text = NSLocalizedString("CONTACT_PICKER_NO_EMAILS_AVAILABLE", comment: "table cell subtitle when contact card has no email")
}
}
}
}
fileprivate extension CNContact {
/**
* Bold the sorting portion of the name. e.g. if we sort by family name, bold the family name.
*/
func formattedFullName(font: UIFont) -> NSAttributedString? {
let keyToHighlight = ContactSortOrder == .familyName ? CNContactFamilyNameKey : CNContactGivenNameKey
let boldDescriptor = font.fontDescriptor.withSymbolicTraits(.traitBold)
let boldAttributes = [
NSAttributedString.Key.font: UIFont(descriptor: boldDescriptor!, size: 0)
]
if let attributedName = CNContactFormatter.attributedString(from: self, style: .fullName, defaultAttributes: nil) {
let highlightedName = attributedName.mutableCopy() as! NSMutableAttributedString
highlightedName.enumerateAttributes(in: NSRange(location: 0, length: highlightedName.length), options: [], using: { (attrs, range, _) in
if let property = attrs[NSAttributedString.Key(rawValue: CNContactPropertyAttribute)] as? String, property == keyToHighlight {
highlightedName.addAttributes(boldAttributes, range: range)
}
})
return highlightedName
}
if let emailAddress = self.emailAddresses.first?.value {
return NSAttributedString(string: emailAddress as String, attributes: boldAttributes)
}
if let phoneNumber = self.phoneNumbers.first?.value.stringValue {
return NSAttributedString(string: phoneNumber, attributes: boldAttributes)
}
return nil
}
}