Avoid repaint by requestng contacts before Compose

This entailed passing callback params through the contact request.

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent dc75e592c1
commit fee47efbea

@ -279,9 +279,18 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
- (IBAction)composeNew
{
MessageComposeTableViewController *viewController = [MessageComposeTableViewController new];
UINavigationController *navigationController =
[[UINavigationController alloc] initWithRootViewController:viewController];
[self presentTopLevelModalViewController:navigationController animateDismissal:YES animatePresentation:YES];
[self.contactsManager requestSystemContactsOnceWithCompletion:^(NSError *_Nullable error) {
DDLogError(@"%@ Error when requesting contacts: %@", self.tag, error);
// Even if there was an error fetching contacts we proceed to the next screen.
// As the compose view will present the proper thing depending on contact access.
//
// We just want to make sure contact access is *complete* before showing the compose
// screen to avoid flicker.
UINavigationController *navigationController =
[[UINavigationController alloc] initWithRootViewController:viewController];
[self presentTopLevelModalViewController:navigationController animateDismissal:YES animatePresentation:YES];
}];
}
- (void)swappedSegmentedControl {

@ -39,6 +39,7 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
// Request systems contacts and start syncing changes. The user will see an alert
// if they haven't previously.
- (void)requestSystemContactsOnce;
- (void)requestSystemContactsOnceWithCompletion:(void (^_Nullable)(NSError *_Nullable error))completion;
// Ensure's the app has the latest contacts, but won't prompt the user for contact
// access if they haven't granted it.

@ -54,9 +54,15 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification =
// Request contacts access if you haven't asked recently.
- (void)requestSystemContactsOnce
{
[self.systemContactsFetcher requestOnce];
[self requestSystemContactsOnceWithCompletion:nil];
}
- (void)requestSystemContactsOnceWithCompletion:(void (^_Nullable)(NSError *_Nullable error))completion
{
[self.systemContactsFetcher requestOnceWithCompletion:completion];
}
- (void)fetchSystemContactsIfAlreadyAuthorized
{
[self.systemContactsFetcher fetchIfAlreadyAuthorized];

@ -39,11 +39,19 @@ class SystemContactsFetcher: NSObject {
CNContactEmailAddressesKey as CNKeyDescriptor
]
public func requestOnce() {
/**
* Ensures we've requested access for system contacts. This can be used in multiple places,
* where we might need contact access, but will ensure we don't wastefully reload contacts
* if we have already fetched contacts.
*
* @param completion completion handler is called on main thread.
*/
public func requestOnce(completion: ((Error?) -> Void)?) {
AssertIsOnMainThread()
guard !systemContactsHaveBeenRequestedAtLeastOnce else {
Logger.debug("\(TAG) already requested system contacts")
completion?(nil)
return
}
systemContactsHaveBeenRequestedAtLeastOnce = true
@ -54,22 +62,32 @@ class SystemContactsFetcher: NSObject {
contactStore.requestAccess(for: .contacts) { (granted, error) in
if let error = error {
Logger.error("\(self.TAG) error fetching contacts: \(error)")
assertionFailure()
DispatchQueue.main.async {
completion?(error)
}
}
guard granted else {
Logger.info("\(self.TAG) declined contact access.")
// This case should have been caught be the error guard a few lines up.
assertionFailure()
DispatchQueue.main.async {
completion?(nil)
}
return
}
DispatchQueue.main.async {
self.updateContacts()
self.updateContacts(completion: completion)
}
}
case .authorized:
self.updateContacts()
self.updateContacts(completion: completion)
case .denied, .restricted:
Logger.debug("\(TAG) contacts were \(self.authorizationStatus)")
DispatchQueue.main.async {
completion?(nil)
}
}
}
@ -79,10 +97,10 @@ class SystemContactsFetcher: NSObject {
return
}
updateContacts()
updateContacts(completion: nil)
}
private func updateContacts() {
private func updateContacts(completion: ((Error?) -> Void)?) {
AssertIsOnMainThread()
systemContactsHaveBeenRequestedAtLeastOnce = true
@ -100,11 +118,16 @@ class SystemContactsFetcher: NSObject {
} catch let error as NSError {
Logger.error("\(self.TAG) Failed to fetch contacts with error:\(error)")
assertionFailure()
DispatchQueue.main.async {
completion?(error)
}
return
}
let contacts = systemContacts.map { Contact(systemContact: $0) }
DispatchQueue.main.async {
self.delegate?.systemContactsFetcher(self, updatedContacts: contacts)
completion?(nil)
}
}
}
@ -118,7 +141,7 @@ class SystemContactsFetcher: NSObject {
@objc
private func contactStoreDidChange() {
updateContacts()
updateContacts(completion: nil)
}
}

Loading…
Cancel
Save