Reworking observation of Contact and SignalAccount changes.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-05-01 14:10:53 -04:00
parent 994aec0d86
commit ad11c50c1b
5 changed files with 99 additions and 101 deletions

View File

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

View File

@ -93,6 +93,10 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
selector:@selector(blockedPhoneNumbersDidChange:)
name:kNSNotificationName_BlockedPhoneNumbersDidChange
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(signalAccountsDidChange:)
name:OWSContactsManagerSignalAccountsDidChangeNotification
object:nil];
}
- (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
{
[super awakeFromNib];
@ -131,13 +142,6 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
object:nil];
[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:@[
NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil),
NSLocalizedString(@"ARCHIVE_NAV_BAR_TITLE", nil)

View File

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

View File

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

View File

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