Merge branch 'mkirk/profile-name-for-avatar'

pull/1/head
Michael Kirk 8 years ago
commit 3cccf92757

@ -148,6 +148,9 @@
454EBAB41F2BE14C00ACE0BB /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; }; 454EBAB41F2BE14C00ACE0BB /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; };
455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
455AC69B1F4F79E500134004 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455AC69A1F4F79E500134004 /* ImageCache.swift */; };
455AC69C1F4F79E500134004 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455AC69A1F4F79E500134004 /* ImageCache.swift */; };
455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */; };
45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; }; 45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; };
45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */; }; 45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */; };
4563ADF11F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */; }; 4563ADF11F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */; };
@ -602,6 +605,8 @@
454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; }; 454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; };
455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
455AC69A1F4F79E500134004 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCacheTest.swift; sourceTree = "<group>"; };
45638BDB1F3DD0D400128435 /* DebugUICalling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUICalling.swift; sourceTree = "<group>"; }; 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUICalling.swift; sourceTree = "<group>"; };
45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Promise.swift"; sourceTree = "<group>"; }; 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Promise.swift"; sourceTree = "<group>"; };
4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS106EnsureProfileComplete.swift; sourceTree = "<group>"; }; 4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS106EnsureProfileComplete.swift; sourceTree = "<group>"; };
@ -1439,6 +1444,7 @@
76EB04FB18170B33006006FC /* Util.h */, 76EB04FB18170B33006006FC /* Util.h */,
45F170D51E315310003FC1F2 /* Weak.swift */, 45F170D51E315310003FC1F2 /* Weak.swift */,
45F170CB1E310E22003FC1F2 /* WeakTimer.swift */, 45F170CB1E310E22003FC1F2 /* WeakTimer.swift */,
455AC69A1F4F79E500134004 /* ImageCache.swift */,
); );
path = util; path = util;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1639,6 +1645,7 @@
B660F6B31C29868000687D6E /* UtilTest.h */, B660F6B31C29868000687D6E /* UtilTest.h */,
B660F6B41C29868000687D6E /* UtilTest.m */, B660F6B41C29868000687D6E /* UtilTest.m */,
45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */, 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */,
455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */,
); );
path = util; path = util;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2194,6 +2201,7 @@
34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */, 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */,
344F2F671E57A932000D9322 /* UIViewController+OWS.m in Sources */, 344F2F671E57A932000D9322 /* UIViewController+OWS.m in Sources */,
B6DA6B071B8A2F9A00CA6F98 /* AppStoreRating.m in Sources */, B6DA6B071B8A2F9A00CA6F98 /* AppStoreRating.m in Sources */,
455AC69B1F4F79E500134004 /* ImageCache.swift in Sources */,
451A13B11E13DED2000A50FD /* CallNotificationsAdapter.swift in Sources */, 451A13B11E13DED2000A50FD /* CallNotificationsAdapter.swift in Sources */,
3456710A1E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m in Sources */, 3456710A1E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m in Sources */,
450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */, 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */,
@ -2434,6 +2442,7 @@
B660F7771C29988E00687D6E /* UIImage+normalizeImage.m in Sources */, B660F7771C29988E00687D6E /* UIImage+normalizeImage.m in Sources */,
954AEE6A1DF33E01002E5410 /* ContactsPickerTest.swift in Sources */, 954AEE6A1DF33E01002E5410 /* ContactsPickerTest.swift in Sources */,
B660F77B1C29988E00687D6E /* Queue.m in Sources */, B660F77B1C29988E00687D6E /* Queue.m in Sources */,
455AC69C1F4F79E500134004 /* ImageCache.swift in Sources */,
45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */, 45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */,
B660F77F1C29988E00687D6E /* DateUtil.m in Sources */, B660F77F1C29988E00687D6E /* DateUtil.m in Sources */,
B660F7811C29988E00687D6E /* FunctionalUtil.m in Sources */, B660F7811C29988E00687D6E /* FunctionalUtil.m in Sources */,
@ -2462,6 +2471,7 @@
B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */, B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */,
45C0DC1F1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, 45C0DC1F1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */,
4505C2C01E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */, 4505C2C01E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */,
455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */,
450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */, 450873C81D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

@ -243,6 +243,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{ [[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{
[VersionMigrations runSafeBlockingMigrations]; [VersionMigrations runSafeBlockingMigrations];
}]; }];
[[Environment getCurrent].contactsManager startObserving];
self.incomingMessageReadObserver = self.incomingMessageReadObserver =
[[OWSIncomingMessageReadObserver alloc] initWithMessageSender:[Environment getCurrent].messageSender]; [[OWSIncomingMessageReadObserver alloc] initWithMessageSender:[Environment getCurrent].messageSender];

@ -4,6 +4,7 @@
#import "OWSContactAvatarBuilder.h" #import "OWSContactAvatarBuilder.h"
#import "OWSContactsManager.h" #import "OWSContactsManager.h"
#import "Signal-Swift.h"
#import "TSContactThread.h" #import "TSContactThread.h"
#import "TSGroupThread.h" #import "TSGroupThread.h"
#import "TSThread.h" #import "TSThread.h"
@ -48,7 +49,14 @@ NS_ASSUME_NONNULL_BEGIN
diameter:(NSUInteger)diameter diameter:(NSUInteger)diameter
contactsManager:(OWSContactsManager *)contactsManager contactsManager:(OWSContactsManager *)contactsManager
{ {
NSString *name = [contactsManager displayNameForPhoneIdentifier:signalId]; // Name for avatar initials.
NSString *_Nullable name = [contactsManager nameFromSystemContactsForRecipientId:signalId];
if (name.length == 0) {
name = [contactsManager profileNameForRecipientId:signalId];
}
if (name.length == 0) {
name = signalId;
}
return [self initWithContactId:signalId name:name diameter:diameter contactsManager:contactsManager]; return [self initWithContactId:signalId name:name diameter:diameter contactsManager:contactsManager];
} }
@ -69,8 +77,8 @@ NS_ASSUME_NONNULL_BEGIN
- (UIImage *)buildDefaultImage - (UIImage *)buildDefaultImage
{ {
NSString *cacheKey = [NSString stringWithFormat:@"signalId:%@:diamater:%lu", self.signalId, (unsigned long)self.diameter]; UIImage *cachedAvatar =
UIImage *cachedAvatar = [self.contactsManager.avatarCache objectForKey:cacheKey]; [self.contactsManager.avatarCache imageForKey:self.signalId diameter:(CGFloat)self.diameter];
if (cachedAvatar) { if (cachedAvatar) {
return cachedAvatar; return cachedAvatar;
} }
@ -108,7 +116,8 @@ NS_ASSUME_NONNULL_BEGIN
textColor:[UIColor whiteColor] textColor:[UIColor whiteColor]
font:[UIFont ows_boldFontWithSize:fontSize] font:[UIFont ows_boldFontWithSize:fontSize]
diameter:self.diameter] avatarImage]; diameter:self.diameter] avatarImage];
[self.contactsManager.avatarCache setObject:image forKey:cacheKey];
[self.contactsManager.avatarCache setImage:image forKey:self.signalId diameter:self.diameter];
return image; return image;
} }

@ -7,6 +7,7 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
extern NSString *const kNSNotificationName_LocalProfileDidChange; extern NSString *const kNSNotificationName_LocalProfileDidChange;
extern NSString *const kNSNotificationName_OtherUsersProfileWillChange;
extern NSString *const kNSNotificationName_OtherUsersProfileDidChange; extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
extern NSString *const kNSNotificationName_ProfileWhitelistDidChange; extern NSString *const kNSNotificationName_ProfileWhitelistDidChange;
extern NSString *const kNSNotificationKey_ProfileRecipientId; extern NSString *const kNSNotificationKey_ProfileRecipientId;

@ -86,6 +86,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
NSString *const kNSNotificationName_LocalProfileDidChange = @"kNSNotificationName_LocalProfileDidChange"; NSString *const kNSNotificationName_LocalProfileDidChange = @"kNSNotificationName_LocalProfileDidChange";
NSString *const kNSNotificationName_OtherUsersProfileWillChange = @"kNSNotificationName_OtherUsersProfileWillChange";
NSString *const kNSNotificationName_OtherUsersProfileDidChange = @"kNSNotificationName_OtherUsersProfileDidChange"; NSString *const kNSNotificationName_OtherUsersProfileDidChange = @"kNSNotificationName_OtherUsersProfileDidChange";
NSString *const kNSNotificationName_ProfileWhitelistDidChange = @"kNSNotificationName_ProfileWhitelistDidChange"; NSString *const kNSNotificationName_ProfileWhitelistDidChange = @"kNSNotificationName_ProfileWhitelistDidChange";
NSString *const kNSNotificationKey_ProfileRecipientId = @"kNSNotificationKey_ProfileRecipientId"; NSString *const kNSNotificationKey_ProfileRecipientId = @"kNSNotificationKey_ProfileRecipientId";
@ -239,6 +240,12 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
object:nil object:nil
userInfo:nil]; userInfo:nil];
} else { } else {
[[NSNotificationCenter defaultCenter]
postNotificationName:kNSNotificationName_OtherUsersProfileWillChange
object:nil
userInfo:@{
kNSNotificationKey_ProfileRecipientId : userProfile.recipientId,
}];
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
postNotificationName:kNSNotificationName_OtherUsersProfileDidChange postNotificationName:kNSNotificationName_OtherUsersProfileDidChange
object:nil object:nil

@ -212,10 +212,10 @@ const NSUInteger kAvatarViewDiameter = 52;
name:kNSNotificationName_OtherUsersProfileDidChange name:kNSNotificationName_OtherUsersProfileDidChange
object:nil]; object:nil];
[self updateNameLabel]; [self updateNameLabel];
[self updateAvatarView];
self.snippetLabel.attributedText = snippetText; self.snippetLabel.attributedText = snippetText;
self.timeLabel.attributedText = attributedDate; self.timeLabel.attributedText = attributedDate;
self.avatarView.image = nil;
self.separatorInset = UIEdgeInsetsMake(0, self.avatarSize * 1.5f, 0, 0); self.separatorInset = UIEdgeInsetsMake(0, self.avatarSize * 1.5f, 0, 0);
@ -229,11 +229,27 @@ const NSUInteger kAvatarViewDiameter = 52;
self.unreadBadge.hidden = YES; self.unreadBadge.hidden = YES;
self.unreadLabel.hidden = YES; self.unreadLabel.hidden = YES;
} }
}
- (void)updateAvatarView
{
OWSContactsManager *contactsManager = self.contactsManager;
if (contactsManager == nil) {
OWSFail(@"%@ contactsManager should not be nil", self.logTag);
self.avatarView.image = nil;
return;
}
TSThread *thread = self.thread;
if (thread == nil) {
OWSFail(@"%@ thread should not be nil", self.logTag);
self.avatarView.image = nil;
return;
}
self.avatarView.image = self.avatarView.image =
[OWSAvatarBuilder buildImageForThread:thread diameter:kAvatarViewDiameter contactsManager:contactsManager]; [OWSAvatarBuilder buildImageForThread:thread diameter:kAvatarViewDiameter contactsManager:contactsManager];
} }
#pragma mark - Date formatting #pragma mark - Date formatting
- (NSAttributedString *)dateAttributedString:(NSDate *)date { - (NSAttributedString *)dateAttributedString:(NSDate *)date {
@ -286,6 +302,7 @@ const NSUInteger kAvatarViewDiameter = 52;
} }
[self updateNameLabel]; [self updateNameLabel];
[self updateAvatarView];
} }
-(void)updateNameLabel -(void)updateNameLabel

@ -11,13 +11,20 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
@class UIFont; @class UIFont;
@class SignalAccount; @class SignalAccount;
@class ImageCache;
/** /**
* Get latest Signal contacts, and be notified when they change. * Get latest Signal contacts, and be notified when they change.
*/ */
@interface OWSContactsManager : NSObject <ContactsManagerProtocol> @interface OWSContactsManager : NSObject <ContactsManagerProtocol>
@property (nonnull, readonly) NSCache<NSString *, UIImage *> *avatarCache; #pragma mark - Setup
- (void)startObserving;
#pragma mark - Accessors
@property (nonnull, readonly) ImageCache *avatarCache;
@property (atomic, readonly) NSArray<Contact *> *allContacts; @property (atomic, readonly) NSArray<Contact *> *allContacts;
@ -54,7 +61,14 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
- (BOOL)hasNameInSystemContactsForRecipientId:(NSString *)recipientId; - (BOOL)hasNameInSystemContactsForRecipientId:(NSString *)recipientId;
- (NSString *)displayNameForPhoneIdentifier:(nullable NSString *)identifier; - (NSString *)displayNameForPhoneIdentifier:(nullable NSString *)identifier;
- (NSString *)displayNameForSignalAccount:(SignalAccount *)signalAccount; - (NSString *)displayNameForSignalAccount:(SignalAccount *)signalAccount;
// Generally we prefer the formattedProfileName over the raw profileName so as to
// distinguish a profile name apart from a name pulled from the system's contacts.
// This helps clarify when the remote person chooses a potentially confusing profile name.
- (nullable NSString *)formattedProfileNameForRecipientId:(NSString *)recipientId; - (nullable NSString *)formattedProfileNameForRecipientId:(NSString *)recipientId;
- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId;
- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId;
- (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier; - (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier;
- (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font; - (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font;
- (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font; - (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font;

@ -50,7 +50,7 @@ NSString *const kTSStorageManager_AccountLastNames = @"kTSStorageManager_Account
} }
// TODO: We need to configure the limits of this cache. // TODO: We need to configure the limits of this cache.
_avatarCache = [NSCache new]; _avatarCache = [ImageCache new];
_allContacts = @[]; _allContacts = @[];
_signalAccountMap = @{}; _signalAccountMap = @{};
_signalAccounts = @[]; _signalAccounts = @[];
@ -136,6 +136,24 @@ NSString *const kTSStorageManager_AccountLastNames = @"kTSStorageManager_Account
failure:failure]; failure:failure];
} }
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(otherUsersProfileWillChange:)
name:kNSNotificationName_OtherUsersProfileWillChange
object:nil];
}
- (void)otherUsersProfileWillChange:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
NSString *recipientId = notification.userInfo[kNSNotificationKey_ProfileRecipientId];
OWSAssert(recipientId.length > 0);
[self.avatarCache removeAllImagesForKey:recipientId];
}
- (void)updateWithContacts:(NSArray<Contact *> *)contacts - (void)updateWithContacts:(NSArray<Contact *> *)contacts
{ {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@ -154,7 +172,7 @@ NSString *const kTSStorageManager_AccountLastNames = @"kTSStorageManager_Account
self.allContacts = contacts; self.allContacts = contacts;
self.allContactsMap = [allContactsMap copy]; self.allContactsMap = [allContactsMap copy];
[self.avatarCache removeAllObjects]; [self.avatarCache removeAllImages];
[self intersectContacts]; [self intersectContacts];
@ -423,16 +441,25 @@ NSString *const kTSStorageManager_AccountLastNames = @"kTSStorageManager_Account
return [NSString stringWithFormat:profileNameFormatString, profileName]; return [NSString stringWithFormat:profileNameFormatString, profileName];
} }
- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId
{
return [self.profileManager profileNameForRecipientId:recipientId];
}
- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId
{
return [self cachedDisplayNameForRecipientId:recipientId];
}
- (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId - (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId
{ {
if (!recipientId) { if (!recipientId) {
return self.unknownContactName; return self.unknownContactName;
} }
// Prefer a saved name from system contacts, if available NSString *_Nullable displayName = [self nameFromSystemContactsForRecipientId:recipientId];
NSString *_Nullable displayName = [self cachedDisplayNameForRecipientId:recipientId];
// Else fall back to just using their recipientId // Fall back to just using their recipientId
if (displayName.length < 1) { if (displayName.length < 1) {
displayName = recipientId; displayName = recipientId;
} }

@ -0,0 +1,53 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
import UIKit
class ImageCacheRecord: NSObject {
var variations: [CGFloat: UIImage]
init(variations: [CGFloat: UIImage]) {
self.variations = variations
}
}
/**
* A two dimensional hash, allowing you to store variations under a single key.
* This is useful because we generate multiple diameters of an image, but when we
* want to clear out the images for a key we want to clear out *all* variations.
*/
@objc
class ImageCache: NSObject {
let backingCache: NSCache<AnyObject, ImageCacheRecord>
override init() {
self.backingCache = NSCache()
}
func image(forKey key: AnyObject, diameter: CGFloat) -> UIImage? {
guard let record = backingCache.object(forKey: key) else {
return nil
}
return record.variations[diameter]
}
func setImage(_ image: UIImage, forKey key: AnyObject, diameter: CGFloat) {
if let existingRecord = backingCache.object(forKey: key) {
existingRecord.variations[diameter] = image
backingCache.setObject(existingRecord, forKey: key)
} else {
let newRecord = ImageCacheRecord(variations: [diameter: image])
backingCache.setObject(newRecord, forKey: key)
}
}
func removeAllImages() {
backingCache.removeAllObjects()
}
func removeAllImages(forKey key: AnyObject) {
backingCache.removeObject(forKey: key)
}
}

@ -129,6 +129,7 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
name:kNSNotificationName_OtherUsersProfileDidChange name:kNSNotificationName_OtherUsersProfileDidChange
object:nil]; object:nil];
[self updateProfileName]; [self updateProfileName];
[self updateAvatar];
if (self.accessoryMessage) { if (self.accessoryMessage) {
UILabel *blockedLabel = [[UILabel alloc] init]; UILabel *blockedLabel = [[UILabel alloc] init];
@ -141,10 +142,6 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
self.accessoryView = blockedLabel; self.accessoryView = blockedLabel;
} }
self.avatarView.image = [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId
diameter:kContactTableViewCellAvatarSize
contactsManager:contactsManager] build];
// Force layout, since imageView isn't being initally rendered on App Store optimized build. // Force layout, since imageView isn't being initally rendered on App Store optimized build.
[self layoutSubviews]; [self layoutSubviews];
} }
@ -197,7 +194,26 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
return [text copy]; return [text copy];
} }
- (void)updateAvatar
{
OWSContactsManager *contactsManager = self.contactsManager;
if (contactsManager == nil) {
OWSFail(@"%@ contactsManager should not be nil", self.logTag);
self.avatarView.image = nil;
return;
}
NSString *recipientId = self.recipientId;
if (recipientId.length == 0) {
OWSFail(@"%@ recipientId should not be nil", self.logTag);
self.avatarView.image = nil;
return;
}
self.avatarView.image = [[[OWSContactAvatarBuilder alloc] initWithSignalId:recipientId
diameter:kContactTableViewCellAvatarSize
contactsManager:contactsManager] build];
}
- (void)updateProfileName - (void)updateProfileName
{ {
OWSContactsManager *contactsManager = self.contactsManager; OWSContactsManager *contactsManager = self.contactsManager;
@ -246,6 +262,7 @@ const NSUInteger kContactTableViewCellAvatarSize = 40;
if (recipientId.length > 0 && [self.recipientId isEqualToString:recipientId]) { if (recipientId.length > 0 && [self.recipientId isEqualToString:recipientId]) {
[self updateProfileName]; [self updateProfileName];
[self updateAvatar];
} }
} }

@ -0,0 +1,60 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import XCTest
class ImageCacheTest: XCTestCase {
var imageCache: ImageCache!
let firstVariation = UIImage()
let secondVariation = UIImage()
let otherImage = UIImage()
let cacheKey1 = "cache-key-1" as NSString
let cacheKey2 = "cache-key-2" as NSString
override func setUp() {
super.setUp()
self.imageCache = ImageCache()
imageCache.setImage(firstVariation, forKey:cacheKey1, diameter:100)
imageCache.setImage(secondVariation, forKey:cacheKey1, diameter:200)
imageCache.setImage(otherImage, forKey:cacheKey2, diameter:100)
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testSetGet() {
XCTAssertEqual(firstVariation, imageCache.image(forKey:cacheKey1, diameter: 100))
XCTAssertEqual(secondVariation, imageCache.image(forKey:cacheKey1, diameter: 200))
XCTAssertNotEqual(secondVariation, imageCache.image(forKey:cacheKey1, diameter: 100))
XCTAssertEqual(otherImage, imageCache.image(forKey:cacheKey2, diameter: 100))
XCTAssertNil(imageCache.image(forKey:cacheKey2, diameter: 200))
}
func testRemoveAllForKey() {
// sanity check
XCTAssertEqual(firstVariation, imageCache.image(forKey:cacheKey1, diameter: 100))
XCTAssertEqual(otherImage, imageCache.image(forKey:cacheKey2, diameter: 100))
imageCache.removeAllImages(forKey:cacheKey1)
XCTAssertNil(imageCache.image(forKey:cacheKey1, diameter: 100))
XCTAssertNil(imageCache.image(forKey:cacheKey1, diameter: 200))
XCTAssertEqual(otherImage, imageCache.image(forKey:cacheKey2, diameter: 100))
}
func testRemoveAll() {
XCTAssertEqual(firstVariation, imageCache.image(forKey:cacheKey1, diameter: 100))
imageCache.removeAllImages()
XCTAssertNil(imageCache.image(forKey:cacheKey1, diameter: 100))
XCTAssertNil(imageCache.image(forKey:cacheKey1, diameter: 200))
XCTAssertNil(imageCache.image(forKey:cacheKey2, diameter: 100))
}
}

@ -171,7 +171,7 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
{ {
YapDatabaseView *existingView = [database registeredExtension:OWSMessageProcessingJobFinderExtensionName]; YapDatabaseView *existingView = [database registeredExtension:OWSMessageProcessingJobFinderExtensionName];
if (existingView) { if (existingView) {
OWSFail(@"%@ was already initailized.", OWSMessageProcessingJobFinderExtensionName); OWSFail(@"%@ was already initialized.", OWSMessageProcessingJobFinderExtensionName);
// already initialized // already initialized
return; return;
} }

Loading…
Cancel
Save