Reworking observation of Contact and SignalAccount changes.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 994aec0d86
commit ad11c50c1b

@ -106,8 +106,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
- (void)observeNotifications - (void)observeNotifications
{ {
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(signalRecipientsDidChange:) selector:@selector(signalAccountsDidChange:)
name:OWSContactsManagerSignalRecipientsDidChangeNotification name:OWSContactsManagerSignalAccountsDidChangeNotification
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(blockedPhoneNumbersDidChange:) selector:@selector(blockedPhoneNumbersDidChange:)
@ -120,7 +120,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
} }
- (void)signalRecipientsDidChange:(NSNotification *)notification { - (void)signalAccountsDidChange:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self updateContacts]; [self updateContacts];
}); });

@ -93,6 +93,10 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
selector:@selector(blockedPhoneNumbersDidChange:) selector:@selector(blockedPhoneNumbersDidChange:)
name:kNSNotificationName_BlockedPhoneNumbersDidChange name:kNSNotificationName_BlockedPhoneNumbersDidChange
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(signalAccountsDidChange:)
name:OWSContactsManagerSignalAccountsDidChangeNotification
object:nil];
} }
- (void)dealloc - (void)dealloc
@ -109,6 +113,13 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
}); });
} }
- (void)signalAccountsDidChange:(id)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
- (void)awakeFromNib - (void)awakeFromNib
{ {
[super awakeFromNib]; [super awakeFromNib];
@ -131,13 +142,6 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
object:nil]; object:nil];
[self selectedInbox:self]; [self selectedInbox:self];
__weak SignalsViewController *weakSelf = self;
[[[Environment getCurrent] contactsManager].getObservableContacts watchLatestValue:^(id latestValue) {
[weakSelf.tableView reloadData];
}
onThread:[NSThread mainThread]
untilCancelled:nil];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[ self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[
NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil), NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil),
NSLocalizedString(@"ARCHIVE_NAV_BAR_TITLE", nil) NSLocalizedString(@"ARCHIVE_NAV_BAR_TITLE", nil)

@ -8,14 +8,10 @@
#import <SignalServiceKit/PhoneNumber.h> #import <SignalServiceKit/PhoneNumber.h>
#import "CollapsingFutures.h" #import "CollapsingFutures.h"
#import "Contact.h" #import "Contact.h"
#import "ObservableValue.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification; extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
// TODO: Remove this.
// TODO: Remove observableContactsController.
extern NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification;
@class UIFont; @class UIFont;
@class SignalAccount; @class SignalAccount;
@ -33,8 +29,6 @@ extern NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification;
@property (atomic, readonly) NSDictionary<NSString *, SignalAccount *> *signalAccountMap; @property (atomic, readonly) NSDictionary<NSString *, SignalAccount *> *signalAccountMap;
@property (atomic, readonly) NSArray<SignalAccount *> *signalAccounts; @property (atomic, readonly) NSArray<SignalAccount *> *signalAccounts;
- (nonnull ObservableValue *)getObservableContacts;
- (nullable SignalAccount *)signalAccountForRecipientId:(nullable NSString *)recipientId; - (nullable SignalAccount *)signalAccountForRecipientId:(nullable NSString *)recipientId;
- (Contact *)getOrBuildContactForPhoneIdentifier:(NSString *)identifier; - (Contact *)getOrBuildContactForPhoneIdentifier:(NSString *)identifier;

@ -15,16 +15,12 @@ typedef BOOL (^ContactSearchBlock)(id, NSUInteger, BOOL *);
NSString *const OWSContactsManagerSignalAccountsDidChangeNotification = NSString *const OWSContactsManagerSignalAccountsDidChangeNotification =
@"OWSContactsManagerSignalAccountsDidChangeNotification"; @"OWSContactsManagerSignalAccountsDidChangeNotification";
NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
@"OWSContactsManagerSignalRecipientsDidChangeNotification";
@interface OWSContactsManager () @interface OWSContactsManager ()
@property (atomic, nullable) CNContactStore *contactStore; @property (atomic, nullable) CNContactStore *contactStore;
@property (atomic) id addressBookReference; @property (atomic) id addressBookReference;
@property (atomic) TOCFuture *futureAddressBook; @property (atomic) TOCFuture *futureAddressBook;
@property (atomic) ObservableValueController *observableContactsController;
@property (atomic) TOCCancelTokenSource *life;
@property (nonatomic) BOOL isContactsUpdateInFlight; @property (nonatomic) BOOL isContactsUpdateInFlight;
// This reflects the contents of the device phone book and includes // This reflects the contents of the device phone book and includes
// contacts that do not correspond to any signal account. // contacts that do not correspond to any signal account.
@ -37,18 +33,12 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
@implementation OWSContactsManager @implementation OWSContactsManager
- (void)dealloc {
[_life cancel];
}
- (id)init { - (id)init {
self = [super init]; self = [super init];
if (!self) { if (!self) {
return self; return self;
} }
_life = [TOCCancelTokenSource new];
_observableContactsController = [ObservableValueController observableValueControllerWithInitialValue:nil];
_avatarCache = [NSCache new]; _avatarCache = [NSCache new];
_allContacts = @[]; _allContacts = @[];
_signalAccountMap = @{}; _signalAccountMap = @{};
@ -74,14 +64,6 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification =
} }
[self setupAddressBookIfNecessary]; [self setupAddressBookIfNecessary];
__weak OWSContactsManager *weakSelf = self;
[self.observableContactsController watchLatestValueOnArbitraryThread:^(NSArray *latestContacts) {
@synchronized(self) {
[weakSelf updateSignalAccounts:latestContacts];
}
}
untilCancelled:_life.token];
} }
- (void)verifyABPermission { - (void)verifyABPermission {
@ -100,9 +82,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
- (void)handleAddressBookChanged - (void)handleAddressBookChanged
{ {
[self pullLatestAddressBook];
[self intersectContacts];
[self.avatarCache removeAllObjects]; [self.avatarCache removeAllObjects];
[self pullLatestAddressBook];
} }
#pragma mark - Setup #pragma mark - Setup
@ -155,7 +136,7 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
{ {
void (^success)() = ^{ void (^success)() = ^{
DDLogInfo(@"%@ Successfully intersected contacts.", self.tag); DDLogInfo(@"%@ Successfully intersected contacts.", self.tag);
[self fireSignalRecipientsDidChange]; [self updateSignalAccounts];
}; };
void (^failure)(NSError *error) = ^(NSError *error) { void (^failure)(NSError *error) = ^(NSError *error) {
if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain] if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain]
@ -179,70 +160,82 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
failure:failure]; failure:failure];
} }
- (void)fireSignalRecipientsDidChange
{
AssertIsOnMainThread();
[[NSNotificationCenter defaultCenter] postNotificationName:OWSContactsManagerSignalRecipientsDidChangeNotification
object:nil];
}
- (void)pullLatestAddressBook { - (void)pullLatestAddressBook {
CFErrorRef creationError = nil; dispatch_async(ADDRESSBOOK_QUEUE, ^{
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError); CFErrorRef creationError = nil;
checkOperationDescribe(nil == creationError, [((__bridge NSError *)creationError)localizedDescription]); ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError);
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { checkOperationDescribe(nil == creationError, [((__bridge NSError *)creationError)localizedDescription]);
if (!granted) { ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
[OWSContactsManager blockingContactDialog]; if (!granted) {
} [OWSContactsManager blockingContactDialog];
}
});
NSArray<Contact *> *contacts = [self getContactsFromAddressBook:addressBookRef];
[self updateWithContacts:contacts];
}); });
[self.observableContactsController updateValue:[self getContactsFromAddressBook:addressBookRef]];
} }
- (void)updateSignalAccounts:(NSArray<Contact *> *)contacts - (void)updateWithContacts:(NSArray<Contact *> *)contacts
{ {
// This will happen off of the main thread. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableDictionary<NSString *, SignalAccount *> *signalAccountMap = [NSMutableDictionary new]; NSMutableDictionary<NSString *, Contact *> *allContactsMap = [NSMutableDictionary new];
NSMutableArray<SignalAccount *> *signalAccounts = [NSMutableArray new]; for (Contact *contact in contacts) {
NSMutableDictionary<NSString *, Contact *> *allContactsMap = [NSMutableDictionary new]; for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
for (Contact *contact in contacts) { NSString *phoneNumberE164 = phoneNumber.toE164;
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { if (phoneNumberE164.length > 0) {
NSString *phoneNumberE164 = phoneNumber.toE164; allContactsMap[phoneNumberE164] = contact;
if (phoneNumberE164.length > 0) { }
allContactsMap[phoneNumberE164] = contact;
} }
} }
NSArray<SignalRecipient *> *signalRecipients = contact.signalRecipients; dispatch_async(dispatch_get_main_queue(), ^{
for (SignalRecipient *signalRecipient in contact.signalRecipients) { self.allContacts = contacts;
for (NSString *recipientId in self.allContactsMap = [allContactsMap copy];
[contact.textSecureIdentifiers sortedArrayUsingSelector:@selector(compare:)]) {
SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; [self intersectContacts];
signalAccount.contact = contact;
if (signalRecipients.count > 1) { [self updateSignalAccounts];
signalAccount.isMultipleAccountContact = YES; });
signalAccount.multipleAccountLabel = });
[[self class] accountLabelForContact:contact recipientId:recipientId]; }
}
if (signalAccountMap[signalAccount.recipientId]) { - (void)updateSignalAccounts
DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); {
continue; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableDictionary<NSString *, SignalAccount *> *signalAccountMap = [NSMutableDictionary new];
NSMutableArray<SignalAccount *> *signalAccounts = [NSMutableArray new];
NSArray<Contact *> *contacts = self.allContacts;
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (Contact *contact in contacts) {
NSArray<SignalRecipient *> *signalRecipients = [contact signalRecipientsWithTransaction:transaction];
for (SignalRecipient *signalRecipient in
[signalRecipients sortedArrayUsingSelector:@selector(compare:)]) {
SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient];
signalAccount.contact = contact;
if (signalRecipients.count > 1) {
signalAccount.isMultipleAccountContact = YES;
signalAccount.multipleAccountLabel =
[[self class] accountLabelForContact:contact recipientId:signalRecipient.recipientId];
}
if (signalAccountMap[signalAccount.recipientId]) {
DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName);
continue;
}
signalAccountMap[signalAccount.recipientId] = signalAccount;
[signalAccounts addObject:signalAccount];
} }
signalAccountMap[signalAccount.recipientId] = signalAccount;
[signalAccounts addObject:signalAccount];
} }
} }];
}
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.allContacts = contacts; self.signalAccountMap = [signalAccountMap copy];
self.signalAccountMap = [signalAccountMap copy]; self.signalAccounts = [signalAccounts copy];
self.signalAccounts = [signalAccounts copy];
self.allContactsMap = [allContactsMap copy];
[[NSNotificationCenter defaultCenter] postNotificationName:OWSContactsManagerSignalAccountsDidChangeNotification [[NSNotificationCenter defaultCenter]
object:nil]; postNotificationName:OWSContactsManagerSignalAccountsDidChangeNotification
object:nil];
});
}); });
} }
@ -371,12 +364,6 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
} }
} }
#pragma mark - Observables
- (ObservableValue *)getObservableContacts {
return self.observableContactsController;
}
#pragma mark - Address Book utils #pragma mark - Address Book utils
+ (TOCFuture *)asyncGetAddressBook { + (TOCFuture *)asyncGetAddressBook {
@ -405,8 +392,10 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
return futureAddressBookSource.future; return futureAddressBookSource.future;
} }
- (NSArray *)getContactsFromAddressBook:(ABAddressBookRef _Nonnull)addressBook { - (NSArray<Contact *> *)getContactsFromAddressBook:(ABAddressBookRef _Nonnull)addressBook
{
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFMutableArrayRef allPeopleMutable = CFMutableArrayRef allPeopleMutable =
CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(allPeople), allPeople); CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(allPeople), allPeople);

@ -44,16 +44,26 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey =
OWSSingletonAssert(); OWSSingletonAssert();
__weak OWSContactsSyncing *weakSelf = self; [[NSNotificationCenter defaultCenter] addObserver:self
[contactsManager.getObservableContacts watchLatestValue:^(id latestValue) { selector:@selector(signalAccountsDidChange:)
[weakSelf sendSyncContactsMessageIfPossible]; name:OWSContactsManagerSignalAccountsDidChangeNotification
} object:nil];
onThread:[NSThread mainThread]
untilCancelled:nil];
return self; return self;
} }
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)signalAccountsDidChange:(id)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self sendSyncContactsMessageIfPossible];
});
}
#pragma mark - Methods #pragma mark - Methods
- (void)sendSyncContactsMessageIfNecessary - (void)sendSyncContactsMessageIfNecessary

Loading…
Cancel
Save