Reworking observation of Contact and SignalAccount changes.
// FREEBIE
This commit is contained in:
parent
994aec0d86
commit
ad11c50c1b
|
@ -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];
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue