Implement avatar sending

// FREEBIE
This commit is contained in:
Michael Kirk 2018-05-04 22:32:29 -04:00
parent eb97e82d19
commit 77fc5571fb
20 changed files with 275 additions and 131 deletions

View File

@ -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 */,

View File

@ -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
}

View File

@ -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__);

View File

@ -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;
}]];

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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
/**

View File

@ -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];

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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