Merge branch 'charlesmchen/converationColorsGroupAvatars'

pull/1/head
Matthew Chen 7 years ago
commit 5471e1ba9a

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "group-avi.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

File diff suppressed because one or more lines are too long

@ -2,15 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "empty-group-avatar.png", "filename" : "group-28-white@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "group-28-white@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "group-28-white@3x.png",
"scale" : "3x" "scale" : "3x"
} }
], ],

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -280,7 +280,6 @@
cell.contentView.preservesSuperviewLayoutMargins = YES; cell.contentView.preservesSuperviewLayoutMargins = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
const NSUInteger kAvatarSize = 68;
// TODO: Replace this icon. // TODO: Replace this icon.
UIImage *_Nullable localProfileAvatarImage = [OWSProfileManager.sharedManager localProfileAvatarImage]; UIImage *_Nullable localProfileAvatarImage = [OWSProfileManager.sharedManager localProfileAvatarImage];
UIImage *avatarImage = (localProfileAvatarImage UIImage *avatarImage = (localProfileAvatarImage
@ -295,8 +294,8 @@
[cell.contentView addSubview:avatarView]; [cell.contentView addSubview:avatarView];
[avatarView autoVCenterInSuperview]; [avatarView autoVCenterInSuperview];
[avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoPinLeadingToSuperviewMargin];
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize];
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize];
if (!localProfileAvatarImage) { if (!localProfileAvatarImage) {
UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"]; UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"];

@ -117,7 +117,14 @@ NS_ASSUME_NONNULL_BEGIN
@"BLOCK_LIST_BLOCKED_GROUPS_SECTION", @"Section header for groups that have been blocked"); @"BLOCK_LIST_BLOCKED_GROUPS_SECTION", @"Section header for groups that have been blocked");
for (TSGroupModel *blockedGroup in blockedGroups) { for (TSGroupModel *blockedGroup in blockedGroups) {
UIImage *image = blockedGroup.groupImage ?: OWSGroupAvatarBuilder.defaultGroupImage; UIImage *_Nullable image = blockedGroup.groupImage;
if (!image) {
NSString *conversationColorName =
[TSGroupThread defaultConversationColorNameForGroupId:blockedGroup.groupId];
image = [OWSGroupAvatarBuilder defaultAvatarForGroupId:blockedGroup.groupId
conversationColorName:conversationColorName
diameter:kStandardAvatarSize];
}
NSString *groupName NSString *groupName
= blockedGroup.groupName.length > 0 ? blockedGroup.groupName : TSGroupThread.defaultGroupName; = blockedGroup.groupName.length > 0 ? blockedGroup.groupName : TSGroupThread.defaultGroupName;

@ -449,7 +449,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
} }
func updateAvatarImage() { func updateAvatarImage() {
contactAvatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: 400, contactsManager: contactsManager) contactAvatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: 400)
} }
func createIncomingCallControls() { func createIncomingCallControls() {

@ -164,7 +164,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (CGFloat)iconSize + (CGFloat)iconSize
{ {
return 48.f; return kStandardAvatarSize;
} }
- (CGFloat)iconSize - (CGFloat)iconSize

@ -77,7 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (CGFloat)iconSize + (CGFloat)iconSize
{ {
return 48.f; return kStandardAvatarSize;
} }
- (CGFloat)iconSize - (CGFloat)iconSize

@ -82,7 +82,7 @@ NS_ASSUME_NONNULL_BEGIN
- (CGFloat)iconHeight - (CGFloat)iconHeight
{ {
return 48.f; return kStandardAvatarSize;
} }
- (void)createContentsWithConversationStyle:(ConversationStyle *)conversationStyle - (void)createContentsWithConversationStyle:(ConversationStyle *)conversationStyle

@ -262,18 +262,11 @@ NS_ASSUME_NONNULL_BEGIN
return NO; return NO;
} }
OWSContactsManager *contactsManager = self.delegate.contactsManager;
if (contactsManager == nil) {
OWSFailDebug(@"contactsManager should not be nil");
return NO;
}
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.viewItem.interaction; TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.viewItem.interaction;
UIImage *_Nullable authorAvatarImage = UIImage *_Nullable authorAvatarImage =
[[[OWSContactAvatarBuilder alloc] initWithSignalId:incomingMessage.authorId [[[OWSContactAvatarBuilder alloc] initWithSignalId:incomingMessage.authorId
colorName:self.viewItem.authorConversationColorName colorName:self.viewItem.authorConversationColorName
diameter:self.avatarSize diameter:self.avatarSize] build];
contactsManager:contactsManager] build];
self.avatarView.image = authorAvatarImage; self.avatarView.image = authorAvatarImage;
[self.contentView addSubview:self.avatarView]; [self.contentView addSubview:self.avatarView];

@ -334,9 +334,7 @@ NS_ASSUME_NONNULL_BEGIN
return; return;
} }
self.avatarView.image = [OWSAvatarBuilder buildImageForThread:thread.threadRecord self.avatarView.image = [OWSAvatarBuilder buildImageForThread:thread.threadRecord diameter:self.avatarSize];
diameter:self.avatarSize
contactsManager:contactsManager];
} }
- (NSAttributedString *)attributedSnippetForThread:(ThreadViewModel *)thread isBlocked:(BOOL)isBlocked - (NSAttributedString *)attributedSnippetForThread:(ThreadViewModel *)thread isBlocked:(BOOL)isBlocked
@ -427,7 +425,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSUInteger)avatarSize - (NSUInteger)avatarSize
{ {
return 48.f; return kStandardAvatarSize;
} }
- (NSUInteger)avatarHSpacing - (NSUInteger)avatarHSpacing

@ -29,8 +29,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
@interface NewGroupViewController () <UIImagePickerControllerDelegate, @interface NewGroupViewController () <UIImagePickerControllerDelegate,
UITextFieldDelegate, UITextFieldDelegate,
ContactsViewHelperDelegate, ContactsViewHelperDelegate,
@ -48,6 +46,8 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
@property (nonatomic, readonly) AvatarImageView *avatarView; @property (nonatomic, readonly) AvatarImageView *avatarView;
@property (nonatomic, readonly) UITextField *groupNameTextField; @property (nonatomic, readonly) UITextField *groupNameTextField;
@property (nonatomic, readonly) NSData *groupId;
@property (nonatomic, nullable) UIImage *groupAvatar; @property (nonatomic, nullable) UIImage *groupAvatar;
@property (nonatomic) NSMutableSet<NSString *> *memberRecipientIds; @property (nonatomic) NSMutableSet<NSString *> *memberRecipientIds;
@ -86,6 +86,8 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
- (void)commonInit - (void)commonInit
{ {
_groupId = [Randomness generateRandomBytes:16];
_messageSender = SSKEnvironment.shared.messageSender; _messageSender = SSKEnvironment.shared.messageSender;
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self]; _contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];
_avatarViewHelper = [AvatarViewHelper new]; _avatarViewHelper = [AvatarViewHelper new];
@ -151,8 +153,8 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
[threadInfoView addSubview:avatarView]; [threadInfoView addSubview:avatarView];
[avatarView autoVCenterInSuperview]; [avatarView autoVCenterInSuperview];
[avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoPinLeadingToSuperviewMargin];
[avatarView autoSetDimension:ALDimensionWidth toSize:kNewGroupViewControllerAvatarWidth]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize];
[avatarView autoSetDimension:ALDimensionHeight toSize:kNewGroupViewControllerAvatarWidth]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize];
[self updateAvatarView]; [self updateAvatarView];
UITextField *groupNameTextField = [OWSTextField new]; UITextField *groupNameTextField = [OWSTextField new];
@ -505,8 +507,10 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
NSString *groupName = [self.groupNameTextField.text ows_stripped]; NSString *groupName = [self.groupNameTextField.text ows_stripped];
NSMutableArray<NSString *> *recipientIds = [self.memberRecipientIds.allObjects mutableCopy]; NSMutableArray<NSString *> *recipientIds = [self.memberRecipientIds.allObjects mutableCopy];
[recipientIds addObject:[self.contactsViewHelper localNumber]]; [recipientIds addObject:[self.contactsViewHelper localNumber]];
NSData *groupId = [Randomness generateRandomBytes:16]; return [[TSGroupModel alloc] initWithTitle:groupName
return [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:self.groupAvatar groupId:groupId]; memberIds:recipientIds
image:self.groupAvatar
groupId:self.groupId];
} }
#pragma mark - Group Avatar #pragma mark - Group Avatar
@ -529,7 +533,14 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
- (void)updateAvatarView - (void)updateAvatarView
{ {
self.avatarView.image = (self.groupAvatar ?: [UIImage imageNamed:@"empty-group-avatar"]); UIImage *_Nullable groupAvatar = self.groupAvatar;
if (!groupAvatar) {
NSString *conversationColorName = [TSGroupThread defaultConversationColorNameForGroupId:self.groupId];
groupAvatar = [OWSGroupAvatarBuilder defaultAvatarForGroupId:self.groupId
conversationColorName:conversationColorName
diameter:kLargeAvatarSize];
}
self.avatarView.image = groupAvatar;
} }
#pragma mark - Event Handling #pragma mark - Event Handling

@ -758,9 +758,7 @@ const CGFloat kIconViewLength = 24;
[threadInfoView autoPinWidthToSuperviewWithMargin:16.f]; [threadInfoView autoPinWidthToSuperviewWithMargin:16.f];
[threadInfoView autoPinHeightToSuperviewWithMargin:16.f]; [threadInfoView autoPinHeightToSuperviewWithMargin:16.f];
const NSUInteger kAvatarSize = 68; UIImage *avatarImage = [OWSAvatarBuilder buildImageForThread:self.thread diameter:kLargeAvatarSize];
UIImage *avatarImage =
[OWSAvatarBuilder buildImageForThread:self.thread diameter:kAvatarSize contactsManager:self.contactsManager];
OWSAssertDebug(avatarImage); OWSAssertDebug(avatarImage);
AvatarImageView *avatarView = [[AvatarImageView alloc] initWithImage:avatarImage]; AvatarImageView *avatarView = [[AvatarImageView alloc] initWithImage:avatarImage];
@ -768,8 +766,8 @@ const CGFloat kIconViewLength = 24;
[threadInfoView addSubview:avatarView]; [threadInfoView addSubview:avatarView];
[avatarView autoVCenterInSuperview]; [avatarView autoVCenterInSuperview];
[avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoPinLeadingToSuperviewMargin];
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize];
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize];
UIView *threadNameView = [UIView containerView]; UIView *threadNameView = [UIView containerView];
[threadInfoView addSubview:threadNameView]; [threadInfoView addSubview:threadNameView];

@ -179,15 +179,14 @@ NS_ASSUME_NONNULL_BEGIN
[threadInfoView autoPinWidthToSuperviewWithMargin:16.f]; [threadInfoView autoPinWidthToSuperviewWithMargin:16.f];
[threadInfoView autoPinHeightToSuperviewWithMargin:16.f]; [threadInfoView autoPinHeightToSuperviewWithMargin:16.f];
const CGFloat kAvatarSize = 68.f;
AvatarImageView *avatarView = [AvatarImageView new]; AvatarImageView *avatarView = [AvatarImageView new];
_avatarView = avatarView; _avatarView = avatarView;
[threadInfoView addSubview:avatarView]; [threadInfoView addSubview:avatarView];
[avatarView autoVCenterInSuperview]; [avatarView autoVCenterInSuperview];
[avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoPinLeadingToSuperviewMargin];
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize];
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize];
_groupAvatar = self.thread.groupModel.groupImage; _groupAvatar = self.thread.groupModel.groupImage;
[self updateAvatarView]; [self updateAvatarView];
@ -397,7 +396,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateAvatarView - (void)updateAvatarView
{ {
self.avatarView.image = (self.groupAvatar ?: [UIImage imageNamed:@"empty-group-avatar"]); UIImage *_Nullable groupAvatar = self.groupAvatar;
if (!groupAvatar) {
groupAvatar = [[[OWSGroupAvatarBuilder alloc] initWithThread:self.thread diameter:kLargeAvatarSize] build];
}
self.avatarView.image = groupAvatar;
} }
#pragma mark - Event Handling #pragma mark - Event Handling

@ -28,7 +28,7 @@ public class AvatarTableViewCell: UITableViewCell {
@objc @objc
public override init(style: UITableViewCellStyle, reuseIdentifier: String?) { public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
self.avatarView = AvatarImageView() self.avatarView = AvatarImageView()
avatarView.autoSetDimensions(to: CGSize(width: CGFloat(kContactCellAvatarSize), height: CGFloat(kContactCellAvatarSize))) avatarView.autoSetDimensions(to: CGSize(width: CGFloat(kStandardAvatarSize), height: CGFloat(kStandardAvatarSize)))
self._textLabel = UILabel() self._textLabel = UILabel()
self._detailTextLabel = UILabel() self._detailTextLabel = UILabel()

@ -96,8 +96,7 @@ class ContactCell: UITableViewCell {
let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.fullName, let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.fullName,
colorSeed: contactIdForDeterminingBackgroundColor, colorSeed: contactIdForDeterminingBackgroundColor,
diameter: ContactCell.kAvatarDiameter, diameter: ContactCell.kAvatarDiameter)
contactsManager: contactsManager)
contactImageView.image = avatarBuilder.build() contactImageView.image = avatarBuilder.build()
} }

@ -22,7 +22,7 @@ import SignalServiceKit
// Layout // Layout
avatarView.autoSetDimension(.width, toSize: CGFloat(kContactCellAvatarSize)) avatarView.autoSetDimension(.width, toSize: CGFloat(kStandardAvatarSize))
avatarView.autoPinToSquareAspectRatio() avatarView.autoPinToSquareAspectRatio()
let textRows = UIStackView(arrangedSubviews: [nameLabel, subtitleLabel]) let textRows = UIStackView(arrangedSubviews: [nameLabel, subtitleLabel])
@ -58,7 +58,7 @@ import SignalServiceKit
}.joined(separator: ", ") }.joined(separator: ", ")
self.subtitleLabel.text = groupMemberNames self.subtitleLabel.text = groupMemberNames
self.avatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: kContactCellAvatarSize, contactsManager: contactsManager) self.avatarView.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: kStandardAvatarSize)
} }
} }

@ -65,8 +65,7 @@ public class ContactShareViewModel: NSObject {
let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: displayName, let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: displayName,
colorSeed: colorSeed, colorSeed: colorSeed,
diameter: UInt(diameter), diameter: UInt(diameter))
contactsManager: contactsManager)
// Note: we use buildDefaultImage() and not build() so that contact // Note: we use buildDefaultImage() and not build() so that contact
// share views always reflect the contents of the contact share. // share views always reflect the contents of the contact share.
// build() might return an avatar from a corresponding system // build() might return an avatar from a corresponding system

@ -153,6 +153,6 @@ public class ConversationAvatarImageView: AvatarImageView {
public func updateImage() { public func updateImage() {
Logger.debug("updateImage") Logger.debug("updateImage")
self.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: diameter, contactsManager: contactsManager) self.image = OWSAvatarBuilder.buildImage(thread: thread, diameter: diameter)
} }
} }

@ -4,7 +4,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kContactCellAvatarSize;
extern const CGFloat kContactCellAvatarTextMargin; extern const CGFloat kContactCellAvatarTextMargin;
@class OWSContactsManager; @class OWSContactsManager;

@ -15,7 +15,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
const NSUInteger kContactCellAvatarSize = 48;
const CGFloat kContactCellAvatarTextMargin = 12; const CGFloat kContactCellAvatarTextMargin = 12;
@interface ContactCellView () @interface ContactCellView ()
@ -53,8 +52,8 @@ const CGFloat kContactCellAvatarTextMargin = 12;
self.layoutMargins = UIEdgeInsetsZero; self.layoutMargins = UIEdgeInsetsZero;
_avatarView = [AvatarImageView new]; _avatarView = [AvatarImageView new];
[_avatarView autoSetDimension:ALDimensionWidth toSize:kContactCellAvatarSize]; [_avatarView autoSetDimension:ALDimensionWidth toSize:kStandardAvatarSize];
[_avatarView autoSetDimension:ALDimensionHeight toSize:kContactCellAvatarSize]; [_avatarView autoSetDimension:ALDimensionHeight toSize:kStandardAvatarSize];
self.nameLabel = [UILabel new]; self.nameLabel = [UILabel new];
self.nameLabel.lineBreakMode = NSLineBreakByTruncatingTail; self.nameLabel.lineBreakMode = NSLineBreakByTruncatingTail;
@ -164,8 +163,7 @@ const CGFloat kContactCellAvatarTextMargin = 12;
object:nil]; object:nil];
[self updateProfileName]; [self updateProfileName];
} }
self.avatarView.image = self.avatarView.image = [OWSAvatarBuilder buildImageForThread:thread diameter:kStandardAvatarSize];
[OWSAvatarBuilder buildImageForThread:thread diameter:kContactCellAvatarSize contactsManager:contactsManager];
if (self.accessoryMessage) { if (self.accessoryMessage) {
self.accessoryLabel.text = self.accessoryMessage; self.accessoryLabel.text = self.accessoryMessage;
@ -178,13 +176,6 @@ const CGFloat kContactCellAvatarTextMargin = 12;
- (void)updateAvatar - (void)updateAvatar
{ {
OWSContactsManager *contactsManager = self.contactsManager;
if (contactsManager == nil) {
OWSFailDebug(@"contactsManager should not be nil");
self.avatarView.image = nil;
return;
}
NSString *recipientId = self.recipientId; NSString *recipientId = self.recipientId;
if (recipientId.length == 0) { if (recipientId.length == 0) {
OWSFailDebug(@"recipientId should not be nil"); OWSFailDebug(@"recipientId should not be nil");
@ -201,10 +192,9 @@ const CGFloat kContactCellAvatarTextMargin = 12;
} }
}(); }();
self.avatarView.image = [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId self.avatarView.image =
colorName:colorName [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId colorName:colorName diameter:kStandardAvatarSize]
diameter:kContactCellAvatarSize build];
contactsManager:contactsManager] build];
} }
- (void)updateProfileName - (void)updateProfileName

@ -173,6 +173,26 @@ CG_INLINE CGSize CGSizeMax(CGSize size1, CGSize size2)
return CGSizeMake(MAX(size1.width, size2.width), MAX(size1.height, size2.height)); return CGSizeMake(MAX(size1.width, size2.width), MAX(size1.height, size2.height));
} }
CG_INLINE CGPoint CGPointAdd(CGPoint left, CGPoint right)
{
return CGPointMake(left.x + right.x, left.y + right.y);
}
CG_INLINE CGPoint CGPointSubtract(CGPoint left, CGPoint right)
{
return CGPointMake(left.x - right.x, left.y - right.y);
}
CG_INLINE CGPoint CGPointScale(CGPoint point, CGFloat factor)
{
return CGPointMake(point.x * factor, point.y * factor);
}
CG_INLINE CGSize CGSizeScale(CGSize size, CGFloat factor)
{
return CGSizeMake(size.width * factor, size.height * factor);
}
CGFloat CGHairlineWidth(void); CGFloat CGHairlineWidth(void);
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -4,16 +4,16 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class OWSContactsManager; extern const NSUInteger kStandardAvatarSize;
extern const NSUInteger kLargeAvatarSize;
@class TSThread; @class TSThread;
@class UIImage; @class UIImage;
@interface OWSAvatarBuilder : NSObject @interface OWSAvatarBuilder : NSObject
+ (nullable UIImage *)buildImageForThread:(TSThread *)thread + (nullable UIImage *)buildImageForThread:(TSThread *)thread
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter NS_SWIFT_NAME(buildImage(thread:diameter:));
contactsManager:(OWSContactsManager *)contactsManager
NS_SWIFT_NAME(buildImage(thread:diameter:contactsManager:));
+ (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter; + (nullable UIImage *)buildRandomAvatarWithDiameter:(NSUInteger)diameter;
@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
diameter:(NSUInteger)diameter; diameter:(NSUInteger)diameter;
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon + (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
iconSize:(CGSize)iconSize
backgroundColor:(UIColor *)backgroundColor backgroundColor:(UIColor *)backgroundColor
diameter:(NSUInteger)diameter; diameter:(NSUInteger)diameter;

@ -9,19 +9,21 @@
#import "TSGroupThread.h" #import "TSGroupThread.h"
#import "UIColor+OWS.h" #import "UIColor+OWS.h"
#import "UIFont+OWS.h" #import "UIFont+OWS.h"
#import "UIView+OWS.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
const NSUInteger kStandardAvatarSize = 48;
const NSUInteger kLargeAvatarSize = 68;
typedef void (^OWSAvatarDrawBlock)(CGContextRef context); typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
@implementation OWSAvatarBuilder @implementation OWSAvatarBuilder
+ (nullable UIImage *)buildImageForThread:(TSThread *)thread + (nullable UIImage *)buildImageForThread:(TSThread *)thread
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{ {
OWSAssertDebug(thread); OWSAssertDebug(thread);
OWSAssertDebug(contactsManager);
OWSAvatarBuilder *avatarBuilder; OWSAvatarBuilder *avatarBuilder;
if ([thread isKindOfClass:[TSContactThread class]]) { if ([thread isKindOfClass:[TSContactThread class]]) {
@ -29,10 +31,9 @@ typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
NSString *colorName = thread.conversationColorName; NSString *colorName = thread.conversationColorName;
avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:contactThread.contactIdentifier avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:contactThread.contactIdentifier
colorName:colorName colorName:colorName
diameter:diameter diameter:diameter];
contactsManager:contactsManager];
} else if ([thread isKindOfClass:[TSGroupThread class]]) { } else if ([thread isKindOfClass:[TSGroupThread class]]) {
avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread]; avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread diameter:diameter];
} else { } else {
OWSLogError(@"called with unsupported thread: %@", thread); OWSLogError(@"called with unsupported thread: %@", thread);
} }
@ -106,16 +107,19 @@ typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
} }
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon + (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
iconSize:(CGSize)iconSize
backgroundColor:(UIColor *)backgroundColor backgroundColor:(UIColor *)backgroundColor
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
{ {
return [self avatarImageWithIcon:icon return [self avatarImageWithIcon:icon
iconSize:iconSize
iconColor:self.avatarForegroundColor iconColor:self.avatarForegroundColor
backgroundColor:backgroundColor backgroundColor:backgroundColor
diameter:diameter]; diameter:diameter];
} }
+ (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon + (nullable UIImage *)avatarImageWithIcon:(UIImage *)icon
iconSize:(CGSize)iconSize
iconColor:(UIColor *)iconColor iconColor:(UIColor *)iconColor
backgroundColor:(UIColor *)backgroundColor backgroundColor:(UIColor *)backgroundColor
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
@ -126,7 +130,11 @@ typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
return [self avatarImageWithDiameter:diameter return [self avatarImageWithDiameter:diameter
backgroundColor:backgroundColor backgroundColor:backgroundColor
drawBlock:^(CGContextRef context) { drawBlock:^(CGContextRef context) {
[self drawIconInAvatar:icon iconColor:iconColor diameter:diameter]; [self drawIconInAvatar:icon
iconSize:iconSize
iconColor:iconColor
diameter:diameter
context:context];
}]; }];
} }
@ -230,14 +238,34 @@ typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
[initials drawAtPoint:drawPoint withAttributes:textAttributes]; [initials drawAtPoint:drawPoint withAttributes:textAttributes];
} }
+ (void)drawIconInAvatar:(UIImage *)icon iconColor:(UIColor *)iconColor diameter:(NSUInteger)diameter + (void)drawIconInAvatar:(UIImage *)icon
iconSize:(CGSize)iconSize
iconColor:(UIColor *)iconColor
diameter:(NSUInteger)diameter
context:(CGContextRef)context
{ {
OWSAssertDebug(icon); OWSAssertDebug(icon);
OWSAssertDebug(iconColor); OWSAssertDebug(iconColor);
OWSAssertDebug(diameter > 0); OWSAssertDebug(diameter > 0);
OWSAssertDebug(context);
CGPoint drawPoint = CGPointMake((diameter - icon.size.width) * 0.5f, (diameter - icon.size.height) * 0.5f);
[icon drawAtPoint:drawPoint]; // UIKit uses an ULO coordinate system (upper-left-origin).
// Core Graphics uses an LLO coordinate system (lower-left-origin).
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, diameter);
CGContextConcatCTM(context, flipVertical);
CGRect imageRect = CGRectZero;
imageRect.size = CGSizeMake(diameter, diameter);
// The programmatic equivalent of UIImageRenderingModeAlwaysTemplate/tintColor.
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGRect maskRect = CGRectZero;
maskRect.origin = CGPointScale(
CGPointSubtract(CGPointMake(diameter, diameter), CGPointMake(iconSize.width, iconSize.height)), 0.5f);
maskRect.size = iconSize;
CGContextClipToMask(context, maskRect, icon.CGImage);
CGContextSetFillColor(context, CGColorGetComponents(iconColor.CGColor));
CGContextFillRect(context, imageRect);
} }
- (nullable UIImage *)build - (nullable UIImage *)build

@ -6,7 +6,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class OWSContactsManager;
@class TSContactThread; @class TSContactThread;
@interface OWSContactAvatarBuilder : OWSAvatarBuilder @interface OWSContactAvatarBuilder : OWSAvatarBuilder
@ -15,18 +14,14 @@ NS_ASSUME_NONNULL_BEGIN
* Build an avatar for a Signal recipient * Build an avatar for a Signal recipient
*/ */
- (instancetype)initWithSignalId:(NSString *)signalId - (instancetype)initWithSignalId:(NSString *)signalId colorName:(NSString *)colorName diameter:(NSUInteger)diameter;
colorName:(NSString *)colorName
diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager;
/** /**
* Build an avatar for a non-Signal recipient * Build an avatar for a non-Signal recipient
*/ */
- (instancetype)initWithNonSignalName:(NSString *)nonSignalName - (instancetype)initWithNonSignalName:(NSString *)nonSignalName
colorSeed:(NSString *)colorSeed colorSeed:(NSString *)colorSeed
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter;
contactsManager:(OWSContactsManager *)contactsManager;
@end @end

@ -10,12 +10,12 @@
#import "UIColor+OWS.h" #import "UIColor+OWS.h"
#import "UIFont+OWS.h" #import "UIFont+OWS.h"
#import <SignalMessaging/SignalMessaging-Swift.h> #import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/SSKEnvironment.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface OWSContactAvatarBuilder () @interface OWSContactAvatarBuilder ()
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) NSString *signalId; @property (nonatomic, readonly) NSString *signalId;
@property (nonatomic, readonly) NSString *contactName; @property (nonatomic, readonly) NSString *contactName;
@property (nonatomic, readonly) NSString *colorName; @property (nonatomic, readonly) NSString *colorName;
@ -31,7 +31,6 @@ NS_ASSUME_NONNULL_BEGIN
name:(NSString *)name name:(NSString *)name
colorName:(NSString *)colorName colorName:(NSString *)colorName
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{ {
self = [super init]; self = [super init];
if (!self) { if (!self) {
@ -44,7 +43,6 @@ NS_ASSUME_NONNULL_BEGIN
_contactName = name; _contactName = name;
_colorName = colorName; _colorName = colorName;
_diameter = diameter; _diameter = diameter;
_contactsManager = contactsManager;
return self; return self;
} }
@ -52,42 +50,39 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithSignalId:(NSString *)signalId - (instancetype)initWithSignalId:(NSString *)signalId
colorName:(NSString *)colorName colorName:(NSString *)colorName
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{ {
// Name for avatar initials. // Name for avatar initials.
NSString *_Nullable name = [contactsManager nameFromSystemContactsForRecipientId:signalId]; NSString *_Nullable name = [OWSContactAvatarBuilder.contactsManager nameFromSystemContactsForRecipientId:signalId];
if (name.length == 0) { if (name.length == 0) {
name = [contactsManager profileNameForRecipientId:signalId]; name = [OWSContactAvatarBuilder.contactsManager profileNameForRecipientId:signalId];
} }
if (name.length == 0) { if (name.length == 0) {
name = signalId; name = signalId;
} }
return [self initWithContactId:signalId return [self initWithContactId:signalId name:name colorName:colorName diameter:diameter];
name:name
colorName:colorName
diameter:diameter
contactsManager:contactsManager];
} }
- (instancetype)initWithNonSignalName:(NSString *)nonSignalName - (instancetype)initWithNonSignalName:(NSString *)nonSignalName
colorSeed:(NSString *)colorSeed colorSeed:(NSString *)colorSeed
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager
{ {
NSString *colorName = [TSThread stableConversationColorNameForString:colorSeed]; NSString *colorName = [TSThread stableConversationColorNameForString:colorSeed];
return [self initWithContactId:colorSeed return [self initWithContactId:colorSeed name:nonSignalName colorName:(NSString *)colorName diameter:diameter];
name:nonSignalName }
colorName:(NSString *)colorName
diameter:diameter #pragma mark - Dependencies
contactsManager:contactsManager];
+ (OWSContactsManager *)contactsManager
{
return (OWSContactsManager *)SSKEnvironment.shared.contactsManager;
} }
#pragma mark - Instance methods #pragma mark - Instance methods
- (nullable UIImage *)buildSavedImage - (nullable UIImage *)buildSavedImage
{ {
return [self.contactsManager imageForPhoneIdentifier:self.signalId]; return [OWSContactAvatarBuilder.contactsManager imageForPhoneIdentifier:self.signalId];
} }
- (id)cacheKey - (id)cacheKey
@ -97,8 +92,8 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable UIImage *)buildDefaultImage - (nullable UIImage *)buildDefaultImage
{ {
UIImage *cachedAvatar = UIImage *_Nullable cachedAvatar =
[self.contactsManager.avatarCache imageForKey:self.cacheKey diameter:(CGFloat)self.diameter]; [OWSContactAvatarBuilder.contactsManager.avatarCache imageForKey:self.cacheKey diameter:(CGFloat)self.diameter];
if (cachedAvatar) { if (cachedAvatar) {
return cachedAvatar; return cachedAvatar;
} }
@ -139,7 +134,7 @@ NS_ASSUME_NONNULL_BEGIN
return nil; return nil;
} }
[self.contactsManager.avatarCache setImage:image forKey:self.cacheKey diameter:self.diameter]; [OWSContactAvatarBuilder.contactsManager.avatarCache setImage:image forKey:self.cacheKey diameter:self.diameter];
return image; return image;
} }

@ -10,8 +10,11 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSGroupAvatarBuilder : OWSAvatarBuilder @interface OWSGroupAvatarBuilder : OWSAvatarBuilder
- (instancetype)initWithThread:(TSGroupThread *)thread; - (instancetype)initWithThread:(TSGroupThread *)thread diameter:(NSUInteger)diameter;
+ (UIImage *)defaultGroupImage;
+ (nullable UIImage *)defaultAvatarForGroupId:(NSData *)groupId
conversationColorName:(NSString *)conversationColorName
diameter:(NSUInteger)diameter;
@end @end

@ -3,19 +3,24 @@
// //
#import "OWSGroupAvatarBuilder.h" #import "OWSGroupAvatarBuilder.h"
#import "OWSContactsManager.h"
#import "TSGroupThread.h" #import "TSGroupThread.h"
#import "UIColor+OWS.h"
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/SSKEnvironment.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface OWSGroupAvatarBuilder () @interface OWSGroupAvatarBuilder ()
@property (nonatomic, readonly) TSGroupThread *thread; @property (nonatomic, readonly) TSGroupThread *thread;
@property (nonatomic, readonly) NSUInteger diameter;
@end @end
@implementation OWSGroupAvatarBuilder @implementation OWSGroupAvatarBuilder
- (instancetype)initWithThread:(TSGroupThread *)thread - (instancetype)initWithThread:(TSGroupThread *)thread diameter:(NSUInteger)diameter
{ {
self = [super init]; self = [super init];
if (!self) { if (!self) {
@ -23,10 +28,20 @@ NS_ASSUME_NONNULL_BEGIN
} }
_thread = thread; _thread = thread;
_diameter = diameter;
return self; return self;
} }
#pragma mark - Dependencies
+ (OWSContactsManager *)contactsManager
{
return (OWSContactsManager *)SSKEnvironment.shared.contactsManager;
}
#pragma mark -
- (nullable UIImage *)buildSavedImage - (nullable UIImage *)buildSavedImage
{ {
return self.thread.groupModel.groupImage; return self.thread.groupModel.groupImage;
@ -34,17 +49,45 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable UIImage *)buildDefaultImage - (nullable UIImage *)buildDefaultImage
{ {
return self.class.defaultGroupImage; return [self.class defaultAvatarForGroupId:self.thread.groupModel.groupId
conversationColorName:self.thread.conversationColorName
diameter:self.diameter];
}
+ (nullable UIImage *)defaultAvatarForGroupId:(NSData *)groupId
conversationColorName:(NSString *)conversationColorName
diameter:(NSUInteger)diameter
{
NSString *cacheKey = [NSString stringWithFormat:@"%@-%d", groupId.hexadecimalString, Theme.isDarkThemeEnabled];
UIImage *_Nullable cachedAvatar =
[OWSGroupAvatarBuilder.contactsManager.avatarCache imageForKey:cacheKey diameter:(CGFloat)diameter];
if (cachedAvatar) {
return cachedAvatar;
}
UIColor *backgroundColor =
[UIColor ows_conversationColorForColorName:conversationColorName isShaded:Theme.isDarkThemeEnabled];
UIImage *_Nullable image =
[OWSGroupAvatarBuilder groupAvatarImageWithBackgroundColor:backgroundColor diameter:diameter];
if (!image) {
OWSFailDebug(@"Could not create group avatar.");
return nil;
}
[OWSGroupAvatarBuilder.contactsManager.avatarCache setImage:image forKey:cacheKey diameter:diameter];
return image;
} }
+ (UIImage *)defaultGroupImage + (nullable UIImage *)groupAvatarImageWithBackgroundColor:(UIColor *)backgroundColor diameter:(NSUInteger)diameter
{ {
static UIImage *defaultGroupImage; UIImage *icon = [UIImage imageNamed:@"group-avatar"];
static dispatch_once_t onceToken; // The group-avatar asset is designed for the kStandardAvatarSize.
dispatch_once(&onceToken, ^{ // Adjust its size to reflect the actual output diameter.
defaultGroupImage = [UIImage imageNamed:@"empty-group-avatar"]; CGFloat scaling = diameter / (CGFloat)kStandardAvatarSize;
}); CGSize iconSize = CGSizeScale(icon.size, scaling);
return defaultGroupImage; return
[OWSAvatarBuilder avatarImageWithIcon:icon iconSize:iconSize backgroundColor:backgroundColor diameter:diameter];
} }
@end @end

@ -44,6 +44,8 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId;
- (void)fireAvatarChangedNotification; - (void)fireAvatarChangedNotification;
+ (NSString *)defaultConversationColorNameForGroupId:(NSData *)groupId;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -242,6 +242,13 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific
userInfo:userInfo]; userInfo:userInfo];
} }
+ (NSString *)defaultConversationColorNameForGroupId:(NSData *)groupId
{
OWSAssertDebug(groupId.length > 0);
return [self.class stableConversationColorNameForString:[self threadIdFromGroupId:groupId]];
}
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

Loading…
Cancel
Save