From 3754b6f264ee0b921369241de3f72452d028d351 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Tue, 9 May 2017 17:55:18 -0400 Subject: [PATCH] Edit 1:1 contact details // FREEBIE --- .../src/ViewControllers/ContactsViewHelper.h | 13 +++ .../src/ViewControllers/ContactsViewHelper.m | 93 ++++++++++++++++++- ...SConversationSettingsTableViewController.m | 64 ++++++++++++- .../ShowGroupMembersViewController.m | 87 +++-------------- .../translations/en.lproj/Localizable.strings | 3 + 5 files changed, 182 insertions(+), 78 deletions(-) diff --git a/Signal/src/ViewControllers/ContactsViewHelper.h b/Signal/src/ViewControllers/ContactsViewHelper.h index 263675d75..bc9e1088d 100644 --- a/Signal/src/ViewControllers/ContactsViewHelper.h +++ b/Signal/src/ViewControllers/ContactsViewHelper.h @@ -7,15 +7,24 @@ NS_ASSUME_NONNULL_BEGIN @class ContactsViewHelper; @class Contact; @class SignalAccount; +@protocol CNContactViewControllerDelegate; @protocol ContactsViewHelperDelegate - (void)contactsViewHelperDidUpdateContacts; +@optional + - (BOOL)shouldHideLocalNumber; @end +@protocol ContactEditingDelegate + +- (void)didFinishEditingContact; + +@end + #pragma mark - @class OWSContactsManager; @@ -46,6 +55,10 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)nonSignalContactsMatchingSearchString:(NSString *)searchText; +- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId + fromViewController:(UIViewController *)fromViewController + editImmediately:(BOOL)shouldEditImmediately; + @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/ContactsViewHelper.m b/Signal/src/ViewControllers/ContactsViewHelper.m index 1f0e9c787..5990e1ae1 100644 --- a/Signal/src/ViewControllers/ContactsViewHelper.m +++ b/Signal/src/ViewControllers/ContactsViewHelper.m @@ -5,12 +5,15 @@ #import "ContactsViewHelper.h" #import "ContactTableViewCell.h" #import "Environment.h" +#import "Signal-Swift.h" #import #import #import #import #import +@import ContactsUI; + NS_ASSUME_NONNULL_BEGIN @interface ContactsViewHelper () @@ -95,7 +98,10 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert([NSThread isMainThread]); - if ([self.delegate shouldHideLocalNumber] && [self isCurrentUser:signalAccount]) { + + if ([self.delegate respondsToSelector:@selector(shouldHideLocalNumber)] && [self.delegate shouldHideLocalNumber] && + [self isCurrentUser:signalAccount]) { + return YES; } @@ -277,6 +283,91 @@ NS_ASSUME_NONNULL_BEGIN return _nonSignalContacts; } +#pragma mark - Editing + +- (void)presentContactViewControllerForRecipientId:(NSString *)recipientId + fromViewController:(UIViewController *)fromViewController + editImmediately:(BOOL)shouldEditImmediately +{ + SignalAccount *signalAccount = [self signalAccountForRecipientId:recipientId]; + + if (!self.contactsManager.isSystemContactsAuthorized) { + UIAlertController *alertController = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_TITLE", comment + : @"Alert title for when the user has just tried to edit a " + @"contacts after declining to give Signal contacts " + @"permissions") + message:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY", comment + : @"Alert body for when the user has just tried to edit a " + @"contacts after declining to give Signal contacts " + @"permissions") + preferredStyle:UIAlertControllerStyleAlert]; + + [alertController + addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_ACTION_NOT_NOW", + @"Button text to dismiss missing contacts permission alert") + style:UIAlertActionStyleCancel + handler:nil]]; + + [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OPEN_SETTINGS_BUTTON", + @"Button text which opens the settings app") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + [[UIApplication sharedApplication] openSystemSettings]; + }]]; + + [fromViewController presentViewController:alertController animated:YES completion:nil]; + return; + } + + CNContactViewController *_Nullable contactViewController; + if (signalAccount) { + CNContact *_Nullable cnContact = signalAccount.contact.cnContact; + if (cnContact) { + if (shouldEditImmediately) { + // Not acutally a "new" contact, but this brings up the edit form rather than the "Read" form + // saving our users a tap in some cases when we already know they want to edit. + contactViewController = [CNContactViewController viewControllerForNewContact:cnContact]; + } else { + contactViewController = [CNContactViewController viewControllerForContact:cnContact]; + } + } + } + + if (!contactViewController) { + CNMutableContact *newContact = [CNMutableContact new]; + CNPhoneNumber *phoneNumber = [CNPhoneNumber phoneNumberWithStringValue:recipientId]; + CNLabeledValue *labeledPhoneNumber = + [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain value:phoneNumber]; + newContact.phoneNumbers = @[ labeledPhoneNumber ]; + + contactViewController = [CNContactViewController viewControllerForNewContact:newContact]; + } + + contactViewController.delegate = fromViewController; + contactViewController.allowsActions = NO; + contactViewController.allowsEditing = YES; + contactViewController.navigationItem.leftBarButtonItem = + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil) + style:UIBarButtonItemStylePlain + target:fromViewController + action:@selector(didFinishEditingContact)]; + + UINavigationController *navigationController = + [[UINavigationController alloc] initWithRootViewController:contactViewController]; + + // We want the presentation to imply a "replacement" in this case. + if (shouldEditImmediately) { + navigationController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + } + [fromViewController presentViewController:navigationController animated:YES completion:nil]; + + // HACK otherwise CNContactViewController Navbar is shown as black. + // RADAR rdar://28433898 http://www.openradar.me/28433898 + // CNContactViewController incompatible with opaque navigation bar + [UIUtil applyDefaultSystemAppearence]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/OWSConversationSettingsTableViewController.m b/Signal/src/ViewControllers/OWSConversationSettingsTableViewController.m index e64b503a6..1554207c0 100644 --- a/Signal/src/ViewControllers/OWSConversationSettingsTableViewController.m +++ b/Signal/src/ViewControllers/OWSConversationSettingsTableViewController.m @@ -4,6 +4,7 @@ #import "OWSConversationSettingsTableViewController.h" #import "BlockListUIUtils.h" +#import "ContactsViewHelper.h" #import "Environment.h" #import "FingerprintViewController.h" #import "OWSAvatarBuilder.h" @@ -29,9 +30,11 @@ #import #import +@import ContactsUI; + NS_ASSUME_NONNULL_BEGIN -@interface OWSConversationSettingsTableViewController () +@interface OWSConversationSettingsTableViewController () @property (nonatomic) TSThread *thread; @@ -42,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) OWSContactsManager *contactsManager; @property (nonatomic, readonly) OWSMessageSender *messageSender; @property (nonatomic, readonly) OWSBlockingManager *blockingManager; - +@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; @property (nonatomic, readonly) UIImageView *avatarView; @property (nonatomic, readonly) UILabel *disappearingMessagesDurationLabel; @@ -93,6 +96,8 @@ NS_ASSUME_NONNULL_BEGIN _contactsManager = [Environment getCurrent].contactsManager; _messageSender = [Environment getCurrent].messageSender; _blockingManager = [OWSBlockingManager sharedManager]; + _contactsViewHelper = [ContactsViewHelper new]; + _contactsViewHelper.delegate = self; } - (NSString *)threadName @@ -115,6 +120,58 @@ NS_ASSUME_NONNULL_BEGIN - (void)configureWithThread:(TSThread *)thread { self.thread = thread; + [self updateEditButton]; +} + +- (void)updateEditButton +{ + OWSAssert(self.thread); + + if ([self.thread isKindOfClass:[TSContactThread class]]) { + self.navigationItem.rightBarButtonItem = + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"EDIT_TXT", nil) + style:UIBarButtonItemStylePlain + target:self + action:@selector(didTapEditButton)]; + } +} + +- (void)didTapEditButton +{ + if (![self.thread isKindOfClass:[TSContactThread class]]) { + DDLogError(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__); + OWSAssert(NO); + return; + } + + TSContactThread *contactThread = (TSContactThread *)self.thread; + [self.contactsViewHelper presentContactViewControllerForRecipientId:contactThread.contactIdentifier + fromViewController:self + editImmediately:YES]; +} + +#pragma mark - ContactEditingDelegate + +- (void)didFinishEditingContact +{ + DDLogDebug(@"%@ %s", self.tag, __PRETTY_FUNCTION__); + [self dismissViewControllerAnimated:YES completion:nil]; +} + +#pragma mark - CNContactViewControllerDelegate + +- (void)contactViewController:(CNContactViewController *)viewController + didCompleteWithContact:(nullable CNContact *)contact +{ + DDLogDebug(@"%@ done editing contact.", self.tag); + [self dismissViewControllerAnimated:YES completion:nil]; +} + +#pragma mark - ContactsViewHelperDelegate + +- (void)contactsViewHelperDidUpdateContacts +{ + [self updateTableContents]; } #pragma mark - View Lifecycle @@ -568,6 +625,9 @@ NS_ASSUME_NONNULL_BEGIN { [super viewWillAppear:animated]; + // In case we're dismissing a CNContactViewController which requires default system appearance + [UIUtil applySignalAppearence]; + // HACK to unselect rows when swiping back // http://stackoverflow.com/questions/19379510/uitableviewcell-doesnt-get-deselected-when-swiping-back-quickly [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated]; diff --git a/Signal/src/ViewControllers/ShowGroupMembersViewController.m b/Signal/src/ViewControllers/ShowGroupMembersViewController.m index 382cbb312..536bee6a5 100644 --- a/Signal/src/ViewControllers/ShowGroupMembersViewController.m +++ b/Signal/src/ViewControllers/ShowGroupMembersViewController.m @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface ShowGroupMembersViewController () +@interface ShowGroupMembersViewController () @property (nonatomic, readonly) TSGroupThread *thread; @property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; @@ -265,74 +265,9 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(recipientId.length > 0); - ContactsViewHelper *helper = self.contactsViewHelper; - SignalAccount *signalAccount = [helper signalAccountForRecipientId:recipientId]; - - if (!helper.contactsManager.isSystemContactsAuthorized) { - UIAlertController *alertController = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_TITLE", comment - : @"Alert title for when the user has just tried to edit a " - @"contacts after declining to give Signal contacts " - @"permissions") - message:NSLocalizedString(@"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY", comment - : @"Alert body for when the user has just tried to edit a " - @"contacts after declining to give Signal contacts " - @"permissions") - preferredStyle:UIAlertControllerStyleAlert]; - - [alertController - addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_ACTION_NOT_NOW", - @"Button text to dismiss missing contacts permission alert") - style:UIAlertActionStyleCancel - handler:nil]]; - - [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OPEN_SETTINGS_BUTTON", - @"Button text which opens the settings app") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [[UIApplication sharedApplication] openSystemSettings]; - }]]; - - [self presentViewController:alertController animated:YES completion:nil]; - return; - } - - CNContactViewController *_Nullable contactViewController; - if (signalAccount) { - CNContact *_Nullable cnContact = signalAccount.contact.cnContact; - if (cnContact) { - contactViewController = [CNContactViewController viewControllerForContact:cnContact]; - } - } - - if (!contactViewController) { - CNMutableContact *newContact = [CNMutableContact new]; - CNPhoneNumber *phoneNumber = [CNPhoneNumber phoneNumberWithStringValue:recipientId]; - CNLabeledValue *labeledPhoneNumber = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain - value:phoneNumber]; - newContact.phoneNumbers = @[labeledPhoneNumber]; - - contactViewController = [CNContactViewController viewControllerForNewContact:newContact]; - } - - contactViewController.delegate = self; - contactViewController.allowsActions = NO; - contactViewController.allowsEditing = YES; - contactViewController.navigationItem.leftBarButtonItem = - [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil) - style:UIBarButtonItemStylePlain - target:self - action:@selector(dismissPressed)]; - - UINavigationController *navigationController = - [[UINavigationController alloc] initWithRootViewController:contactViewController]; - [self presentViewController:navigationController animated:YES completion:nil]; - - - // HACK otherwise CNContactViewController Navbar is shown as black. - // RADAR rdar://28433898 http://www.openradar.me/28433898 - // CNContactViewController incompatible with opaque navigation bar - [UIUtil applyDefaultSystemAppearence]; + [self.contactsViewHelper presentContactViewControllerForRecipientId:recipientId + fromViewController:self + editImmediately:NO]; } - (void)showConversationViewForRecipientId:(NSString *)recipientId @@ -347,12 +282,6 @@ NS_ASSUME_NONNULL_BEGIN [Environment callUserWithIdentifier:recipientId]; } -- (void)dismissPressed -{ - DDLogDebug(@"%@ %s", self.tag, __PRETTY_FUNCTION__); - [self dismissViewControllerAnimated:YES completion:nil]; -} - #pragma mark - ContactsViewHelperDelegate - (void)contactsViewHelperDidUpdateContacts @@ -365,6 +294,14 @@ NS_ASSUME_NONNULL_BEGIN return YES; } +#pragma mark - ContactEditingDelegate + +- (void)didFinishEditingContact +{ + DDLogDebug(@"%@ %s", self.tag, __PRETTY_FUNCTION__); + [self dismissViewControllerAnimated:YES completion:nil]; +} + #pragma mark - CNContactViewControllerDelegate - (void)contactViewController:(CNContactViewController *)viewController diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index acd93a650..f7342b6cb 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -364,6 +364,9 @@ /* Short name for edit menu item to share contents of media message. */ "EDIT_ITEM_SHARE_ACTION" = "Share"; +/* No comment provided by engineer. */ +"EDIT_TXT" = "Edit"; + /* body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to WhisperSystems home page}} */ "EMAIL_INVITE_BODY" = "Hey,\n\nLately I've been using Signal to keep the conversations on my iPhone private. I'd like you to install it too, so we can be confident that only you and I can read our messages or hear our calls.\n\nSignal is available for iPhones and Android. Get it here: %@\n\nSignal works like your existing messaging app. We can send pictures and video, make calls, and start group chats. The best part is, no one else can see any of it, not even the people who make Signal!\n\nYou can read more about Open Whisper Systems, the people who make Signal, here: %@";