parent
eb97e82d19
commit
77fc5571fb
|
@ -310,7 +310,7 @@
|
|||
45360B901F9527DA00FA666C /* SearcherTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45360B8F1F9527DA00FA666C /* SearcherTest.swift */; };
|
||||
45360B911F952AA900FA666C /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; };
|
||||
4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4539B5851F79348F007141FF /* PushRegistrationManager.swift */; };
|
||||
4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */; };
|
||||
4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */; };
|
||||
4542DF52208B82E9007B4E76 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; };
|
||||
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */; };
|
||||
45464DBC1DFA041F001D3FD6 /* DataChannelMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */; };
|
||||
|
@ -1830,8 +1830,6 @@
|
|||
45194F911FD7214600333B2C /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */,
|
||||
459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */,
|
||||
34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */,
|
||||
34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */,
|
||||
34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */,
|
||||
|
@ -1872,6 +1870,7 @@
|
|||
453518931FC63DBF00210559 /* SignalMessaging */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4541B71C209D3B4F0008608F /* ViewModels */,
|
||||
45194F911FD7214600333B2C /* Models */,
|
||||
451F8A361FD7115D005CB9DA /* ViewControllers */,
|
||||
454A96571FD600B4008D2A0E /* attachments */,
|
||||
|
@ -1893,7 +1892,16 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4541B71C209D3B4F0008608F /* ViewModels */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4541B71A209D2DAE0008608F /* ContactShareViewModel.swift */,
|
||||
459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */,
|
||||
459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3118,6 +3126,7 @@
|
|||
4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */,
|
||||
3438226A209B63500094FEB7 /* EditContactShareNameViewController.swift in Sources */,
|
||||
346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */,
|
||||
4541B71D209D3B7A0008608F /* ContactShareViewModel.swift in Sources */,
|
||||
4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */,
|
||||
346129D21FD2085A00532771 /* CommonStrings.swift in Sources */,
|
||||
45F59A082028E4FB00E8D2B0 /* OWSAudioSession.swift in Sources */,
|
||||
|
@ -3192,7 +3201,6 @@
|
|||
34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */,
|
||||
340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */,
|
||||
340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */,
|
||||
4541B71B209D2DAE0008608F /* ContactShareViewModel.swift in Sources */,
|
||||
3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */,
|
||||
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */,
|
||||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */,
|
||||
|
|
|
@ -65,8 +65,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
|
||||
var reachability: Reachability?
|
||||
|
||||
// TODO rename this property to contactShare
|
||||
private let contact: ContactShareViewModel
|
||||
private let contactShare: ContactShareViewModel
|
||||
|
||||
// MARK: - Initializers
|
||||
|
||||
|
@ -77,7 +76,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
|
||||
required init(contactShare: ContactShareViewModel) {
|
||||
contactsManager = Environment.current().contactsManager
|
||||
self.contact = contactShare
|
||||
self.contactShare = contactShare
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -141,7 +140,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
private func updateMode() {
|
||||
SwiftAssertIsOnMainThread(#function)
|
||||
|
||||
guard phoneNumbersForContact().count > 0 else {
|
||||
guard contactShare.phoneNumberStrings.count > 0 else {
|
||||
viewMode = .noPhoneNumber
|
||||
return
|
||||
}
|
||||
|
@ -160,7 +159,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
private func systemContactsWithSignalAccountsForContact() -> [String] {
|
||||
SwiftAssertIsOnMainThread(#function)
|
||||
|
||||
return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in
|
||||
return contactShare.phoneNumberStrings.filter({ (phoneNumber) -> Bool in
|
||||
return contactsManager.hasSignalAccount(forRecipientId: phoneNumber)
|
||||
})
|
||||
}
|
||||
|
@ -168,21 +167,11 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
private func systemContactsForContact() -> [String] {
|
||||
SwiftAssertIsOnMainThread(#function)
|
||||
|
||||
return phoneNumbersForContact().filter({ (phoneNumber) -> Bool in
|
||||
return contactShare.phoneNumberStrings.filter({ (phoneNumber) -> Bool in
|
||||
return contactsManager.allContactsMap[phoneNumber] != nil
|
||||
})
|
||||
}
|
||||
|
||||
private func phoneNumbersForContact() -> [String] {
|
||||
SwiftAssertIsOnMainThread(#function)
|
||||
|
||||
var result = [String]()
|
||||
for phoneNumber in contact.phoneNumbers {
|
||||
result.append(phoneNumber.phoneNumber)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private func updateContent() {
|
||||
SwiftAssertIsOnMainThread(#function)
|
||||
|
||||
|
@ -265,8 +254,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
|
||||
let avatarView = AvatarImageView()
|
||||
// TODO: What's the best colorSeed value to use?
|
||||
let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contact.displayName,
|
||||
colorSeed: contact.displayName,
|
||||
let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: contactShare.displayName,
|
||||
colorSeed: contactShare.displayName,
|
||||
diameter: UInt(avatarSize),
|
||||
contactsManager: contactsManager)
|
||||
avatarView.image = avatarBuilder.build()
|
||||
|
@ -277,7 +266,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
avatarView.autoSetDimension(.height, toSize: avatarSize)
|
||||
|
||||
let nameLabel = UILabel()
|
||||
nameLabel.text = contact.displayName
|
||||
nameLabel.text = contactShare.displayName
|
||||
nameLabel.font = UIFont.ows_dynamicTypeTitle2.ows_bold()
|
||||
nameLabel.textColor = UIColor.black
|
||||
nameLabel.lineBreakMode = .byTruncatingTail
|
||||
|
@ -289,7 +278,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
|
||||
var lastView: UIView = nameLabel
|
||||
|
||||
if let firstPhoneNumber = contact.phoneNumbers.first {
|
||||
if let firstPhoneNumber = contactShare.phoneNumbers.first {
|
||||
let phoneNumberLabel = UILabel()
|
||||
phoneNumberLabel.text = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: firstPhoneNumber.phoneNumber)
|
||||
phoneNumberLabel.font = UIFont.ows_dynamicTypeCaption2
|
||||
|
@ -388,7 +377,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
// action:#selector(didPressShareContact)))
|
||||
// }
|
||||
|
||||
for phoneNumber in contact.phoneNumbers {
|
||||
for phoneNumber in contactShare.phoneNumbers {
|
||||
let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: phoneNumber.phoneNumber)
|
||||
|
||||
rows.append(createNameValueRow(name: phoneNumber.localizedLabel(),
|
||||
|
@ -402,7 +391,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
}))
|
||||
}
|
||||
|
||||
for email in contact.emails {
|
||||
for email in contactShare.emails {
|
||||
rows.append(createNameValueRow(name: email.localizedLabel(),
|
||||
value: email.email,
|
||||
actionBlock: {
|
||||
|
@ -600,7 +589,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
OWSAlerts.showErrorAlert(message: NSLocalizedString("UNSUPPORTED_FEATURE_ERROR", comment: ""))
|
||||
return
|
||||
}
|
||||
let phoneNumbers = phoneNumbersForContact()
|
||||
let phoneNumbers = contactShare.phoneNumberStrings
|
||||
guard phoneNumbers.count > 0 else {
|
||||
owsFail("\(logTag) no phone numbers.")
|
||||
return
|
||||
|
@ -640,8 +629,8 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
return
|
||||
}
|
||||
|
||||
guard let systemContact = OWSContacts.systemContact(for: contact.dbRecord) else {
|
||||
owsFail("\(logTag) Could not derive system contact.")
|
||||
guard let systemContact = OWSContacts.systemContact(for: contactShare.dbRecord) else {
|
||||
owsFail("\(logTag) Could not derive system contactShare.")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -679,7 +668,7 @@ class ContactViewController: OWSViewController, CNContactViewControllerDelegate
|
|||
return
|
||||
}
|
||||
|
||||
guard let firstPhoneNumber = contact.phoneNumbers.first else {
|
||||
guard let firstPhoneNumber = contactShare.phoneNumbers.first else {
|
||||
owsFail("\(logTag) Missing phone number.")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#import <SignalMessaging/ThreadUtil.h>
|
||||
#import <SignalMessaging/UIUtil.h>
|
||||
#import <SignalMessaging/UIViewController+OWS.h>
|
||||
#import <SignalServiceKit/Contact.h>
|
||||
#import <SignalServiceKit/ContactsUpdater.h>
|
||||
#import <SignalServiceKit/MimeTypeUtil.h>
|
||||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
|
@ -2948,7 +2949,7 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
|
||||
- (void)sendContactShare:(OWSContact *)contactShare
|
||||
- (void)sendContactShare:(ContactShareViewModel *)contactShare
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(contactShare);
|
||||
|
@ -2956,12 +2957,20 @@ typedef enum : NSUInteger {
|
|||
DDLogVerbose(@"%@ Sending contact share.", self.logTag);
|
||||
|
||||
BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread];
|
||||
TSOutgoingMessage *message = [ThreadUtil sendMessageWithContactShare:contactShare
|
||||
inThread:self.thread
|
||||
messageSender:self.messageSender
|
||||
completion:nil];
|
||||
|
||||
[self messageWasSent:message];
|
||||
[self.editingDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
if (contactShare.avatarImage) {
|
||||
[contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction];
|
||||
}
|
||||
}
|
||||
completionBlock:^{
|
||||
TSOutgoingMessage *message = [ThreadUtil sendMessageWithContactShare:contactShare.dbRecord
|
||||
inThread:self.thread
|
||||
messageSender:self.messageSender
|
||||
completion:nil];
|
||||
[self messageWasSent:message];
|
||||
}];
|
||||
|
||||
|
||||
if (didAddToProfileWhitelist) {
|
||||
[self ensureDynamicInteractions];
|
||||
|
@ -4942,12 +4951,28 @@ interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransiti
|
|||
|
||||
DDLogDebug(@"%@ in %s with contact: %@", self.logTag, __PRETTY_FUNCTION__, contact);
|
||||
|
||||
OWSContact *_Nullable contactShare = [OWSContacts contactForSystemContact:contact.cnContact];
|
||||
if (!contactShare) {
|
||||
OWSContact *_Nullable contactShareRecord = [OWSContacts contactForSystemContact:contact.cnContact];
|
||||
if (!contactShareRecord) {
|
||||
DDLogError(@"%@ Could not convert system contact.", self.logTag);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL isProfileAvatar = NO;
|
||||
UIImage *_Nullable avatarImage = contact.image;
|
||||
if (!avatarImage) {
|
||||
NSString *firstSignalId = contact.textSecureIdentifiers.firstObject;
|
||||
if (firstSignalId) {
|
||||
avatarImage = [self.contactsManager profileImageForPhoneIdentifier:firstSignalId];
|
||||
if (avatarImage) {
|
||||
isProfileAvatar = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContactShareViewModel *contactShare =
|
||||
[[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord avatarImage:avatarImage];
|
||||
contactShareRecord.isProfileAvatar = isProfileAvatar;
|
||||
|
||||
// TODO: We should probably show this in the same navigation view controller.
|
||||
ApproveContactShareViewController *approveContactShare =
|
||||
[[ApproveContactShareViewController alloc] initWithContactShare:contactShare
|
||||
|
@ -4974,7 +4999,7 @@ interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransiti
|
|||
#pragma mark - ApproveContactShareViewControllerDelegate
|
||||
|
||||
- (void)approveContactShare:(ApproveContactShareViewController *)approveContactShare
|
||||
didApproveContactShare:(OWSContact *)contactShare
|
||||
didApproveContactShare:(ContactShareViewModel *)contactShare
|
||||
{
|
||||
DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
|
@ -4985,7 +5010,7 @@ interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransiti
|
|||
}
|
||||
|
||||
- (void)approveContactShare:(ApproveContactShareViewController *)approveContactShare
|
||||
didCancelContactShare:(OWSContact *)contactShare
|
||||
didCancelContactShare:(ContactShareViewModel *)contactShare
|
||||
{
|
||||
DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
|
|
|
@ -3033,19 +3033,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
|
||||
UIImage *avatarImage =
|
||||
[OWSAvatarBuilder buildRandomAvatarWithDiameter:200];
|
||||
NSData *avatarImageData
|
||||
= UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9);
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc]
|
||||
initWithContentType:OWSMimeTypeImageJpeg
|
||||
byteCount:avatarImageData.length
|
||||
sourceFilename:nil];
|
||||
|
||||
NSError *error;
|
||||
BOOL success =
|
||||
[attachmentStream writeData:avatarImageData error:&error];
|
||||
OWSAssert(success && !error);
|
||||
[attachmentStream saveWithTransaction:transaction];
|
||||
[contact setAvatarAttachmentStream:attachmentStream];
|
||||
[contact saveAvatarImage:avatarImage transaction:transaction];
|
||||
|
||||
return contact;
|
||||
}]];
|
||||
|
@ -3218,19 +3206,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
|
||||
UIImage *avatarImage =
|
||||
[OWSAvatarBuilder buildRandomAvatarWithDiameter:200];
|
||||
NSData *avatarImageData
|
||||
= UIImageJPEGRepresentation(avatarImage, (CGFloat)0.9);
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc]
|
||||
initWithContentType:OWSMimeTypeImageJpeg
|
||||
byteCount:avatarImageData.length
|
||||
sourceFilename:nil];
|
||||
|
||||
NSError *error;
|
||||
BOOL success =
|
||||
[attachmentStream writeData:avatarImageData error:&error];
|
||||
OWSAssert(success && !error);
|
||||
[attachmentStream saveWithTransaction:transaction];
|
||||
[contact setAvatarAttachmentStream:attachmentStream];
|
||||
[contact saveAvatarImage:avatarImage transaction:transaction];
|
||||
|
||||
return contact;
|
||||
}]];
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class ThreadViewModel: NSObject {
|
||||
let hasUnreadMessages: Bool
|
||||
let lastMessageDate: Date
|
||||
let isGroupThread: Bool
|
||||
let threadRecord: TSThread
|
||||
let unreadCount: UInt
|
||||
let contactIdentifier: String?
|
||||
let name: String
|
||||
let isMuted: Bool
|
||||
var isContactThread: Bool {
|
||||
return !isGroupThread
|
||||
}
|
||||
|
||||
let lastMessageText: String?
|
||||
|
||||
init(thread: TSThread, transaction: YapDatabaseReadTransaction) {
|
||||
self.threadRecord = thread
|
||||
self.lastMessageDate = thread.lastMessageDate()
|
||||
self.isGroupThread = thread.isGroupThread()
|
||||
self.name = thread.name()
|
||||
self.isMuted = thread.isMuted
|
||||
self.lastMessageText = thread.lastMessageText(transaction: transaction)
|
||||
|
||||
if let contactThread = thread as? TSContactThread {
|
||||
self.contactIdentifier = contactThread.contactIdentifier()
|
||||
} else {
|
||||
self.contactIdentifier = nil
|
||||
}
|
||||
|
||||
self.unreadCount = thread.unreadMessageCount(transaction: transaction)
|
||||
self.hasUnreadMessages = unreadCount > 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class ContactShareViewModel: NSObject {
|
||||
|
||||
public let dbRecord: OWSContact
|
||||
public let avatarImage: UIImage?
|
||||
|
||||
public required init(contactShareRecord: OWSContact, avatarImage: UIImage?) {
|
||||
self.dbRecord = contactShareRecord
|
||||
self.avatarImage = avatarImage
|
||||
}
|
||||
|
||||
public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) {
|
||||
if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream {
|
||||
self.init(contactShareRecord: contactShareRecord, avatarImage: avatarAttachment.image())
|
||||
} else {
|
||||
self.init(contactShareRecord: contactShareRecord, avatarImage: nil)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Delegated -> dbRecord
|
||||
|
||||
public var addresses: [OWSContactAddress] {
|
||||
get {
|
||||
return dbRecord.addresses
|
||||
}
|
||||
set {
|
||||
return dbRecord.addresses = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var emails: [OWSContactEmail] {
|
||||
get {
|
||||
return dbRecord.emails
|
||||
}
|
||||
set {
|
||||
dbRecord.emails = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var phoneNumbers: [OWSContactPhoneNumber] {
|
||||
get {
|
||||
return dbRecord.phoneNumbers
|
||||
}
|
||||
set {
|
||||
dbRecord.phoneNumbers = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var phoneNumberStrings: [String] {
|
||||
return phoneNumbers.map { $0.phoneNumber }
|
||||
}
|
||||
|
||||
public var displayName: String {
|
||||
return dbRecord.displayName
|
||||
}
|
||||
|
||||
public var ows_isValid: Bool {
|
||||
return dbRecord.ows_isValid()
|
||||
}
|
||||
|
||||
public var namePrefix: String? {
|
||||
return dbRecord.namePrefix
|
||||
}
|
||||
|
||||
public var givenName: String? {
|
||||
return dbRecord.givenName
|
||||
}
|
||||
|
||||
public var middleName: String? {
|
||||
return dbRecord.middleName
|
||||
}
|
||||
|
||||
public var familyName: String? {
|
||||
return dbRecord.familyName
|
||||
}
|
||||
|
||||
public var nameSuffix: String? {
|
||||
return dbRecord.nameSuffix
|
||||
}
|
||||
|
||||
public var isProfileAvatar: Bool {
|
||||
return dbRecord.isProfileAvatar
|
||||
}
|
||||
|
||||
public func copy(withNamePrefix namePrefix: String?,
|
||||
givenName: String?,
|
||||
middleName: String?,
|
||||
familyName: String?,
|
||||
nameSuffix: String?) -> ContactShareViewModel {
|
||||
|
||||
// TODO move the `copy` logic into the view model?
|
||||
let newDbRecord = dbRecord.copy(withNamePrefix: namePrefix, givenName: givenName, middleName: middleName, familyName: familyName, nameSuffix: nameSuffix)
|
||||
|
||||
return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage)
|
||||
}
|
||||
|
||||
public func newContact(withNamePrefix namePrefix: String?,
|
||||
givenName: String?,
|
||||
middleName: String?,
|
||||
familyName: String?,
|
||||
nameSuffix: String?) -> ContactShareViewModel {
|
||||
|
||||
// TODO move the `newContact` logic into the view model?
|
||||
let newDbRecord = dbRecord.newContact(withNamePrefix: namePrefix,
|
||||
givenName: givenName,
|
||||
middleName: middleName,
|
||||
familyName: familyName,
|
||||
nameSuffix: nameSuffix)
|
||||
|
||||
return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImage: self.avatarImage)
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,8 @@ import SignalServiceKit
|
|||
|
||||
@objc
|
||||
public protocol ApproveContactShareViewControllerDelegate: class {
|
||||
func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didApproveContactShare contactShare: OWSContact)
|
||||
func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didCancelContactShare contactShare: OWSContact)
|
||||
func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didApproveContactShare contactShare: ContactShareViewModel)
|
||||
func approveContactShare(_ approveContactShare: ApproveContactShareViewController, didCancelContactShare contactShare: ContactShareViewModel)
|
||||
}
|
||||
|
||||
protocol ContactShareField: class {
|
||||
|
@ -48,7 +48,7 @@ class ContactShareFieldBase<ContactFieldType: OWSContactField>: NSObject, Contac
|
|||
isIncludedFlag = isIncluded
|
||||
}
|
||||
|
||||
func applyToContact(contact: OWSContact) {
|
||||
func applyToContact(contact: ContactShareViewModel) {
|
||||
preconditionFailure("This method must be overridden")
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class ContactShareFieldBase<ContactFieldType: OWSContactField>: NSObject, Contac
|
|||
|
||||
class ContactSharePhoneNumber: ContactShareFieldBase<OWSContactPhoneNumber> {
|
||||
|
||||
override func applyToContact(contact: OWSContact) {
|
||||
override func applyToContact(contact: ContactShareViewModel) {
|
||||
assert(isIncluded())
|
||||
|
||||
var values = [OWSContactPhoneNumber]()
|
||||
|
@ -71,7 +71,7 @@ class ContactSharePhoneNumber: ContactShareFieldBase<OWSContactPhoneNumber> {
|
|||
|
||||
class ContactShareEmail: ContactShareFieldBase<OWSContactEmail> {
|
||||
|
||||
override func applyToContact(contact: OWSContact) {
|
||||
override func applyToContact(contact: ContactShareViewModel) {
|
||||
assert(isIncluded())
|
||||
|
||||
var values = [OWSContactEmail]()
|
||||
|
@ -85,7 +85,7 @@ class ContactShareEmail: ContactShareFieldBase<OWSContactEmail> {
|
|||
|
||||
class ContactShareAddress: ContactShareFieldBase<OWSContactAddress> {
|
||||
|
||||
override func applyToContact(contact: OWSContact) {
|
||||
override func applyToContact(contact: ContactShareViewModel) {
|
||||
assert(isIncluded())
|
||||
|
||||
var values = [OWSContactAddress]()
|
||||
|
@ -185,7 +185,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
|
||||
let contactsManager: OWSContactsManager
|
||||
|
||||
var contactShare: OWSContact
|
||||
var contactShare: ContactShareViewModel
|
||||
|
||||
var fieldViews = [ContactShareFieldView]()
|
||||
|
||||
|
@ -199,7 +199,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
}
|
||||
|
||||
@objc
|
||||
required public init(contactShare: OWSContact, contactsManager: OWSContactsManager, delegate: ApproveContactShareViewControllerDelegate) {
|
||||
required public init(contactShare: ContactShareViewModel, contactsManager: OWSContactsManager, delegate: ApproveContactShareViewControllerDelegate) {
|
||||
self.contactsManager = contactsManager
|
||||
self.contactShare = contactShare
|
||||
self.delegate = delegate
|
||||
|
@ -277,7 +277,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
|
||||
// TODO: Surface error with resolution to user if not.
|
||||
func canShareContact() -> Bool {
|
||||
return contactShare.ows_isValid()
|
||||
return contactShare.ows_isValid
|
||||
}
|
||||
|
||||
func updateNavigationBar() {
|
||||
|
@ -471,7 +471,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
|
||||
// MARK: -
|
||||
|
||||
func filteredContactShare() -> OWSContact {
|
||||
func filteredContactShare() -> ContactShareViewModel {
|
||||
let result = self.contactShare.newContact(withNamePrefix: self.contactShare.namePrefix,
|
||||
givenName: self.contactShare.givenName,
|
||||
middleName: self.contactShare.middleName,
|
||||
|
@ -498,7 +498,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
}
|
||||
|
||||
let filteredContactShare = self.filteredContactShare()
|
||||
assert(filteredContactShare.ows_isValid())
|
||||
assert(filteredContactShare.ows_isValid)
|
||||
|
||||
delegate.approveContactShare(self, didApproveContactShare: filteredContactShare)
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ public class ApproveContactShareViewController: OWSViewController, EditContactSh
|
|||
|
||||
// MARK: - EditContactShareNameViewControllerDelegate
|
||||
|
||||
public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: OWSContact) {
|
||||
public func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel) {
|
||||
self.contactShare = contactShare
|
||||
|
||||
nameLabel.text = contactShare.displayName
|
||||
|
|
|
@ -109,7 +109,7 @@ class ContactNameFieldView: UIView {
|
|||
|
||||
@objc
|
||||
public protocol EditContactShareNameViewControllerDelegate: class {
|
||||
func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: OWSContact)
|
||||
func editContactShareNameView(_ editContactShareNameView: EditContactShareNameViewController, didEditContactShare contactShare: ContactShareViewModel)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
@ -118,7 +118,7 @@ public protocol EditContactShareNameViewControllerDelegate: class {
|
|||
public class EditContactShareNameViewController: OWSViewController, ContactNameFieldViewDelegate {
|
||||
weak var delegate: EditContactShareNameViewControllerDelegate?
|
||||
|
||||
let contactShare: OWSContact
|
||||
let contactShare: ContactShareViewModel
|
||||
|
||||
var namePrefixView: ContactNameFieldView!
|
||||
var givenNameView: ContactNameFieldView!
|
||||
|
@ -136,7 +136,7 @@ public class EditContactShareNameViewController: OWSViewController, ContactNameF
|
|||
}
|
||||
|
||||
@objc
|
||||
required public init(contactShare: OWSContact, delegate: EditContactShareNameViewControllerDelegate) {
|
||||
required public init(contactShare: ContactShareViewModel, delegate: EditContactShareNameViewControllerDelegate) {
|
||||
self.contactShare = contactShare
|
||||
self.delegate = delegate
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalServiceKit/Contact.h>
|
||||
|
@ -77,6 +77,9 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
|
|||
- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId;
|
||||
- (NSString *)stringForConversationTitleWithPhoneIdentifier:(NSString *)recipientId;
|
||||
|
||||
- (nullable UIImage *)systemContactImageForPhoneIdentifier:(nullable NSString *)identifier;
|
||||
- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier;
|
||||
|
||||
- (nullable UIImage *)imageForPhoneIdentifier:(nullable NSString *)identifier;
|
||||
- (NSAttributedString *)formattedDisplayNameForSignalAccount:(SignalAccount *)signalAccount font:(UIFont *_Nonnull)font;
|
||||
- (NSAttributedString *)formattedFullNameForRecipientId:(NSString *)recipientId font:(UIFont *)font;
|
||||
|
|
|
@ -707,19 +707,32 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
|
|||
return [self signalAccountForRecipientId:recipientId] != nil;
|
||||
}
|
||||
|
||||
- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier
|
||||
|
||||
- (UIImage *_Nullable)systemContactImageForPhoneIdentifier:(NSString *_Nullable)identifier
|
||||
{
|
||||
Contact *contact = self.allContactsMap[identifier];
|
||||
if (!contact) {
|
||||
// If we haven't loaded system contacts yet, we may have a cached
|
||||
// copy in the db
|
||||
contact = [self signalAccountForRecipientId:identifier].contact;
|
||||
}
|
||||
|
||||
return contact.image;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)profileImageForPhoneIdentifier:(nullable NSString *)identifier
|
||||
{
|
||||
return [self.profileManager profileAvatarForRecipientId:identifier];
|
||||
}
|
||||
|
||||
- (UIImage *_Nullable)imageForPhoneIdentifier:(NSString *_Nullable)identifier
|
||||
{
|
||||
// Prefer the contact image from the local address book if available
|
||||
UIImage *_Nullable image = contact.image;
|
||||
UIImage *_Nullable image = [self systemContactImageForPhoneIdentifier:identifier];
|
||||
|
||||
// Else try to use the image from their profile
|
||||
if (image == nil) {
|
||||
image = [self.profileManager profileAvatarForRecipientId:identifier];
|
||||
image = [self profileImageForPhoneIdentifier:identifier];
|
||||
}
|
||||
|
||||
return image;
|
||||
|
|
|
@ -43,16 +43,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *recipientIdentifiers;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
|
||||
/**
|
||||
* Returns the image representing the thread. Nil if not available.
|
||||
*
|
||||
* @return UIImage of the thread, or nil.
|
||||
*/
|
||||
- (nullable UIImage *)image;
|
||||
#endif
|
||||
|
||||
#pragma mark Interactions
|
||||
|
||||
/**
|
||||
|
|
|
@ -120,15 +120,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [[TextSecureKitEnv sharedEnv].contactsManager displayNameForPhoneIdentifier:self.contactIdentifier];
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
- (nullable UIImage *)image
|
||||
{
|
||||
UIImage *image = [[TextSecureKitEnv sharedEnv].contactsManager imageForPhoneIdentifier:self.contactIdentifier];
|
||||
return image;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+ (NSString *)threadIdFromContactId:(NSString *)contactId {
|
||||
return [TSContactThreadPrefix stringByAppendingString:contactId];
|
||||
|
|
|
@ -112,10 +112,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value);
|
|||
@property (nonatomic, readonly) NSArray<OWSContactEmail *> *emails;
|
||||
@property (nonatomic, readonly) NSArray<OWSContactAddress *> *addresses;
|
||||
|
||||
// MJK
|
||||
@property (nonatomic, readonly, nullable) NSString *avatarAttachmentId;
|
||||
- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
// "Profile" avatars should _not_ be saved to device contacts.
|
||||
@property (nonatomic, readonly) BOOL isProfileAvatar;
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
//
|
||||
|
||||
#import "OWSContact.h"
|
||||
#import "NSString+SSK.h" OWSAttachmentInfo.h
|
||||
#import "MimeTypeUtil.h"
|
||||
#import "NSString+SSK.h"
|
||||
#import "OWSContact+Private.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "PhoneNumber.h"
|
||||
|
||||
//#import "Contact.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentPointer.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
|
@ -459,18 +458,26 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
|
|||
}
|
||||
|
||||
#pragma mark - Avatar
|
||||
// MJK
|
||||
|
||||
- (nullable TSAttachment *)avatarAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
return [TSAttachment fetchObjectWithUniqueID:self.avatarAttachmentId transaction:transaction];
|
||||
}
|
||||
|
||||
- (void)setAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
OWSAssert([attachmentStream isKindOfClass:[TSAttachmentStream class]]);
|
||||
OWSAssert(self.avatarAttachmentId == nil);
|
||||
|
||||
- (void)saveAvatarImage:(UIImage *)image transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
NSData *imageData = UIImageJPEGRepresentation(image, (CGFloat)0.9);
|
||||
|
||||
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg
|
||||
byteCount:imageData.length
|
||||
sourceFilename:nil];
|
||||
|
||||
NSError *error;
|
||||
BOOL success = [attachmentStream writeData:imageData error:&error];
|
||||
OWSAssert(success && !error);
|
||||
|
||||
[attachmentStream saveWithTransaction:transaction];
|
||||
self.avatarAttachmentId = attachmentStream.uniqueId;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (nullable TSAttachment *)attachmentWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (void)setQuotedMessageThumbnailAttachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
|
||||
- (BOOL)shouldStartExpireTimer;
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
|
|
@ -332,13 +332,6 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
[self.quotedMessage setThumbnailAttachmentStream:attachmentStream];
|
||||
}
|
||||
|
||||
- (void)setContactShareAvatarAttachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
OWSAssert(self.contactShare);
|
||||
|
||||
[self.contactShare setAvatarAttachmentStream:attachmentStream];
|
||||
}
|
||||
|
||||
#pragma mark - Update With... Methods
|
||||
|
||||
- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
|
|
|
@ -314,11 +314,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
[message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction];
|
||||
}
|
||||
|
||||
// MJK TODO - don't generate the avatar attachment until here, when we've committed to sending it.
|
||||
if (message.contactShare.avatarAttachmentId != nil) {
|
||||
// contactShareAvatarAttachment = [message.contactShare
|
||||
// createAvatarForUploadWithTransaction:transaction];
|
||||
// TODO generate and save the attachment for upload here.
|
||||
TSAttachment *avatarAttachment = [message.contactShare avatarAttachmentWithTransaction:transaction];
|
||||
if ([avatarAttachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
contactShareAvatarAttachment = (TSAttachmentStream *)avatarAttachment;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@class Contact;
|
||||
|
@ -12,8 +12,4 @@
|
|||
- (NSString * _Nonnull)displayNameForPhoneIdentifier:(NSString * _Nullable)phoneNumber;
|
||||
- (NSArray<SignalAccount *> * _Nonnull)signalAccounts;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (UIImage * _Nullable)imageForPhoneIdentifier:(NSString * _Nullable)phoneNumber;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue