Add contact view.

pull/1/head
Matthew Chen 7 years ago
parent fa5577eece
commit 91d54360ba

@ -7,6 +7,7 @@ import SignalServiceKit
import SignalMessaging
import Reachability
import ContactsUI
import MessageUI
class TappableView: UIView {
let actionBlock : (() -> Void)
@ -38,9 +39,7 @@ class TappableView: UIView {
// MARK: -
class ContactViewController: OWSViewController, CNContactViewControllerDelegate
//, ContactsViewHelperDelegate
{
class ContactViewController: OWSViewController, CNContactViewControllerDelegate {
let TAG = "[ContactView]"
@ -74,8 +73,6 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
private let contact: OWSContact
// private var contactsViewHelper : ContactsViewHelper!
// MARK: - Initializers
@available(*, unavailable, message: "use init(call:) constructor instead.")
@ -90,8 +87,6 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
super.init(nibName: nil, bundle: nil)
// contactsViewHelper = ContactsViewHelper(delegate:self)
tryToDetermineMode()
NotificationCenter.default.addObserver(forName: .OWSContactsManagerSignalAccountsDidChange, object: nil, queue: nil) { [weak self] _ in
@ -137,14 +132,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
private var scrollView: UIScrollView
override func loadView() {
// scrollView.dir
// self.view = scrollView
// let rootView = UIView()
super.loadView()
// self.view.layoutMargins = .zero
// self.scrollView = scrollView
// scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(scrollView)
scrollView.layoutMargins = .zero
scrollView.autoPinWidthToSuperview()
@ -161,18 +150,15 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
private func tryToDetermineMode() {
SwiftAssertIsOnMainThread(#function)
guard let firstPhoneNumber = contact.phoneNumbers?.first else {
guard phoneNumbersForContact().count > 0 else {
viewMode = .noPhoneNumber
return
}
if contactsManager.hasSignalAccount(forRecipientId: firstPhoneNumber.phoneNumber) {
if systemContactsWithSignalAccountsForContact().count > 0 {
viewMode = .systemContactWithSignal
return
}
if contactsManager.allContactsMap[firstPhoneNumber.phoneNumber] != nil {
// We can infer that this is _not_ a signal user because
// all contacts in contactsManager.allContactsMap have
// already been looked up.
if systemContactsForContact().count > 0 {
viewMode = .systemContactWithoutSignal
return
}
@ -180,6 +166,34 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
viewMode = .nonSystemContact
}
private func systemContactsWithSignalAccountsForContact() -> [String] {
SwiftAssertIsOnMainThread(#function)
return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in
return contactsManager.hasSignalAccount(forRecipientId: phoneNumber)
})
}
private func systemContactsForContact() -> [String] {
SwiftAssertIsOnMainThread(#function)
return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in
return contactsManager.allContactsMap[phoneNumber] != nil
})
}
private func phoneNumbersForContact() -> [String] {
SwiftAssertIsOnMainThread(#function)
var result = [String]()
if let phoneNumbers = contact.phoneNumbers {
for phoneNumber in phoneNumbers {
result.append(phoneNumber.phoneNumber)
}
}
return result
}
private func tryToDetermineModeRetry() {
// Try again after a minute.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 60.0) { [weak self] in
@ -212,21 +226,21 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
avatarView.backgroundColor = UIColor.ows_materialBlue
avatarView.layer.cornerRadius = avatarSize * 0.5
topView.addSubview(avatarView)
avatarView.autoPin(toTopLayoutGuideOf: self, withInset: 10)
avatarView.autoPin(toTopLayoutGuideOf: self, withInset: 20)
avatarView.autoHCenterInSuperview()
avatarView.autoSetDimension(.width, toSize: avatarSize)
avatarView.autoSetDimension(.height, toSize: avatarSize)
let nameLabel = UILabel()
nameLabel.text = contact.displayName
nameLabel.font = UIFont.ows_dynamicTypeTitle1
nameLabel.font = UIFont.ows_dynamicTypeTitle2.ows_bold()
nameLabel.textColor = UIColor.black
nameLabel.lineBreakMode = .byTruncatingTail
nameLabel.textAlignment = .center
topView.addSubview(nameLabel)
nameLabel.autoPinEdge(.top, to: .bottom, of: avatarView, withOffset: 10)
nameLabel.autoPinLeadingToSuperviewMargin()
nameLabel.autoPinTrailingToSuperviewMargin()
nameLabel.autoPinLeadingToSuperviewMargin(withInset: hMargin)
nameLabel.autoPinTrailingToSuperviewMargin(withInset: hMargin)
var lastView: UIView = nameLabel
@ -239,18 +253,53 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
phoneNumberLabel.textAlignment = .center
topView.addSubview(phoneNumberLabel)
phoneNumberLabel.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 5)
phoneNumberLabel.autoPinLeadingToSuperviewMargin()
phoneNumberLabel.autoPinTrailingToSuperviewMargin()
phoneNumberLabel.autoPinLeadingToSuperviewMargin(withInset: hMargin)
phoneNumberLabel.autoPinTrailingToSuperviewMargin(withInset: hMargin)
lastView = phoneNumberLabel
}
switch viewMode {
case .systemContactWithSignal:
// Show actions buttons for system contacts with a Signal account.
break
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_SEND_MESSAGE",
comment: "Label for 'sent message' button in contact view."),
actionBlock: { [weak self] _ in
guard let strongSelf = self else { return }
strongSelf.didPressSendMessage()
}))
stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_AUDIO_CALL",
comment: "Label for 'audio call' button in contact view."),
actionBlock: { [weak self] _ in
guard let strongSelf = self else { return }
strongSelf.didPressAudioCall()
}))
stackView.addArrangedSubview(createCircleActionButton(text: NSLocalizedString("ACTION_VIDEO_CALL",
comment: "Label for 'video call' button in contact view."),
actionBlock: { [weak self] _ in
guard let strongSelf = self else { return }
strongSelf.didPressVideoCall()
}))
topView.addSubview(stackView)
stackView.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 20)
stackView.autoPinLeadingToSuperviewMargin(withInset: hMargin)
stackView.autoPinTrailingToSuperviewMargin(withInset: hMargin)
lastView = stackView
case .systemContactWithoutSignal:
// Show invite button for system contacts without a Signal account.
break
let inviteButton = createLargePillButton(text: NSLocalizedString("ACTION_INVITE",
comment: "Label for 'invite' button in contact view."),
actionBlock: { [weak self] _ in
guard let strongSelf = self else { return }
strongSelf.didPressInvite()
})
topView.addSubview(inviteButton)
inviteButton.autoPinEdge(.top, to: .bottom, of: lastView, withOffset: 20)
inviteButton.autoPinLeadingToSuperviewMargin(withInset: 55)
inviteButton.autoPinTrailingToSuperviewMargin(withInset: 55)
lastView = inviteButton
case .nonSystemContact:
// Show no action buttons for contacts not in user's device contacts.
break
@ -363,12 +412,15 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
lastRow?.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0)
}
private let hMargin = CGFloat(10)
private let hMargin = CGFloat(16)
private func createActionRow(labelText: String, action: Selector) -> UIView {
let row = UIView()
row.layoutMargins.left = 0
row.layoutMargins.right = 0
row.isUserInteractionEnabled = true
row.addGestureRecognizer(UITapGestureRecognizer(target: self, action: action))
let label = UILabel()
label.text = labelText
label.font = UIFont.ows_dynamicTypeBody
@ -379,11 +431,14 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
label.autoPinBottomToSuperviewMargin()
label.autoPinLeadingToSuperviewMargin(withInset: hMargin)
label.autoPinTrailingToSuperviewMargin(withInset: hMargin)
return row
}
private func createNameValueRow(name: String, value: String, actionBlock : @escaping () -> Void) -> UIView {
let row = TappableView(actionBlock: actionBlock)
row.layoutMargins.left = 0
row.layoutMargins.right = 0
let nameLabel = UILabel()
nameLabel.text = name
@ -411,46 +466,60 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
return row
}
// acceptIncomingButton = createButton(image: #imageLiteral(resourceName: "call-active-wide"),
// action: #selector(didPressAnswerCall))
// acceptIncomingButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_ACCEPT_INCOMING_CALL_LABEL",
// comment: "Accessibility label for accepting incoming calls")
// func createButton(image: UIImage, action: Selector) -> UIButton {
// let button = UIButton()
// button.setImage(image, for: .normal)
// button.imageEdgeInsets = UIEdgeInsets(top: buttonInset(),
// left: buttonInset(),
// bottom: buttonInset(),
// right: buttonInset())
// button.addTarget(self, action: action, for: .touchUpInside)
// button.autoSetDimension(.width, toSize: buttonSize())
// button.autoSetDimension(.height, toSize: buttonSize())
// return button
// }
//
// // MARK: - Layout
//
// TODO: Use real assets.
private func createCircleActionButton(text: String, actionBlock : @escaping () -> Void) -> UIView {
let buttonSize = CGFloat(50)
//
// func didPressFlipCamera(sender: UIButton) {
// // toggle value
// sender.isSelected = !sender.isSelected
//
// let useBackCamera = sender.isSelected
// Logger.info("\(TAG) in \(#function) with useBackCamera: \(useBackCamera)")
//
// callUIAdapter.setCameraSource(call: call, useBackCamera: useBackCamera)
// }
//
// internal func dismissImmediately(completion: (() -> Void)?) {
// if ContactView.kShowCallViewOnSeparateWindow {
// OWSWindowManager.shared().endCall(self)
// completion?()
// } else {
// self.dismiss(animated: true, completion: completion)
// }
// }
let button = TappableView(actionBlock: actionBlock)
button.layoutMargins = .zero
button.autoSetDimension(.width, toSize: buttonSize, relation: .greaterThanOrEqual)
let circleView = UIView()
circleView.backgroundColor = UIColor.white
circleView.autoSetDimension(.width, toSize: buttonSize)
circleView.autoSetDimension(.height, toSize: buttonSize)
circleView.layer.cornerRadius = buttonSize * 0.5
button.addSubview(circleView)
circleView.autoPinEdge(toSuperviewEdge: .top)
circleView.autoHCenterInSuperview()
let label = UILabel()
label.text = text
label.font = UIFont.ows_dynamicTypeCaption2
label.textColor = UIColor.black
label.lineBreakMode = .byTruncatingTail
label.textAlignment = .center
button.addSubview(label)
label.autoPinEdge(.top, to: .bottom, of: circleView, withOffset: 3)
label.autoPinEdge(toSuperviewEdge: .bottom)
label.autoPinLeadingToSuperviewMargin()
label.autoPinTrailingToSuperviewMargin()
return button
}
private func createLargePillButton(text: String, actionBlock : @escaping () -> Void) -> UIView {
let button = TappableView(actionBlock: actionBlock)
button.backgroundColor = UIColor.white
button.layoutMargins = .zero
button.autoSetDimension(.height, toSize: 45)
button.layer.cornerRadius = 5
let label = UILabel()
label.text = text
label.font = UIFont.ows_dynamicTypeCaption1
label.textColor = UIColor.ows_materialBlue
label.lineBreakMode = .byTruncatingTail
label.textAlignment = .center
button.addSubview(label)
label.autoPinLeadingToSuperviewMargin(withInset: 20)
label.autoPinTrailingToSuperviewMargin(withInset: 20)
label.autoVCenterInSuperview()
label.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual)
label.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0, relation: .greaterThanOrEqual)
return button
}
func didPressCreateNewContact(sender: UIGestureRecognizer) {
Logger.info("\(self.TAG) \(#function)")
@ -479,14 +548,64 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
// TODO:
}
// MARK: - ContactsViewHelperDelegate
func didPressSendMessage() {
Logger.info("\(self.TAG) \(#function)")
// @objc
// public func contactsViewHelperDidUpdateContacts() {
// Logger.info("\(self.TAG) \(#function)")
//
// // Do nothing
// }
// TODO: We're taking the first Signal account id. We might
// want to let the user select if there's more than one.
guard let recipientId = systemContactsWithSignalAccountsForContact().first else {
owsFail("\(logTag) missing Signal recipient id.")
return
}
SignalApp.shared().presentConversation(forRecipientId: recipientId, action: .compose)
}
func didPressAudioCall() {
Logger.info("\(self.TAG) \(#function)")
// TODO: We're taking the first Signal account id. We might
// want to let the user select if there's more than one.
guard let recipientId = systemContactsWithSignalAccountsForContact().first else {
owsFail("\(logTag) missing Signal recipient id.")
return
}
SignalApp.shared().presentConversation(forRecipientId: recipientId, action: .audioCall)
}
func didPressVideoCall() {
Logger.info("\(self.TAG) \(#function)")
// TODO: We're taking the first Signal account id. We might
// want to let the user select if there's more than one.
guard let recipientId = systemContactsWithSignalAccountsForContact().first else {
owsFail("\(logTag) missing Signal recipient id.")
return
}
SignalApp.shared().presentConversation(forRecipientId: recipientId, action: .videoCall)
}
func didPressInvite() {
Logger.info("\(self.TAG) \(#function)")
guard MFMessageComposeViewController.canSendText() else {
Logger.info("\(TAG) Device cannot send text")
OWSAlerts.showErrorAlert(message: NSLocalizedString("UNSUPPORTED_FEATURE_ERROR", comment: ""))
return
}
let phoneNumbers =
phoneNumbersForContact()
guard phoneNumbers.count > 0 else {
owsFail("\(logTag) no phone numbers.")
return
}
let inviteFlow =
InviteFlow(presentingViewController: self, contactsManager: contactsManager)
inviteFlow.sendSMSTo(phoneNumbers: phoneNumbers)
}
// MARK: -
@ -495,13 +614,6 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
owsFail("\(self.logTag) Contact editing not supported")
return
}
// contactsViewHelper.presentContactViewController
// let contactsViewHelper = ContactsViewHelper(delegate:self)
//
// TSContactThread *contactThread = (TSContactThread *)self.thread;
// [self.contactsViewHelper presentContactViewControllerForRecipientId:contactThread.contactIdentifier
// fromViewController:self
// editImmediately:YES];
guard let systemContact = OWSContacts.systemContact(for: contact) else {
owsFail("\(self.logTag) Could not derive system contact.")
@ -537,11 +649,6 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
return
}
guard let systemContact = OWSContacts.systemContact(for: contact) else {
owsFail("\(self.logTag) Could not derive system contact.")
return
}
guard contactsManager.isSystemContactsAuthorized else {
ContactsViewHelper.presentMissingContactAccessAlertController(from: self)
return
@ -552,6 +659,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
return
}
// TODO: We need to modify OWSAddToContactViewController to take a OWSContact
// and merge it with an existing CNContact.
let viewController = OWSAddToContactViewController()
viewController.configure(withRecipientId: firstPhoneNumber.phoneNumber)
self.navigationController?.pushViewController(viewController, animated: true)

@ -6,15 +6,20 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, ConversationViewAction) {
ConversationViewActionNone,
ConversationViewActionCompose,
ConversationViewActionAudioCall,
ConversationViewActionVideoCall,
};
@class TSThread;
@interface ConversationViewController : OWSViewController
@property (nonatomic, readonly) TSThread *thread;
- (void)configureForThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing;
- (void)configureForThread:(TSThread *)thread action:(ConversationViewAction)action;
- (void)popKeyBoard;

@ -189,8 +189,7 @@ typedef enum : NSUInteger {
@property (nonatomic, readonly) NSUInteger backButtonUnreadCount;
@property (nonatomic) NSUInteger lastRangeLength;
@property (nonatomic) BOOL composeOnOpen;
@property (nonatomic) BOOL callOnOpen;
@property (nonatomic) ConversationViewAction actionOnOpen;
@property (nonatomic) BOOL peek;
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@ -396,7 +395,7 @@ typedef enum : NSUInteger {
- (void)peekSetup
{
_peek = YES;
[self setComposeOnOpen:NO];
self.actionOnOpen = ConversationViewActionNone;
}
- (void)popped
@ -405,21 +404,11 @@ typedef enum : NSUInteger {
[self hideInputIfNeeded];
}
- (void)configureForThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing
- (void)configureForThread:(TSThread *)thread action:(ConversationViewAction)action
{
// At most one.
OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing);
if (callOnViewAppearing) {
keyboardOnViewAppearing = NO;
}
_thread = thread;
_isGroupConversation = [self.thread isKindOfClass:[TSGroupThread class]];
_composeOnOpen = keyboardOnViewAppearing;
_callOnOpen = callOnViewAppearing;
self.actionOnOpen = action;
_cellMediaCache = [NSCache new];
// Cache the cell media for ~24 cells.
self.cellMediaCache.countLimit = 24;
@ -1032,15 +1021,22 @@ typedef enum : NSUInteger {
[self updateNavigationBarSubtitleLabel];
[self updateBackButtonUnreadCount];
if (_composeOnOpen && !self.inputToolbar.hidden) {
[self popKeyBoard];
_composeOnOpen = NO;
}
if (_callOnOpen) {
[self callAction];
_callOnOpen = NO;
switch (self.actionOnOpen) {
case ConversationViewActionNone:
break;
case ConversationViewActionCompose:
[self popKeyBoard];
break;
case ConversationViewActionAudioCall:
[self audioCallAction];
break;
case ConversationViewActionVideoCall:
[self videoCallAction];
break;
}
self.actionOnOpen = ConversationViewActionNone;
self.isViewCompletelyAppeared = YES;
self.viewHasEverAppeared = YES;
@ -1227,7 +1223,7 @@ typedef enum : NSUInteger {
imageEdgeInsets.bottom = round(kBarButtonSize - (image.size.height + imageEdgeInsets.top));
callButton.imageEdgeInsets = imageEdgeInsets;
callButton.accessibilityLabel = NSLocalizedString(@"CALL_LABEL", "Accessibility label for placing call button");
[callButton addTarget:self action:@selector(callAction) forControlEvents:UIControlEventTouchUpInside];
[callButton addTarget:self action:@selector(audioCallAction) forControlEvents:UIControlEventTouchUpInside];
callButton.frame = CGRectMake(0,
0,
round(image.size.width + imageEdgeInsets.left + imageEdgeInsets.right),
@ -1362,7 +1358,17 @@ typedef enum : NSUInteger {
#pragma mark - Calls
- (void)callAction
- (void)audioCallAction
{
[self callWithVideo:NO];
}
- (void)videoCallAction
{
[self callWithVideo:YES];
}
- (void)callWithVideo:(BOOL)isVideo
{
OWSAssert([self.thread isKindOfClass:[TSContactThread class]]);
@ -1375,7 +1381,7 @@ typedef enum : NSUInteger {
if ([self isBlockedContactConversation]) {
[self showUnblockContactUI:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf callAction];
[weakSelf callWithVideo:isVideo];
}
}];
return;
@ -1385,14 +1391,14 @@ typedef enum : NSUInteger {
[self showSafetyNumberConfirmationIfNecessaryWithConfirmationText:[CallStrings confirmAndCallButtonTitle]
completion:^(BOOL didConfirmIdentity) {
if (didConfirmIdentity) {
[weakSelf callAction];
[weakSelf callWithVideo:isVideo];
}
}];
if (didShowSNAlert) {
return;
}
[self.outboundCallInitiator initiateCallWithRecipientId:self.thread.contactIdentifier];
[self.outboundCallInitiator initiateCallWithRecipientId:self.thread.contactIdentifier isVideo:isVideo];
}
- (BOOL)canCall
@ -1875,7 +1881,7 @@ typedef enum : NSUInteger {
UIAlertAction *callAction = [UIAlertAction actionWithTitle:[CallStrings callBackAlertCallButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[weakSelf callAction];
[weakSelf audioCallAction];
}];
[alertController addAction:callAction];
[alertController addAction:[OWSAlerts cancelAction]];

@ -3023,6 +3023,46 @@ typedef OWSContact * (^OWSContactBlock)(void);
// TODO: Avatar
return contact;
}]];
[actions addObject:[self fakeShareContactMessageAction:thread
label:@"Long values"
contactBlock:^{
OWSContact *contact = [OWSContact new];
contact.givenName = @"Bobasdjasdlkjasldkjas";
contact.familyName = @"Bobasdjasdlkjasldkjas";
OWSContactEmail *email = [OWSContactEmail new];
email.emailType = OWSContactEmailType_Mobile;
email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com";
contact.emails = @[
email,
];
return contact;
}]];
[actions addObject:[self fakeShareContactMessageAction:thread
label:@"System Contact w/o Signal"
contactBlock:^{
OWSContact *contact = [OWSContact new];
contact.givenName = @"Add Me To Your Contacts";
OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new];
phoneNumber.phoneType = OWSContactPhoneType_Work;
phoneNumber.phoneNumber = @"+324602053911";
contact.phoneNumbers = @[
phoneNumber,
];
return contact;
}]];
[actions addObject:[self fakeShareContactMessageAction:thread
label:@"System Contact w. Signal"
contactBlock:^{
OWSContact *contact = [OWSContact new];
contact.givenName = @"Add Me To Your Contacts";
OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new];
phoneNumber.phoneType = OWSContactPhoneType_Work;
phoneNumber.phoneNumber = @"+32460205392";
contact.phoneNumbers = @[
phoneNumber,
];
return contact;
}]];
return actions;
}

@ -2,6 +2,7 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "ConversationViewController.h"
#import <SignalMessaging/OWSViewController.h>
#import <UIKit/UIKit.h>
@ -9,9 +10,7 @@
@interface HomeViewController : OWSViewController
- (void)presentThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing;
- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action;
- (void)showNewConversationView;

@ -5,7 +5,6 @@
#import "HomeViewController.h"
#import "AppDelegate.h"
#import "AppSettingsViewController.h"
#import "ConversationViewController.h"
#import "HomeViewCell.h"
#import "NewContactThreadViewController.h"
#import "OWSNavigationController.h"
@ -387,7 +386,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
ConversationViewController *vc = [ConversationViewController new];
TSThread *thread = [self threadForIndexPath:indexPath];
self.lastThread = thread;
[vc configureForThread:thread keyboardOnViewAppearing:NO callOnViewAppearing:NO];
[vc configureForThread:thread action:ConversationViewActionNone];
[vc peekSetup];
return vc;
@ -916,17 +915,12 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
}
TSThread *thread = [self threadForIndexPath:indexPath];
[self presentThread:thread keyboardOnViewAppearing:NO callOnViewAppearing:NO];
[self presentThread:thread action:ConversationViewActionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)presentThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing
- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action
{
// At most one.
OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing);
if (thread == nil) {
OWSFail(@"Thread unexpectedly nil");
return;
@ -935,9 +929,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
// We do this synchronously if we're already on the main thread.
DispatchMainThreadSafe(^{
ConversationViewController *mvc = [ConversationViewController new];
[mvc configureForThread:thread
keyboardOnViewAppearing:keyboardOnViewAppearing
callOnViewAppearing:callOnViewAppearing];
[mvc configureForThread:thread action:action];
self.lastThread = thread;
[self pushTopLevelViewController:mvc animateDismissal:YES animatePresentation:YES];

@ -809,7 +809,8 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(thread != nil);
[self dismissViewControllerAnimated:YES
completion:^() {
[SignalApp.sharedApp presentConversationForThread:thread withCompose:YES];
[SignalApp.sharedApp presentConversationForThread:thread
action:ConversationViewActionCompose];
}];
}

@ -407,12 +407,12 @@ NS_ASSUME_NONNULL_BEGIN
{
OWSAssert(recipientId.length > 0);
[SignalApp.sharedApp presentConversationForRecipientId:recipientId withCompose:YES];
[SignalApp.sharedApp presentConversationForRecipientId:recipientId action:ConversationViewActionCompose];
}
- (void)callMember:(NSString *)recipientId
{
[SignalApp.sharedApp callRecipientId:recipientId];
[SignalApp.sharedApp presentConversationForRecipientId:recipientId action:ConversationViewActionAudioCall];
}
- (void)showSafetyNumberView:(NSString *)recipientId

@ -35,13 +35,14 @@ import SignalMessaging
return false
}
return initiateCall(recipientId: recipientId)
return initiateCall(recipientId: recipientId, isVideo: false)
}
/**
* |recipientId| is a e164 formatted phone number.
*/
public func initiateCall(recipientId: String) -> Bool {
public func initiateCall(recipientId: String,
isVideo: Bool) -> Bool {
// Rather than an init-assigned dependency property, we access `callUIAdapter` via Environment
// because it can change after app launch due to user settings
guard let callUIAdapter = SignalApp.shared().callUIAdapter else {
@ -58,7 +59,7 @@ import SignalMessaging
contactsManager: self.contactsManager,
completion: { didConfirmIdentity in
if didConfirmIdentity {
_ = self.initiateCall(recipientId: recipientId)
_ = self.initiateCall(recipientId: recipientId, isVideo: isVideo)
}
})
guard !showedAlert else {
@ -81,7 +82,7 @@ import SignalMessaging
OWSAlerts.showNoMicrophonePermissionAlert()
return
}
callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId)
callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId, hasLocalVideo: isVideo)
})
return true

@ -28,7 +28,7 @@ protocol CallUIAdaptee {
func failCall(_ call: SignalCall, error: CallError)
func setIsMuted(call: SignalCall, isMuted: Bool)
func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool)
func startAndShowOutgoingCall(recipientId: String)
func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool)
}
// Shared default implementations
@ -63,7 +63,7 @@ extension CallUIAdaptee {
notificationsAdapter.presentMissedCall(call, callerName: callerName)
}
internal func startAndShowOutgoingCall(recipientId: String) {
internal func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool) {
SwiftAssertIsOnMainThread(#function)
guard self.callService.call == nil else {
@ -73,6 +73,7 @@ extension CallUIAdaptee {
}
let call = self.startOutgoingCall(handle: recipientId)
call.hasLocalVideo = hasLocalVideo
self.showCall(call)
}
}
@ -186,10 +187,10 @@ extension CallUIAdaptee {
}
}
internal func startAndShowOutgoingCall(recipientId: String) {
internal func startAndShowOutgoingCall(recipientId: String, hasLocalVideo: Bool) {
SwiftAssertIsOnMainThread(#function)
adaptee.startAndShowOutgoingCall(recipientId: recipientId)
adaptee.startAndShowOutgoingCall(recipientId: recipientId, hasLocalVideo: hasLocalVideo)
}
internal func recipientAcceptedCall(_ call: SignalCall) {

@ -1,7 +1,9 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "ConversationViewController.h"
@class AccountManager;
@class CallService;
@class CallUIAdapter;
@ -33,11 +35,10 @@
#pragma mark - View Convenience Methods
- (void)presentConversationForRecipientId:(NSString *)recipientId;
- (void)presentConversationForRecipientId:(NSString *)recipientId withCompose:(BOOL)compose;
- (void)callRecipientId:(NSString *)recipientId;
- (void)presentConversationForRecipientId:(NSString *)recipientId action:(ConversationViewAction)action;
- (void)presentConversationForThreadId:(NSString *)threadId;
- (void)presentConversationForThread:(TSThread *)thread;
- (void)presentConversationForThread:(TSThread *)thread withCompose:(BOOL)compose;
- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action;
#pragma mark - Methods

@ -152,35 +152,18 @@
- (void)presentConversationForRecipientId:(NSString *)recipientId
{
[self presentConversationForRecipientId:recipientId keyboardOnViewAppearing:YES callOnViewAppearing:NO];
[self presentConversationForRecipientId:recipientId action:ConversationViewActionNone];
}
- (void)presentConversationForRecipientId:(NSString *)recipientId withCompose:(BOOL)compose
- (void)presentConversationForRecipientId:(NSString *)recipientId action:(ConversationViewAction)action
{
[self presentConversationForRecipientId:recipientId keyboardOnViewAppearing:compose callOnViewAppearing:NO];
}
- (void)callRecipientId:(NSString *)recipientId
{
[self presentConversationForRecipientId:recipientId keyboardOnViewAppearing:NO callOnViewAppearing:YES];
}
- (void)presentConversationForRecipientId:(NSString *)recipientId
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing
{
// At most one.
OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing);
DispatchMainThreadSafe(^{
__block TSThread *thread = nil;
[OWSPrimaryStorage.dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
}];
[self presentConversationForThread:thread
keyboardOnViewAppearing:keyboardOnViewAppearing
callOnViewAppearing:callOnViewAppearing];
[self presentConversationForThread:thread action:action];
});
}
@ -199,21 +182,12 @@
- (void)presentConversationForThread:(TSThread *)thread
{
[self presentConversationForThread:thread withCompose:YES];
}
- (void)presentConversationForThread:(TSThread *)thread withCompose:(BOOL)compose
{
[self presentConversationForThread:thread keyboardOnViewAppearing:compose callOnViewAppearing:NO];
[self presentConversationForThread:thread action:ConversationViewActionNone];
}
- (void)presentConversationForThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing
- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action
{
OWSAssertIsOnMainThread();
// At most one.
OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing);
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
@ -233,9 +207,7 @@
}
}
[self.homeViewController presentThread:thread
keyboardOnViewAppearing:keyboardOnViewAppearing
callOnViewAppearing:callOnViewAppearing];
[self.homeViewController presentThread:thread action:action];
});
}

@ -253,7 +253,7 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe
return;
}
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId];
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId hasLocalVideo:NO];
completionHandler();
} else if ([identifier isEqualToString:PushManagerActionsShowThread]) {
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];

@ -4,6 +4,21 @@
/* Action sheet item */
"ACCEPT_NEW_IDENTITY_ACTION" = "Accept New Safety Number";
/* Label for 'audio call' button in contact view. */
"ACTION_AUDIO_CALL" = "Signal Call";
/* Label for 'invite' button in contact view. */
"ACTION_INVITE" = "Invite to Signal";
/* Label for 'sent message' button in contact view. */
"ACTION_SEND_MESSAGE" = "Send Message";
/* Label for 'share contact' button. */
"ACTION_SHARE_CONTACT" = "Share Contact";
/* Label for 'video call' button in contact view. */
"ACTION_VIDEO_CALL" = "Video Call";
/* A label for the 'add by phone number' button in the 'add group member' view */
"ADD_GROUP_MEMBER_VIEW_BUTTON" = "Add";

Loading…
Cancel
Save