session-ios/SignalUtilitiesKit/Profile Pictures/ProfilePictureView.swift

152 lines
6.9 KiB
Swift
Raw Normal View History

2020-11-09 06:03:59 +01:00
import SessionUIKit
2019-11-28 06:42:07 +01:00
2019-12-10 04:27:38 +01:00
@objc(LKProfilePictureView)
2020-01-20 03:20:27 +01:00
public final class ProfilePictureView : UIView {
2021-02-26 04:42:46 +01:00
private var hasTappableProfilePicture: Bool = false
@objc public var size: CGFloat = 0 // Not an implicitly unwrapped optional due to Obj-C limitations
@objc public var useFallbackPicture = false
@objc public var publicKey: String!
@objc public var additionalPublicKey: String?
@objc public var openGroupProfilePicture: UIImage?
// Constraints
2019-11-28 06:42:07 +01:00
private var imageViewWidthConstraint: NSLayoutConstraint!
private var imageViewHeightConstraint: NSLayoutConstraint!
2020-09-14 03:31:45 +02:00
private var additionalImageViewWidthConstraint: NSLayoutConstraint!
private var additionalImageViewHeightConstraint: NSLayoutConstraint!
2019-11-28 06:42:07 +01:00
// MARK: Components
private lazy var imageView = getImageView()
private lazy var additionalImageView = getImageView()
// MARK: Lifecycle
2020-01-20 03:20:27 +01:00
public override init(frame: CGRect) {
2019-11-28 06:42:07 +01:00
super.init(frame: frame)
2019-12-02 01:58:15 +01:00
setUpViewHierarchy()
2019-11-28 06:42:07 +01:00
}
2020-01-20 03:20:27 +01:00
public required init?(coder: NSCoder) {
2019-11-28 06:42:07 +01:00
super.init(coder: coder)
2019-12-02 01:58:15 +01:00
setUpViewHierarchy()
2019-11-28 06:42:07 +01:00
}
2019-12-02 01:58:15 +01:00
private func setUpViewHierarchy() {
2019-11-28 06:42:07 +01:00
// Set up image view
addSubview(imageView)
imageView.pin(.leading, to: .leading, of: self)
imageView.pin(.top, to: .top, of: self)
2020-03-17 06:18:53 +01:00
let imageViewSize = CGFloat(Values.mediumProfilePictureSize)
2020-01-22 03:34:49 +01:00
imageViewWidthConstraint = imageView.set(.width, to: imageViewSize)
imageViewHeightConstraint = imageView.set(.height, to: imageViewSize)
2019-11-28 06:42:07 +01:00
// Set up additional image view
addSubview(additionalImageView)
additionalImageView.pin(.trailing, to: .trailing, of: self)
additionalImageView.pin(.bottom, to: .bottom, of: self)
2020-03-17 06:18:53 +01:00
let additionalImageViewSize = CGFloat(Values.smallProfilePictureSize)
2020-09-14 03:31:45 +02:00
additionalImageViewWidthConstraint = additionalImageView.set(.width, to: additionalImageViewSize)
additionalImageViewHeightConstraint = additionalImageView.set(.height, to: additionalImageViewSize)
2019-11-28 06:42:07 +01:00
additionalImageView.layer.cornerRadius = additionalImageViewSize / 2
}
// MARK: Updating
2020-10-02 01:03:06 +02:00
@objc(updateForContact:)
public func update(for publicKey: String) {
openGroupProfilePicture = nil
2021-02-26 04:42:46 +01:00
self.publicKey = publicKey
additionalPublicKey = nil
useFallbackPicture = false
2020-10-02 01:03:06 +02:00
update()
}
@objc(updateForThread:)
public func update(for thread: TSThread) {
openGroupProfilePicture = nil
2020-09-14 03:31:45 +02:00
if let thread = thread as? TSGroupThread {
if let openGroupProfilePicture = thread.groupModel.groupImage { // An open group with a profile picture
self.openGroupProfilePicture = openGroupProfilePicture
2021-02-26 04:42:46 +01:00
useFallbackPicture = false
2020-10-30 01:07:37 +01:00
hasTappableProfilePicture = true
2020-11-16 00:34:47 +01:00
} else if thread.groupModel.groupType == .openGroup { // An open group without a profile picture or an RSS feed
2021-02-26 04:42:46 +01:00
publicKey = ""
useFallbackPicture = true
} else { // A closed group
2021-08-03 01:37:48 +02:00
var users = Set(thread.groupModel.groupMemberIds)
users.remove(getUserHexEncodedPublicKey())
var randomUsers = users.sorted() // Sort to provide a level of stability
if users.count == 1 {
randomUsers.insert(getUserHexEncodedPublicKey(), at: 0) // Ensure the current user is at the back visually
}
2021-02-26 04:42:46 +01:00
publicKey = randomUsers.count >= 1 ? randomUsers[0] : ""
additionalPublicKey = randomUsers.count >= 2 ? randomUsers[1] : ""
useFallbackPicture = false
}
2020-10-02 01:03:06 +02:00
update()
2020-09-14 03:31:45 +02:00
} else { // A one-to-one chat
2021-05-05 01:53:18 +02:00
let thread = thread as! TSContactThread
hasTappableProfilePicture = OWSProfileManager.shared().profileAvatar(forRecipientId: thread.contactSessionID()) != nil
update(for: thread.contactSessionID())
}
}
2020-01-20 03:20:27 +01:00
@objc public func update() {
2020-06-15 05:50:56 +02:00
AssertIsOnMainThread()
2020-10-02 01:03:06 +02:00
func getProfilePicture(of size: CGFloat, for publicKey: String) -> UIImage? {
guard !publicKey.isEmpty else { return nil }
if let profilePicture = OWSProfileManager.shared().profileAvatar(forRecipientId: publicKey) {
2020-09-14 03:31:45 +02:00
return profilePicture
} else {
2021-02-26 05:56:41 +01:00
// TODO: Pass in context?
let displayName = Storage.shared.getContact(with: publicKey)?.name ?? publicKey
2020-10-02 01:03:06 +02:00
return Identicon.generatePlaceholderIcon(seed: publicKey, text: displayName, size: size)
2020-09-14 03:31:45 +02:00
}
2019-11-29 06:30:01 +01:00
}
2019-11-28 06:42:07 +01:00
let size: CGFloat
2021-02-26 04:42:46 +01:00
if let additionalPublicKey = additionalPublicKey, !useFallbackPicture, openGroupProfilePicture == nil {
2020-09-14 03:31:45 +02:00
if self.size == 40 {
size = 32
} else if self.size == Values.largeProfilePictureSize {
size = 56
} else {
size = Values.smallProfilePictureSize
}
2020-01-22 03:34:49 +01:00
imageViewWidthConstraint.constant = size
imageViewHeightConstraint.constant = size
2020-09-14 03:31:45 +02:00
additionalImageViewWidthConstraint.constant = size
additionalImageViewHeightConstraint.constant = size
2019-11-28 06:42:07 +01:00
additionalImageView.isHidden = false
2021-02-26 04:42:46 +01:00
additionalImageView.image = getProfilePicture(of: size, for: additionalPublicKey)
2019-11-28 06:42:07 +01:00
} else {
size = self.size
2020-01-22 03:34:49 +01:00
imageViewWidthConstraint.constant = size
imageViewHeightConstraint.constant = size
2019-11-28 06:42:07 +01:00
additionalImageView.isHidden = true
additionalImageView.image = nil
}
2021-02-26 04:42:46 +01:00
guard publicKey != nil || openGroupProfilePicture != nil else { return }
imageView.image = useFallbackPicture ? nil : (openGroupProfilePicture ?? getProfilePicture(of: size, for: publicKey))
imageView.backgroundColor = useFallbackPicture ? UIColor(rgbHex: 0x353535) : Colors.unimportant
2019-11-28 06:42:07 +01:00
imageView.layer.cornerRadius = size / 2
2020-09-14 03:31:45 +02:00
additionalImageView.layer.cornerRadius = size / 2
2021-02-26 04:42:46 +01:00
imageView.contentMode = useFallbackPicture ? .center : .scaleAspectFit
if useFallbackPicture {
2020-09-14 03:31:45 +02:00
switch size {
case Values.smallProfilePictureSize..<Values.mediumProfilePictureSize: imageView.image = #imageLiteral(resourceName: "SessionWhite16")
case Values.mediumProfilePictureSize..<Values.largeProfilePictureSize: imageView.image = #imageLiteral(resourceName: "SessionWhite24")
default: imageView.image = #imageLiteral(resourceName: "SessionWhite40")
}
}
2019-11-28 06:42:07 +01:00
}
// MARK: Convenience
private func getImageView() -> UIImageView {
let result = UIImageView()
result.layer.masksToBounds = true
2020-03-17 06:18:53 +01:00
result.backgroundColor = Colors.unimportant
2019-11-29 06:30:01 +01:00
result.contentMode = .scaleAspectFit
2019-11-28 06:42:07 +01:00
return result
}
@objc public func getProfilePicture() -> UIImage? {
2020-10-30 01:07:37 +01:00
return hasTappableProfilePicture ? imageView.image : nil
}
2019-11-28 06:42:07 +01:00
}