Updated the profile picture modal and standardised the ProfilePictureView sizes
Fixed an issue where 'CurrentAppContext().isMainAppAndActive' wasn't called on the main thread Updated the ProfilePictureView to have the updated icon UI
This commit is contained in:
parent
2035d508d9
commit
2d792e4e3e
|
@ -205,9 +205,9 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
guard CurrentAppContext().isMainAppAndActive else { return }
|
guard CurrentAppContext().isMainAppAndActive else { return }
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
guard let presentingVC = CurrentAppContext().frontmostViewController() else {
|
guard let presentingVC = CurrentAppContext().frontmostViewController() else {
|
||||||
preconditionFailure() // FIXME: Handle more gracefully
|
preconditionFailure() // FIXME: Handle more gracefully
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
||||||
import WebRTC
|
import WebRTC
|
||||||
import SessionUIKit
|
import SessionUIKit
|
||||||
import SessionMessagingKit
|
import SessionMessagingKit
|
||||||
|
import SignalUtilitiesKit
|
||||||
|
|
||||||
final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
|
final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
|
||||||
private static let swipeToOperateThreshold: CGFloat = 60
|
private static let swipeToOperateThreshold: CGFloat = 60
|
||||||
|
@ -20,14 +21,7 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
|
||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = {
|
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView(size: .list)
|
||||||
let result = ProfilePictureView()
|
|
||||||
let size: CGFloat = 60
|
|
||||||
result.size = size
|
|
||||||
result.set(.width, to: size)
|
|
||||||
result.set(.height, to: size)
|
|
||||||
return result
|
|
||||||
}()
|
|
||||||
|
|
||||||
private lazy var displayNameLabel: UILabel = {
|
private lazy var displayNameLabel: UILabel = {
|
||||||
let result = UILabel()
|
let result = UILabel()
|
||||||
|
|
|
@ -1104,15 +1104,13 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
|
||||||
|
|
||||||
switch threadData.threadVariant {
|
switch threadData.threadVariant {
|
||||||
case .contact:
|
case .contact:
|
||||||
let profilePictureView = ProfilePictureView()
|
let profilePictureView = ProfilePictureView(size: .navigation)
|
||||||
profilePictureView.size = Values.verySmallProfilePictureSize
|
|
||||||
profilePictureView.update(
|
profilePictureView.update(
|
||||||
publicKey: threadData.threadId, // Contact thread uses the contactId
|
publicKey: threadData.threadId, // Contact thread uses the contactId
|
||||||
profile: threadData.profile,
|
profile: threadData.profile,
|
||||||
threadVariant: threadData.threadVariant
|
threadVariant: threadData.threadVariant
|
||||||
)
|
)
|
||||||
profilePictureView.set(.width, to: (44 - 16)) // Width of the standard back button
|
profilePictureView.customWidth = (44 - 16) // Width of the standard back button
|
||||||
profilePictureView.set(.height, to: Values.verySmallProfilePictureSize)
|
|
||||||
|
|
||||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
||||||
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
||||||
import SessionUIKit
|
import SessionUIKit
|
||||||
import SessionMessagingKit
|
import SessionMessagingKit
|
||||||
import SessionUtilitiesKit
|
import SessionUtilitiesKit
|
||||||
|
import SignalUtilitiesKit
|
||||||
|
|
||||||
final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, MentionSelectionViewDelegate {
|
final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, MentionSelectionViewDelegate {
|
||||||
// MARK: - Variables
|
// MARK: - Variables
|
||||||
|
@ -491,7 +492,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
|
||||||
func showMentionsUI(for candidates: [MentionInfo]) {
|
func showMentionsUI(for candidates: [MentionInfo]) {
|
||||||
mentionsView.candidates = candidates
|
mentionsView.candidates = candidates
|
||||||
|
|
||||||
let mentionCellHeight = (Values.smallProfilePictureSize + 2 * Values.smallSpacing)
|
let mentionCellHeight = (ProfilePictureView.Size.message.viewSize + 2 * Values.smallSpacing)
|
||||||
mentionsViewHeightConstraint.constant = CGFloat(min(3, candidates.count)) * mentionCellHeight
|
mentionsViewHeightConstraint.constant = CGFloat(min(3, candidates.count)) * mentionCellHeight
|
||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
|
|
||||||
|
|
|
@ -111,9 +111,7 @@ private extension MentionSelectionView {
|
||||||
final class Cell: UITableViewCell {
|
final class Cell: UITableViewCell {
|
||||||
// MARK: - UI
|
// MARK: - UI
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView()
|
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView(size: .message)
|
||||||
|
|
||||||
private lazy var moderatorIconImageView: UIImageView = UIImageView(image: #imageLiteral(resourceName: "Crown"))
|
|
||||||
|
|
||||||
private lazy var displayNameLabel: UILabel = {
|
private lazy var displayNameLabel: UILabel = {
|
||||||
let result: UILabel = UILabel()
|
let result: UILabel = UILabel()
|
||||||
|
@ -155,18 +153,12 @@ private extension MentionSelectionView {
|
||||||
selectedBackgroundView.themeBackgroundColor = .highlighted(.settings_tabBackground)
|
selectedBackgroundView.themeBackgroundColor = .highlighted(.settings_tabBackground)
|
||||||
self.selectedBackgroundView = selectedBackgroundView
|
self.selectedBackgroundView = selectedBackgroundView
|
||||||
|
|
||||||
// Profile picture image view
|
|
||||||
let profilePictureViewSize = Values.smallProfilePictureSize
|
|
||||||
profilePictureView.set(.width, to: profilePictureViewSize)
|
|
||||||
profilePictureView.set(.height, to: profilePictureViewSize)
|
|
||||||
profilePictureView.size = profilePictureViewSize
|
|
||||||
|
|
||||||
// Main stack view
|
// Main stack view
|
||||||
let mainStackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel ])
|
let mainStackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel ])
|
||||||
mainStackView.axis = .horizontal
|
mainStackView.axis = .horizontal
|
||||||
mainStackView.alignment = .center
|
mainStackView.alignment = .center
|
||||||
mainStackView.spacing = Values.mediumSpacing
|
mainStackView.spacing = Values.mediumSpacing
|
||||||
mainStackView.set(.height, to: profilePictureViewSize)
|
mainStackView.set(.height, to: ProfilePictureView.Size.message.viewSize)
|
||||||
contentView.addSubview(mainStackView)
|
contentView.addSubview(mainStackView)
|
||||||
mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.mediumSpacing)
|
mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.mediumSpacing)
|
||||||
mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.smallSpacing)
|
mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.smallSpacing)
|
||||||
|
@ -174,13 +166,6 @@ private extension MentionSelectionView {
|
||||||
contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.smallSpacing)
|
contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.smallSpacing)
|
||||||
mainStackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing)
|
mainStackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing)
|
||||||
|
|
||||||
// Moderator icon image view
|
|
||||||
moderatorIconImageView.set(.width, to: 20)
|
|
||||||
moderatorIconImageView.set(.height, to: 20)
|
|
||||||
contentView.addSubview(moderatorIconImageView)
|
|
||||||
moderatorIconImageView.pin(.trailing, to: .trailing, of: profilePictureView, withInset: 1)
|
|
||||||
moderatorIconImageView.pin(.bottom, to: .bottom, of: profilePictureView, withInset: 4.5)
|
|
||||||
|
|
||||||
// Separator
|
// Separator
|
||||||
addSubview(separator)
|
addSubview(separator)
|
||||||
separator.pin(.leading, to: .leading, of: self)
|
separator.pin(.leading, to: .leading, of: self)
|
||||||
|
@ -200,9 +185,9 @@ private extension MentionSelectionView {
|
||||||
profilePictureView.update(
|
profilePictureView.update(
|
||||||
publicKey: profile.id,
|
publicKey: profile.id,
|
||||||
profile: profile,
|
profile: profile,
|
||||||
|
icon: (isUserModeratorOrAdmin ? .crown : .none),
|
||||||
threadVariant: threadVariant
|
threadVariant: threadVariant
|
||||||
)
|
)
|
||||||
moderatorIconImageView.isHidden = !isUserModeratorOrAdmin
|
|
||||||
separator.isHidden = isLast
|
separator.isHidden = isLast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
private lazy var authorLabelTopConstraint = authorLabel.pin(.top, to: .top, of: self)
|
private lazy var authorLabelTopConstraint = authorLabel.pin(.top, to: .top, of: self)
|
||||||
private lazy var authorLabelHeightConstraint = authorLabel.set(.height, to: 0)
|
private lazy var authorLabelHeightConstraint = authorLabel.set(.height, to: 0)
|
||||||
private lazy var profilePictureViewLeadingConstraint = profilePictureView.pin(.leading, to: .leading, of: self, withInset: VisibleMessageCell.groupThreadHSpacing)
|
private lazy var profilePictureViewLeadingConstraint = profilePictureView.pin(.leading, to: .leading, of: self, withInset: VisibleMessageCell.groupThreadHSpacing)
|
||||||
private lazy var profilePictureViewWidthConstraint = profilePictureView.set(.width, to: Values.verySmallProfilePictureSize)
|
|
||||||
private lazy var contentViewLeadingConstraint1 = snContentView.pin(.leading, to: .trailing, of: profilePictureView, withInset: VisibleMessageCell.groupThreadHSpacing)
|
private lazy var contentViewLeadingConstraint1 = snContentView.pin(.leading, to: .trailing, of: profilePictureView, withInset: VisibleMessageCell.groupThreadHSpacing)
|
||||||
private lazy var contentViewLeadingConstraint2 = snContentView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: VisibleMessageCell.gutterSize)
|
private lazy var contentViewLeadingConstraint2 = snContentView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: VisibleMessageCell.gutterSize)
|
||||||
private lazy var contentViewTopConstraint = snContentView.pin(.top, to: .bottom, of: authorLabel, withInset: VisibleMessageCell.authorLabelBottomSpacing)
|
private lazy var contentViewTopConstraint = snContentView.pin(.top, to: .bottom, of: authorLabel, withInset: VisibleMessageCell.authorLabelBottomSpacing)
|
||||||
|
@ -51,22 +50,13 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
private lazy var viewsToMoveForReply: [UIView] = [
|
private lazy var viewsToMoveForReply: [UIView] = [
|
||||||
snContentView,
|
snContentView,
|
||||||
profilePictureView,
|
profilePictureView,
|
||||||
moderatorIconImageView,
|
|
||||||
replyButton,
|
replyButton,
|
||||||
timerView,
|
timerView,
|
||||||
messageStatusImageView,
|
messageStatusImageView,
|
||||||
reactionContainerView
|
reactionContainerView
|
||||||
]
|
]
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = {
|
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView(size: .message)
|
||||||
let result: ProfilePictureView = ProfilePictureView()
|
|
||||||
result.set(.height, to: Values.verySmallProfilePictureSize)
|
|
||||||
result.size = Values.verySmallProfilePictureSize
|
|
||||||
|
|
||||||
return result
|
|
||||||
}()
|
|
||||||
|
|
||||||
private lazy var moderatorIconImageView = UIImageView(image: #imageLiteral(resourceName: "Crown"))
|
|
||||||
|
|
||||||
lazy var bubbleBackgroundView: UIView = {
|
lazy var bubbleBackgroundView: UIView = {
|
||||||
let result = UIView()
|
let result = UIView()
|
||||||
|
@ -176,7 +166,6 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
private static let messageStatusImageViewSize: CGFloat = 12
|
private static let messageStatusImageViewSize: CGFloat = 12
|
||||||
private static let authorLabelBottomSpacing: CGFloat = 4
|
private static let authorLabelBottomSpacing: CGFloat = 4
|
||||||
private static let groupThreadHSpacing: CGFloat = 12
|
private static let groupThreadHSpacing: CGFloat = 12
|
||||||
private static let profilePictureSize = Values.verySmallProfilePictureSize
|
|
||||||
private static let authorLabelInset: CGFloat = 12
|
private static let authorLabelInset: CGFloat = 12
|
||||||
private static let replyButtonSize: CGFloat = 24
|
private static let replyButtonSize: CGFloat = 24
|
||||||
private static let maxBubbleTranslationX: CGFloat = 40
|
private static let maxBubbleTranslationX: CGFloat = 40
|
||||||
|
@ -186,7 +175,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
static let contactThreadHSpacing = Values.mediumSpacing
|
static let contactThreadHSpacing = Values.mediumSpacing
|
||||||
|
|
||||||
static var gutterSize: CGFloat = {
|
static var gutterSize: CGFloat = {
|
||||||
var result = groupThreadHSpacing + profilePictureSize + groupThreadHSpacing
|
var result = groupThreadHSpacing + ProfilePictureView.Size.message.viewSize + groupThreadHSpacing
|
||||||
|
|
||||||
if UIDevice.current.isIPad {
|
if UIDevice.current.isIPad {
|
||||||
result += 168
|
result += 168
|
||||||
|
@ -195,7 +184,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
|
||||||
static var leftGutterSize: CGFloat { groupThreadHSpacing + profilePictureSize + groupThreadHSpacing }
|
static var leftGutterSize: CGFloat { groupThreadHSpacing + ProfilePictureView.Size.message.viewSize + groupThreadHSpacing }
|
||||||
|
|
||||||
// MARK: Direction & Position
|
// MARK: Direction & Position
|
||||||
|
|
||||||
|
@ -214,21 +203,13 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
// Profile picture view
|
// Profile picture view
|
||||||
addSubview(profilePictureView)
|
addSubview(profilePictureView)
|
||||||
profilePictureViewLeadingConstraint.isActive = true
|
profilePictureViewLeadingConstraint.isActive = true
|
||||||
profilePictureViewWidthConstraint.isActive = true
|
|
||||||
|
|
||||||
// Moderator icon image view
|
|
||||||
moderatorIconImageView.set(.width, to: 20)
|
|
||||||
moderatorIconImageView.set(.height, to: 20)
|
|
||||||
addSubview(moderatorIconImageView)
|
|
||||||
moderatorIconImageView.pin(.trailing, to: .trailing, of: profilePictureView, withInset: 1)
|
|
||||||
moderatorIconImageView.pin(.bottom, to: .bottom, of: profilePictureView, withInset: 4.5)
|
|
||||||
|
|
||||||
// Content view
|
// Content view
|
||||||
addSubview(snContentView)
|
addSubview(snContentView)
|
||||||
contentViewLeadingConstraint1.isActive = true
|
contentViewLeadingConstraint1.isActive = true
|
||||||
contentViewTopConstraint.isActive = true
|
contentViewTopConstraint.isActive = true
|
||||||
contentViewTrailingConstraint1.isActive = true
|
contentViewTrailingConstraint1.isActive = true
|
||||||
snContentView.pin(.bottom, to: .bottom, of: profilePictureView, withInset: -1)
|
snContentView.pin(.bottom, to: .bottom, of: profilePictureView)
|
||||||
|
|
||||||
// Bubble background view
|
// Bubble background view
|
||||||
bubbleBackgroundView.addSubview(bubbleView)
|
bubbleBackgroundView.addSubview(bubbleView)
|
||||||
|
@ -317,14 +298,13 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
|
||||||
|
|
||||||
// Profile picture view
|
// Profile picture view
|
||||||
profilePictureViewLeadingConstraint.constant = (isGroupThread ? VisibleMessageCell.groupThreadHSpacing : 0)
|
profilePictureViewLeadingConstraint.constant = (isGroupThread ? VisibleMessageCell.groupThreadHSpacing : 0)
|
||||||
profilePictureViewWidthConstraint.constant = (isGroupThread ? VisibleMessageCell.profilePictureSize : 0)
|
|
||||||
profilePictureView.isHidden = (!cellViewModel.shouldShowProfile || cellViewModel.profile == nil)
|
profilePictureView.isHidden = (!cellViewModel.shouldShowProfile || cellViewModel.profile == nil)
|
||||||
profilePictureView.update(
|
profilePictureView.update(
|
||||||
publicKey: cellViewModel.authorId,
|
publicKey: cellViewModel.authorId,
|
||||||
profile: cellViewModel.profile,
|
profile: cellViewModel.profile,
|
||||||
|
icon: (cellViewModel.isSenderOpenGroupModerator ? .crown : .none),
|
||||||
threadVariant: cellViewModel.threadVariant
|
threadVariant: cellViewModel.threadVariant
|
||||||
)
|
)
|
||||||
moderatorIconImageView.isHidden = (!cellViewModel.isSenderOpenGroupModerator || !cellViewModel.shouldShowProfile)
|
|
||||||
|
|
||||||
// Bubble view
|
// Bubble view
|
||||||
contentViewLeadingConstraint1.isActive = (
|
contentViewLeadingConstraint1.isActive = (
|
||||||
|
|
|
@ -477,19 +477,15 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi
|
||||||
|
|
||||||
private func updateNavBarButtons() {
|
private func updateNavBarButtons() {
|
||||||
// Profile picture view
|
// Profile picture view
|
||||||
let profilePictureSize = Values.verySmallProfilePictureSize
|
let profilePictureView = ProfilePictureView(size: .navigation)
|
||||||
let profilePictureView = ProfilePictureView()
|
|
||||||
profilePictureView.accessibilityIdentifier = "User settings"
|
profilePictureView.accessibilityIdentifier = "User settings"
|
||||||
profilePictureView.accessibilityLabel = "User settings"
|
profilePictureView.accessibilityLabel = "User settings"
|
||||||
profilePictureView.isAccessibilityElement = true
|
profilePictureView.isAccessibilityElement = true
|
||||||
profilePictureView.size = profilePictureSize
|
|
||||||
profilePictureView.update(
|
profilePictureView.update(
|
||||||
publicKey: getUserHexEncodedPublicKey(),
|
publicKey: getUserHexEncodedPublicKey(),
|
||||||
profile: Profile.fetchOrCreateCurrentUser(),
|
profile: Profile.fetchOrCreateCurrentUser(),
|
||||||
threadVariant: .contact
|
threadVariant: .contact
|
||||||
)
|
)
|
||||||
profilePictureView.set(.width, to: profilePictureSize)
|
|
||||||
profilePictureView.set(.height, to: profilePictureSize)
|
|
||||||
|
|
||||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
||||||
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SessionUIKit
|
import SessionUIKit
|
||||||
|
import SignalUtilitiesKit
|
||||||
|
|
||||||
class MessageRequestsCell: UITableViewCell {
|
class MessageRequestsCell: UITableViewCell {
|
||||||
static let reuseIdentifier = "MessageRequestsCell"
|
static let reuseIdentifier = "MessageRequestsCell"
|
||||||
|
@ -29,7 +30,7 @@ class MessageRequestsCell: UITableViewCell {
|
||||||
result.translatesAutoresizingMaskIntoConstraints = false
|
result.translatesAutoresizingMaskIntoConstraints = false
|
||||||
result.clipsToBounds = true
|
result.clipsToBounds = true
|
||||||
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
|
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
|
||||||
result.layer.cornerRadius = (Values.mediumProfilePictureSize / 2)
|
result.layer.cornerRadius = (ProfilePictureView.Size.list.viewSize / 2)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
@ -100,8 +101,8 @@ class MessageRequestsCell: UITableViewCell {
|
||||||
constant: (Values.accentLineThickness + Values.mediumSpacing)
|
constant: (Values.accentLineThickness + Values.mediumSpacing)
|
||||||
),
|
),
|
||||||
iconContainerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
iconContainerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
|
||||||
iconContainerView.widthAnchor.constraint(equalToConstant: Values.mediumProfilePictureSize),
|
iconContainerView.widthAnchor.constraint(equalToConstant: ProfilePictureView.Size.list.viewSize),
|
||||||
iconContainerView.heightAnchor.constraint(equalToConstant: Values.mediumProfilePictureSize),
|
iconContainerView.heightAnchor.constraint(equalToConstant: ProfilePictureView.Size.list.viewSize),
|
||||||
|
|
||||||
iconImageView.centerXAnchor.constraint(equalTo: iconContainerView.centerXAnchor),
|
iconImageView.centerXAnchor.constraint(equalTo: iconContainerView.centerXAnchor),
|
||||||
iconImageView.centerYAnchor.constraint(equalTo: iconContainerView.centerYAnchor),
|
iconImageView.centerYAnchor.constraint(equalTo: iconContainerView.centerYAnchor),
|
||||||
|
|
|
@ -8,7 +8,7 @@ import SignalUtilitiesKit
|
||||||
class BlockedContactCell: UITableViewCell {
|
class BlockedContactCell: UITableViewCell {
|
||||||
// MARK: - Components
|
// MARK: - Components
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView()
|
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView(size: .list)
|
||||||
|
|
||||||
private let selectionView: RadioButton = {
|
private let selectionView: RadioButton = {
|
||||||
let result: RadioButton = RadioButton(size: .medium)
|
let result: RadioButton = RadioButton(size: .medium)
|
||||||
|
@ -61,9 +61,6 @@ class BlockedContactCell: UITableViewCell {
|
||||||
.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -Values.mediumSpacing)
|
.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -Values.mediumSpacing)
|
||||||
.isActive = true
|
.isActive = true
|
||||||
profilePictureView.pin(.left, to: .left, of: contentView, withInset: Values.veryLargeSpacing)
|
profilePictureView.pin(.left, to: .left, of: contentView, withInset: Values.veryLargeSpacing)
|
||||||
profilePictureView.set(.width, to: Values.mediumProfilePictureSize)
|
|
||||||
profilePictureView.set(.height, to: Values.mediumProfilePictureSize)
|
|
||||||
profilePictureView.size = Values.mediumProfilePictureSize
|
|
||||||
|
|
||||||
selectionView.center(.vertical, in: contentView)
|
selectionView.center(.vertical, in: contentView)
|
||||||
selectionView.topAnchor
|
selectionView.topAnchor
|
||||||
|
|
|
@ -18,7 +18,7 @@ public final class FullConversationCell: UITableViewCell {
|
||||||
|
|
||||||
private let accentLineView: UIView = UIView()
|
private let accentLineView: UIView = UIView()
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView()
|
private lazy var profilePictureView: ProfilePictureView = ProfilePictureView(size: .list)
|
||||||
|
|
||||||
private lazy var displayNameLabel: UILabel = {
|
private lazy var displayNameLabel: UILabel = {
|
||||||
let result: UILabel = UILabel()
|
let result: UILabel = UILabel()
|
||||||
|
@ -159,12 +159,6 @@ public final class FullConversationCell: UITableViewCell {
|
||||||
accentLineView.set(.width, to: Values.accentLineThickness)
|
accentLineView.set(.width, to: Values.accentLineThickness)
|
||||||
accentLineView.set(.height, to: cellHeight)
|
accentLineView.set(.height, to: cellHeight)
|
||||||
|
|
||||||
// Profile picture view
|
|
||||||
let profilePictureViewSize = Values.mediumProfilePictureSize
|
|
||||||
profilePictureView.set(.width, to: profilePictureViewSize)
|
|
||||||
profilePictureView.set(.height, to: profilePictureViewSize)
|
|
||||||
profilePictureView.size = profilePictureViewSize
|
|
||||||
|
|
||||||
// Unread count view
|
// Unread count view
|
||||||
unreadCountView.addSubview(unreadCountLabel)
|
unreadCountView.addSubview(unreadCountLabel)
|
||||||
unreadCountLabel.setCompressionResistanceHigh()
|
unreadCountLabel.setCompressionResistanceHigh()
|
||||||
|
@ -640,7 +634,7 @@ public final class FullConversationCell: UITableViewCell {
|
||||||
// This method determines if the content is probably too long and returns the truncated or untruncated
|
// This method determines if the content is probably too long and returns the truncated or untruncated
|
||||||
// content accordingly
|
// content accordingly
|
||||||
func truncatingIfNeeded(approxWidth: CGFloat, content: NSAttributedString) -> NSAttributedString {
|
func truncatingIfNeeded(approxWidth: CGFloat, content: NSAttributedString) -> NSAttributedString {
|
||||||
let approxFullWidth: CGFloat = (approxWidth + profilePictureView.size + (Values.mediumSpacing * 3))
|
let approxFullWidth: CGFloat = (approxWidth + profilePictureView.size.viewSize + (Values.mediumSpacing * 3))
|
||||||
|
|
||||||
guard ((bounds.width - approxFullWidth) < 0) else { return content }
|
guard ((bounds.width - approxFullWidth) < 0) else { return content }
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,10 @@ class SessionAvatarCell: UITableViewCell {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fileprivate let profilePictureView: ProfilePictureView = {
|
fileprivate let profilePictureView: ProfilePictureView = {
|
||||||
let view: ProfilePictureView = ProfilePictureView()
|
let view: ProfilePictureView = ProfilePictureView(size: .hero)
|
||||||
view.accessibilityLabel = "Profile picture"
|
view.accessibilityLabel = "Profile picture"
|
||||||
view.isAccessibilityElement = true
|
view.isAccessibilityElement = true
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.size = Values.largeProfilePictureSize
|
|
||||||
|
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
@ -148,9 +147,6 @@ class SessionAvatarCell: UITableViewCell {
|
||||||
private func setupLayout() {
|
private func setupLayout() {
|
||||||
stackView.pin(to: contentView)
|
stackView.pin(to: contentView)
|
||||||
|
|
||||||
profilePictureView.set(.width, to: profilePictureView.size)
|
|
||||||
profilePictureView.set(.height, to: profilePictureView.size)
|
|
||||||
|
|
||||||
displayNameLabel.pin(to: displayNameContainer)
|
displayNameLabel.pin(to: displayNameContainer)
|
||||||
displayNameTextField.center(in: displayNameContainer)
|
displayNameTextField.center(in: displayNameContainer)
|
||||||
displayNameTextField.widthAnchor
|
displayNameTextField.widthAnchor
|
||||||
|
|
|
@ -141,12 +141,8 @@ extension SessionCell {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = {
|
private lazy var profilePictureView: ProfilePictureView = {
|
||||||
let result: ProfilePictureView = ProfilePictureView()
|
let result: ProfilePictureView = ProfilePictureView(size: .list)
|
||||||
result.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
result.size = Values.smallProfilePictureSize
|
|
||||||
result.isHidden = true
|
result.isHidden = true
|
||||||
result.set(.width, to: Values.smallProfilePictureSize)
|
|
||||||
result.set(.height, to: Values.smallProfilePictureSize)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -39,7 +39,7 @@ final class SimplifiedConversationCell: UITableViewCell {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var profilePictureView: ProfilePictureView = {
|
private lazy var profilePictureView: ProfilePictureView = {
|
||||||
let view: ProfilePictureView = ProfilePictureView()
|
let view: ProfilePictureView = ProfilePictureView(size: .list)
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
@ -79,10 +79,6 @@ final class SimplifiedConversationCell: UITableViewCell {
|
||||||
accentLineView.set(.width, to: Values.accentLineThickness)
|
accentLineView.set(.width, to: Values.accentLineThickness)
|
||||||
accentLineView.set(.height, to: 68)
|
accentLineView.set(.height, to: 68)
|
||||||
|
|
||||||
profilePictureView.set(.width, to: Values.mediumProfilePictureSize)
|
|
||||||
profilePictureView.set(.height, to: Values.mediumProfilePictureSize)
|
|
||||||
profilePictureView.size = Values.mediumProfilePictureSize
|
|
||||||
|
|
||||||
stackView.pin(to: self)
|
stackView.pin(to: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,11 @@ internal enum Theme_ClassicDark: ThemeColors {
|
||||||
.reactions_contextMoreBackground: .classicDark1,
|
.reactions_contextMoreBackground: .classicDark1,
|
||||||
|
|
||||||
// NewConversation
|
// NewConversation
|
||||||
.newConversation_background: .classicDark1
|
.newConversation_background: .classicDark1,
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
.profileIcon: .primary,
|
||||||
|
.profileIcon_greenPrimaryColor: .black,
|
||||||
|
.profileIcon_background: .white
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,11 @@ internal enum Theme_ClassicLight: ThemeColors {
|
||||||
.reactions_contextMoreBackground: .classicLight6,
|
.reactions_contextMoreBackground: .classicLight6,
|
||||||
|
|
||||||
// NewConversation
|
// NewConversation
|
||||||
.newConversation_background: .classicLight6
|
.newConversation_background: .classicLight6,
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
.profileIcon: .primary,
|
||||||
|
.profileIcon_greenPrimaryColor: .primary,
|
||||||
|
.profileIcon_background: .black
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,11 @@ internal enum Theme_OceanDark: ThemeColors {
|
||||||
.reactions_contextMoreBackground: .oceanDark2,
|
.reactions_contextMoreBackground: .oceanDark2,
|
||||||
|
|
||||||
// NewConversation
|
// NewConversation
|
||||||
.newConversation_background: .oceanDark3
|
.newConversation_background: .oceanDark3,
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
.profileIcon: .primary,
|
||||||
|
.profileIcon_greenPrimaryColor: .black,
|
||||||
|
.profileIcon_background: .white
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,11 @@ internal enum Theme_OceanLight: ThemeColors {
|
||||||
.reactions_contextMoreBackground: .oceanLight6,
|
.reactions_contextMoreBackground: .oceanLight6,
|
||||||
|
|
||||||
// NewConversation
|
// NewConversation
|
||||||
.newConversation_background: .oceanLight7
|
.newConversation_background: .oceanLight7,
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
.profileIcon: .primary,
|
||||||
|
.profileIcon_greenPrimaryColor: .primary,
|
||||||
|
.profileIcon_background: .oceanLight1
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,11 @@ public indirect enum ThemeValue: Hashable {
|
||||||
|
|
||||||
// NewConversation
|
// NewConversation
|
||||||
case newConversation_background
|
case newConversation_background
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
case profileIcon
|
||||||
|
case profileIcon_greenPrimaryColor
|
||||||
|
case profileIcon_background
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ForcedThemeValue
|
// MARK: - ForcedThemeValue
|
||||||
|
|
|
@ -25,11 +25,6 @@ public final class Values : NSObject {
|
||||||
|
|
||||||
@objc public static let accentLineThickness = CGFloat(4)
|
@objc public static let accentLineThickness = CGFloat(4)
|
||||||
|
|
||||||
@objc public static let verySmallProfilePictureSize = CGFloat(26)
|
|
||||||
@objc public static let smallProfilePictureSize = CGFloat(33)
|
|
||||||
@objc public static let mediumProfilePictureSize = CGFloat(45)
|
|
||||||
@objc public static let largeProfilePictureSize = CGFloat(75)
|
|
||||||
|
|
||||||
@objc public static let searchBarHeight = CGFloat(36)
|
@objc public static let searchBarHeight = CGFloat(36)
|
||||||
|
|
||||||
@objc public static var separatorThickness: CGFloat { return 1 / UIScreen.main.scale }
|
@objc public static var separatorThickness: CGFloat { return 1 / UIScreen.main.scale }
|
||||||
|
|
|
@ -7,14 +7,107 @@ import SessionUIKit
|
||||||
import SessionMessagingKit
|
import SessionMessagingKit
|
||||||
|
|
||||||
public final class ProfilePictureView: UIView {
|
public final class ProfilePictureView: UIView {
|
||||||
private var hasTappableProfilePicture: Bool = false
|
public enum Size {
|
||||||
public var size: CGFloat = 0
|
case navigation
|
||||||
|
case message
|
||||||
|
case list
|
||||||
|
case hero
|
||||||
|
|
||||||
// Constraints
|
public var viewSize: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .navigation, .message: return 26
|
||||||
|
case .list: return 46
|
||||||
|
case .hero: return 110
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageSize: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .navigation, .message: return 26
|
||||||
|
case .list: return 46
|
||||||
|
case .hero: return 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var multiImageSize: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .navigation, .message: return 18 // Shouldn't be used
|
||||||
|
case .list: return 32
|
||||||
|
case .hero: return 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconSize: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .navigation, .message: return 8
|
||||||
|
case .list: return 16
|
||||||
|
case .hero: return 24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconVerticalInset: CGFloat {
|
||||||
|
switch self {
|
||||||
|
case .navigation, .message: return 1
|
||||||
|
case .list: return 3
|
||||||
|
case .hero: return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ProfileIcon {
|
||||||
|
case none
|
||||||
|
case crown
|
||||||
|
case rightPlus
|
||||||
|
}
|
||||||
|
|
||||||
|
public var size: Size {
|
||||||
|
didSet {
|
||||||
|
widthConstraint.constant = (customWidth ?? size.viewSize)
|
||||||
|
heightConstraint.constant = size.viewSize
|
||||||
|
profileIconTopConstraint.constant = size.iconVerticalInset
|
||||||
|
profileIconBottomConstraint.constant = -size.iconVerticalInset
|
||||||
|
profileIconBackgroundWidthConstraint.constant = size.iconSize
|
||||||
|
profileIconBackgroundHeightConstraint.constant = size.iconSize
|
||||||
|
additionalProfileIconTopConstraint.constant = size.iconVerticalInset
|
||||||
|
additionalProfileIconBottomConstraint.constant = -size.iconVerticalInset
|
||||||
|
additionalProfileIconBackgroundWidthConstraint.constant = size.iconSize
|
||||||
|
additionalProfileIconBackgroundHeightConstraint.constant = size.iconSize
|
||||||
|
|
||||||
|
profileIconBackgroundView.layer.cornerRadius = (size.iconSize / 2)
|
||||||
|
additionalProfileIconBackgroundView.layer.cornerRadius = (size.iconSize / 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public var customWidth: CGFloat? {
|
||||||
|
didSet {
|
||||||
|
self.widthConstraint.constant = (customWidth ?? self.size.viewSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var hasTappableProfilePicture: Bool = false
|
||||||
|
|
||||||
|
// MARK: - Constraints
|
||||||
|
|
||||||
|
private var widthConstraint: NSLayoutConstraint!
|
||||||
|
private var heightConstraint: NSLayoutConstraint!
|
||||||
|
private var imageViewTopConstraint: NSLayoutConstraint!
|
||||||
|
private var imageViewLeadingConstraint: NSLayoutConstraint!
|
||||||
|
private var imageViewCenterXConstraint: NSLayoutConstraint!
|
||||||
|
private var imageViewCenterYConstraint: NSLayoutConstraint!
|
||||||
private var imageViewWidthConstraint: NSLayoutConstraint!
|
private var imageViewWidthConstraint: NSLayoutConstraint!
|
||||||
private var imageViewHeightConstraint: NSLayoutConstraint!
|
private var imageViewHeightConstraint: NSLayoutConstraint!
|
||||||
private var additionalImageViewWidthConstraint: NSLayoutConstraint!
|
private var additionalImageViewWidthConstraint: NSLayoutConstraint!
|
||||||
private var additionalImageViewHeightConstraint: NSLayoutConstraint!
|
private var additionalImageViewHeightConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconTopConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconBottomConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconBackgroundLeftAlignConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconBackgroundRightAlignConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconBackgroundWidthConstraint: NSLayoutConstraint!
|
||||||
|
private var profileIconBackgroundHeightConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconTopConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconBottomConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconBackgroundLeftAlignConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconBackgroundRightAlignConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconBackgroundWidthConstraint: NSLayoutConstraint!
|
||||||
|
private var additionalProfileIconBackgroundHeightConstraint: NSLayoutConstraint!
|
||||||
|
|
||||||
// MARK: - Components
|
// MARK: - Components
|
||||||
|
|
||||||
|
@ -51,7 +144,6 @@ public final class ProfilePictureView: UIView {
|
||||||
result.clipsToBounds = true
|
result.clipsToBounds = true
|
||||||
result.themeBackgroundColor = .primary
|
result.themeBackgroundColor = .primary
|
||||||
result.themeBorderColor = .backgroundPrimary
|
result.themeBorderColor = .backgroundPrimary
|
||||||
result.layer.cornerRadius = (Values.smallProfilePictureSize / 2)
|
|
||||||
result.isHidden = true
|
result.isHidden = true
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -88,33 +180,72 @@ public final class ProfilePictureView: UIView {
|
||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var profileIconBackgroundView: UIView = {
|
||||||
|
let result: UIView = UIView()
|
||||||
|
result.isHidden = true
|
||||||
|
|
||||||
|
return result
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var profileIconImageView: UIImageView = {
|
||||||
|
let result: UIImageView = UIImageView()
|
||||||
|
result.contentMode = .scaleAspectFit
|
||||||
|
|
||||||
|
return result
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var additionalProfileIconBackgroundView: UIView = {
|
||||||
|
let result: UIView = UIView()
|
||||||
|
result.isHidden = true
|
||||||
|
|
||||||
|
return result
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var additionalProfileIconImageView: UIImageView = {
|
||||||
|
let result: UIImageView = UIImageView()
|
||||||
|
result.contentMode = .scaleAspectFit
|
||||||
|
|
||||||
|
return result
|
||||||
|
}()
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
public init(size: Size) {
|
||||||
super.init(frame: frame)
|
self.size = size
|
||||||
|
|
||||||
|
super.init(frame: CGRect(x: 0, y: 0, width: size.viewSize, height: size.viewSize))
|
||||||
|
|
||||||
setUpViewHierarchy()
|
setUpViewHierarchy()
|
||||||
}
|
}
|
||||||
|
|
||||||
public required init?(coder: NSCoder) {
|
public required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
preconditionFailure("Use init(size:) instead.")
|
||||||
setUpViewHierarchy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setUpViewHierarchy() {
|
private func setUpViewHierarchy() {
|
||||||
let imageViewSize = CGFloat(Values.mediumProfilePictureSize)
|
|
||||||
let additionalImageViewSize = CGFloat(Values.smallProfilePictureSize)
|
|
||||||
|
|
||||||
addSubview(imageContainerView)
|
addSubview(imageContainerView)
|
||||||
|
addSubview(profileIconBackgroundView)
|
||||||
addSubview(additionalImageContainerView)
|
addSubview(additionalImageContainerView)
|
||||||
|
addSubview(additionalProfileIconBackgroundView)
|
||||||
|
|
||||||
imageContainerView.pin(.leading, to: .leading, of: self)
|
profileIconBackgroundView.addSubview(profileIconImageView)
|
||||||
imageContainerView.pin(.top, to: .top, of: self)
|
additionalProfileIconBackgroundView.addSubview(additionalProfileIconImageView)
|
||||||
imageViewWidthConstraint = imageContainerView.set(.width, to: imageViewSize)
|
|
||||||
imageViewHeightConstraint = imageContainerView.set(.height, to: imageViewSize)
|
widthConstraint = self.set(.width, to: self.size.viewSize)
|
||||||
|
heightConstraint = self.set(.height, to: self.size.viewSize)
|
||||||
|
|
||||||
|
imageViewTopConstraint = imageContainerView.pin(.top, to: .top, of: self)
|
||||||
|
imageViewLeadingConstraint = imageContainerView.pin(.leading, to: .leading, of: self)
|
||||||
|
imageViewCenterXConstraint = imageContainerView.center(.horizontal, in: self)
|
||||||
|
imageViewCenterXConstraint.isActive = false
|
||||||
|
imageViewCenterYConstraint = imageContainerView.center(.vertical, in: self)
|
||||||
|
imageViewCenterYConstraint.isActive = false
|
||||||
|
imageViewWidthConstraint = imageContainerView.set(.width, to: size.imageSize)
|
||||||
|
imageViewHeightConstraint = imageContainerView.set(.height, to: size.imageSize)
|
||||||
additionalImageContainerView.pin(.trailing, to: .trailing, of: self)
|
additionalImageContainerView.pin(.trailing, to: .trailing, of: self)
|
||||||
additionalImageContainerView.pin(.bottom, to: .bottom, of: self)
|
additionalImageContainerView.pin(.bottom, to: .bottom, of: self)
|
||||||
additionalImageViewWidthConstraint = additionalImageContainerView.set(.width, to: additionalImageViewSize)
|
additionalImageViewWidthConstraint = additionalImageContainerView.set(.width, to: size.multiImageSize)
|
||||||
additionalImageViewHeightConstraint = additionalImageContainerView.set(.height, to: additionalImageViewSize)
|
additionalImageViewHeightConstraint = additionalImageContainerView.set(.height, to: size.multiImageSize)
|
||||||
|
|
||||||
imageContainerView.addSubview(imageView)
|
imageContainerView.addSubview(imageView)
|
||||||
imageContainerView.addSubview(animatedImageView)
|
imageContainerView.addSubview(animatedImageView)
|
||||||
|
@ -131,32 +262,137 @@ public final class ProfilePictureView: UIView {
|
||||||
additionalProfilePlaceholderImageView.pin(.left, to: .left, of: additionalImageContainerView)
|
additionalProfilePlaceholderImageView.pin(.left, to: .left, of: additionalImageContainerView)
|
||||||
additionalProfilePlaceholderImageView.pin(.right, to: .right, of: additionalImageContainerView)
|
additionalProfilePlaceholderImageView.pin(.right, to: .right, of: additionalImageContainerView)
|
||||||
additionalProfilePlaceholderImageView.pin(.bottom, to: .bottom, of: additionalImageContainerView, withInset: 5)
|
additionalProfilePlaceholderImageView.pin(.bottom, to: .bottom, of: additionalImageContainerView, withInset: 5)
|
||||||
|
|
||||||
|
profileIconTopConstraint = profileIconImageView.pin(
|
||||||
|
.top,
|
||||||
|
to: .top,
|
||||||
|
of: profileIconBackgroundView,
|
||||||
|
withInset: size.iconVerticalInset
|
||||||
|
)
|
||||||
|
profileIconImageView.pin(.left, to: .left, of: profileIconBackgroundView)
|
||||||
|
profileIconImageView.pin(.right, to: .right, of: profileIconBackgroundView)
|
||||||
|
profileIconBottomConstraint = profileIconImageView.pin(
|
||||||
|
.bottom,
|
||||||
|
to: .bottom,
|
||||||
|
of: profileIconBackgroundView,
|
||||||
|
withInset: -size.iconVerticalInset
|
||||||
|
)
|
||||||
|
profileIconBackgroundLeftAlignConstraint = profileIconBackgroundView.pin(.leading, to: .leading, of: imageContainerView)
|
||||||
|
profileIconBackgroundRightAlignConstraint = profileIconBackgroundView.pin(.trailing, to: .trailing, of: imageContainerView)
|
||||||
|
profileIconBackgroundView.pin(.bottom, to: .bottom, of: imageContainerView)
|
||||||
|
profileIconBackgroundWidthConstraint = profileIconBackgroundView.set(.width, to: size.iconSize)
|
||||||
|
profileIconBackgroundHeightConstraint = profileIconBackgroundView.set(.height, to: size.iconSize)
|
||||||
|
profileIconBackgroundLeftAlignConstraint.isActive = false
|
||||||
|
profileIconBackgroundRightAlignConstraint.isActive = false
|
||||||
|
|
||||||
|
additionalProfileIconTopConstraint = additionalProfileIconImageView.pin(
|
||||||
|
.top,
|
||||||
|
to: .top,
|
||||||
|
of: additionalProfileIconBackgroundView,
|
||||||
|
withInset: size.iconVerticalInset
|
||||||
|
)
|
||||||
|
additionalProfileIconImageView.pin(.left, to: .left, of: additionalProfileIconBackgroundView)
|
||||||
|
additionalProfileIconImageView.pin(.right, to: .right, of: additionalProfileIconBackgroundView)
|
||||||
|
additionalProfileIconBottomConstraint = additionalProfileIconImageView.pin(
|
||||||
|
.bottom,
|
||||||
|
to: .bottom,
|
||||||
|
of: additionalProfileIconBackgroundView,
|
||||||
|
withInset: -size.iconVerticalInset
|
||||||
|
)
|
||||||
|
additionalProfileIconBackgroundLeftAlignConstraint = additionalProfileIconBackgroundView.pin(.leading, to: .leading, of: additionalImageContainerView)
|
||||||
|
additionalProfileIconBackgroundRightAlignConstraint = additionalProfileIconBackgroundView.pin(.trailing, to: .trailing, of: additionalImageContainerView)
|
||||||
|
additionalProfileIconBackgroundView.pin(.bottom, to: .bottom, of: additionalImageContainerView)
|
||||||
|
additionalProfileIconBackgroundWidthConstraint = additionalProfileIconBackgroundView.set(.width, to: size.iconSize)
|
||||||
|
additionalProfileIconBackgroundHeightConstraint = additionalProfileIconBackgroundView.set(.height, to: size.iconSize)
|
||||||
|
additionalProfileIconBackgroundLeftAlignConstraint.isActive = false
|
||||||
|
additionalProfileIconBackgroundRightAlignConstraint.isActive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Content
|
||||||
|
|
||||||
|
private func updateIconView(
|
||||||
|
icon: ProfileIcon,
|
||||||
|
imageView: UIImageView,
|
||||||
|
backgroundView: UIView,
|
||||||
|
leftAlignConstraint: NSLayoutConstraint,
|
||||||
|
rightAlignConstraint: NSLayoutConstraint
|
||||||
|
) {
|
||||||
|
backgroundView.isHidden = (icon == .none)
|
||||||
|
leftAlignConstraint.isActive = (
|
||||||
|
icon == .none ||
|
||||||
|
icon == .crown
|
||||||
|
)
|
||||||
|
rightAlignConstraint.isActive = (
|
||||||
|
icon == .rightPlus
|
||||||
|
)
|
||||||
|
|
||||||
|
switch icon {
|
||||||
|
case .none: imageView.image = nil
|
||||||
|
|
||||||
|
case .crown:
|
||||||
|
imageView.image = UIImage(systemName: "crown.fill")
|
||||||
|
backgroundView.themeBackgroundColor = .profileIcon_background
|
||||||
|
|
||||||
|
ThemeManager.onThemeChange(observer: imageView) { [weak imageView] _, primaryColor in
|
||||||
|
let targetColor: ThemeValue = (primaryColor == .green ?
|
||||||
|
.profileIcon_greenPrimaryColor :
|
||||||
|
.profileIcon
|
||||||
|
)
|
||||||
|
|
||||||
|
guard imageView?.themeTintColor != targetColor else { return }
|
||||||
|
|
||||||
|
imageView?.themeTintColor = targetColor
|
||||||
|
}
|
||||||
|
|
||||||
|
case .rightPlus:
|
||||||
|
imageView.image = UIImage(systemName: "plus")
|
||||||
|
imageView.themeTintColor = .black
|
||||||
|
backgroundView.themeBackgroundColor = .primary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(
|
public func update(
|
||||||
publicKey: String = "",
|
publicKey: String = "",
|
||||||
profile: Profile? = nil,
|
profile: Profile? = nil,
|
||||||
|
icon: ProfileIcon = .none,
|
||||||
additionalProfile: Profile? = nil,
|
additionalProfile: Profile? = nil,
|
||||||
|
additionalIcon: ProfileIcon = .none,
|
||||||
threadVariant: SessionThread.Variant,
|
threadVariant: SessionThread.Variant,
|
||||||
openGroupProfilePictureData: Data? = nil,
|
openGroupProfilePictureData: Data? = nil,
|
||||||
useFallbackPicture: Bool = false,
|
useFallbackPicture: Bool = false,
|
||||||
showMultiAvatarForClosedGroup: Bool = false
|
showMultiAvatarForClosedGroup: Bool = false
|
||||||
) {
|
) {
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
|
// Sort out the profile icon first
|
||||||
|
updateIconView(
|
||||||
|
icon: icon,
|
||||||
|
imageView: profileIconImageView,
|
||||||
|
backgroundView: profileIconBackgroundView,
|
||||||
|
leftAlignConstraint: profileIconBackgroundLeftAlignConstraint,
|
||||||
|
rightAlignConstraint: profileIconBackgroundRightAlignConstraint
|
||||||
|
)
|
||||||
|
|
||||||
guard !useFallbackPicture else {
|
guard !useFallbackPicture else {
|
||||||
switch self.size {
|
switch self.size {
|
||||||
case Values.smallProfilePictureSize..<Values.mediumProfilePictureSize: imageView.image = #imageLiteral(resourceName: "SessionWhite16")
|
case .navigation, .message: imageView.image = #imageLiteral(resourceName: "SessionWhite16")
|
||||||
case Values.mediumProfilePictureSize..<Values.largeProfilePictureSize: imageView.image = #imageLiteral(resourceName: "SessionWhite24")
|
case .list: imageView.image = #imageLiteral(resourceName: "SessionWhite24")
|
||||||
default: imageView.image = #imageLiteral(resourceName: "SessionWhite40")
|
case .hero: imageView.image = #imageLiteral(resourceName: "SessionWhite40")
|
||||||
}
|
}
|
||||||
|
|
||||||
imageView.contentMode = .center
|
imageView.contentMode = .center
|
||||||
imageView.isHidden = false
|
imageView.isHidden = false
|
||||||
animatedImageView.isHidden = true
|
animatedImageView.isHidden = true
|
||||||
imageContainerView.themeBackgroundColorForced = .theme(.classicDark, color: .borderSeparator)
|
imageContainerView.themeBackgroundColorForced = .theme(.classicDark, color: .borderSeparator)
|
||||||
imageContainerView.layer.cornerRadius = (self.size / 2)
|
imageContainerView.layer.cornerRadius = (self.size.imageSize / 2)
|
||||||
imageViewWidthConstraint.constant = self.size
|
imageViewWidthConstraint.constant = self.size.imageSize
|
||||||
imageViewHeightConstraint.constant = self.size
|
imageViewHeightConstraint.constant = self.size.imageSize
|
||||||
|
profileIconBackgroundWidthConstraint.constant = self.size.iconSize
|
||||||
|
profileIconBackgroundHeightConstraint.constant = self.size.iconSize
|
||||||
|
profileIconBackgroundView.layer.cornerRadius = (self.size.iconSize / 2)
|
||||||
|
additionalProfileIconBackgroundWidthConstraint.constant = self.size.iconSize
|
||||||
|
additionalProfileIconBackgroundHeightConstraint.constant = self.size.iconSize
|
||||||
|
additionalProfileIconBackgroundView.layer.cornerRadius = (self.size.iconSize / 2)
|
||||||
additionalImageContainerView.isHidden = true
|
additionalImageContainerView.isHidden = true
|
||||||
animatedImageView.image = nil
|
animatedImageView.image = nil
|
||||||
additionalImageView.image = nil
|
additionalImageView.image = nil
|
||||||
|
@ -203,25 +439,25 @@ public final class ProfilePictureView: UIView {
|
||||||
|
|
||||||
switch (threadVariant, showMultiAvatarForClosedGroup) {
|
switch (threadVariant, showMultiAvatarForClosedGroup) {
|
||||||
case (.closedGroup, true):
|
case (.closedGroup, true):
|
||||||
if self.size == 40 {
|
targetSize = self.size.multiImageSize
|
||||||
targetSize = 32
|
|
||||||
}
|
|
||||||
else if self.size == Values.largeProfilePictureSize {
|
|
||||||
targetSize = 56
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
targetSize = Values.smallProfilePictureSize
|
|
||||||
}
|
|
||||||
|
|
||||||
imageViewWidthConstraint.constant = targetSize
|
|
||||||
imageViewHeightConstraint.constant = targetSize
|
|
||||||
additionalImageViewWidthConstraint.constant = targetSize
|
|
||||||
additionalImageViewHeightConstraint.constant = targetSize
|
|
||||||
additionalImageContainerView.isHidden = false
|
additionalImageContainerView.isHidden = false
|
||||||
|
imageViewTopConstraint.isActive = true
|
||||||
|
imageViewLeadingConstraint.isActive = true
|
||||||
|
imageViewCenterXConstraint.isActive = false
|
||||||
|
imageViewCenterYConstraint.isActive = false
|
||||||
|
|
||||||
|
// Sort out the additinoal profile icon if needed
|
||||||
|
updateIconView(
|
||||||
|
icon: additionalIcon,
|
||||||
|
imageView: additionalProfileIconImageView,
|
||||||
|
backgroundView: additionalProfileIconBackgroundView,
|
||||||
|
leftAlignConstraint: additionalProfileIconBackgroundLeftAlignConstraint,
|
||||||
|
rightAlignConstraint: additionalProfileIconBackgroundRightAlignConstraint
|
||||||
|
)
|
||||||
|
|
||||||
if let additionalProfile: Profile = additionalProfile {
|
if let additionalProfile: Profile = additionalProfile {
|
||||||
let (image, animatedImage, _): (UIImage?, YYImage?, Bool) = getProfilePicture(
|
let (image, animatedImage, _): (UIImage?, YYImage?, Bool) = getProfilePicture(
|
||||||
of: targetSize,
|
of: self.size.multiImageSize,
|
||||||
for: additionalProfile.id,
|
for: additionalProfile.id,
|
||||||
profile: additionalProfile
|
profile: additionalProfile
|
||||||
)
|
)
|
||||||
|
@ -241,15 +477,19 @@ public final class ProfilePictureView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
targetSize = self.size
|
targetSize = self.size.imageSize
|
||||||
imageViewWidthConstraint.constant = targetSize
|
|
||||||
imageViewHeightConstraint.constant = targetSize
|
|
||||||
additionalImageContainerView.isHidden = true
|
additionalImageContainerView.isHidden = true
|
||||||
|
additionalProfileIconBackgroundView.isHidden = true
|
||||||
additionalImageView.image = nil
|
additionalImageView.image = nil
|
||||||
additionalImageView.isHidden = true
|
additionalImageView.isHidden = true
|
||||||
additionalAnimatedImageView.image = nil
|
additionalAnimatedImageView.image = nil
|
||||||
additionalAnimatedImageView.isHidden = true
|
additionalAnimatedImageView.isHidden = true
|
||||||
additionalProfilePlaceholderImageView.isHidden = true
|
additionalProfilePlaceholderImageView.isHidden = true
|
||||||
|
imageViewTopConstraint.isActive = false
|
||||||
|
imageViewLeadingConstraint.isActive = false
|
||||||
|
imageViewCenterXConstraint.isActive = true
|
||||||
|
imageViewCenterYConstraint.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the image
|
// Set the image
|
||||||
|
@ -287,8 +527,14 @@ public final class ProfilePictureView: UIView {
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
animatedImageView.contentMode = .scaleAspectFill
|
animatedImageView.contentMode = .scaleAspectFill
|
||||||
imageContainerView.themeBackgroundColor = .backgroundSecondary
|
imageContainerView.themeBackgroundColor = .backgroundSecondary
|
||||||
|
imageViewWidthConstraint.constant = targetSize
|
||||||
|
imageViewHeightConstraint.constant = targetSize
|
||||||
imageContainerView.layer.cornerRadius = (targetSize / 2)
|
imageContainerView.layer.cornerRadius = (targetSize / 2)
|
||||||
|
additionalImageViewWidthConstraint.constant = targetSize
|
||||||
|
additionalImageViewHeightConstraint.constant = targetSize
|
||||||
additionalImageContainerView.layer.cornerRadius = (targetSize / 2)
|
additionalImageContainerView.layer.cornerRadius = (targetSize / 2)
|
||||||
|
profileIconBackgroundView.layer.cornerRadius = (size.iconSize / 2)
|
||||||
|
additionalProfileIconBackgroundView.layer.cornerRadius = (size.iconSize / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Convenience
|
// MARK: - Convenience
|
||||||
|
|
Loading…
Reference in New Issue