Enable profile pictures

pull/65/head
Maxim Shishmarev 6 years ago
parent 7aa4e83700
commit 859384afaf

@ -58,7 +58,7 @@ final class DisplayNameVC : OnboardingBaseViewController {
guard !displayName.isEmpty else { guard !displayName.isEmpty else {
return OWSAlerts.showErrorAlert(message: NSLocalizedString("Please pick a display name", comment: "")) return OWSAlerts.showErrorAlert(message: NSLocalizedString("Please pick a display name", comment: ""))
} }
guard displayName.allSatisfy({ "0"..."9" ~= $0 || "a"..."z" ~= $0 || "A"..."Z" ~= $0 || $0 == "_" }) else { guard displayName.allSatisfy({ "0"..."9" ~= $0 || "a"..."z" ~= $0 || "A"..."Z" ~= $0 || $0 == "_" || $0 == " " }) else {
return OWSAlerts.showErrorAlert(message: NSLocalizedString("Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters", comment: "")) return OWSAlerts.showErrorAlert(message: NSLocalizedString("Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters", comment: ""))
} }
guard !OWSProfileManager.shared().isProfileNameTooLong(displayName) else { guard !OWSProfileManager.shared().isProfileNameTooLong(displayName) else {

@ -57,7 +57,9 @@ NS_ASSUME_NONNULL_BEGIN
handler:^(UIAlertAction *_Nonnull action) { handler:^(UIAlertAction *_Nonnull action) {
[self.delegate clearAvatar]; [self.delegate clearAvatar];
}]; }];
[actionSheet addAction:clearAction];
// TODO: enable this once we support removing avatars (as opposed to replacing)
// [actionSheet addAction:clearAction];
} }
[self.delegate.fromViewController presentAlert:actionSheet]; [self.delegate.fromViewController presentAlert:actionSheet];

@ -396,7 +396,7 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
return [OWSAlerts showErrorAlertWithMessage:NSLocalizedString(@"Please pick a display name", @"")]; return [OWSAlerts showErrorAlertWithMessage:NSLocalizedString(@"Please pick a display name", @"")];
} }
NSCharacterSet *allowedCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"]; NSCharacterSet *allowedCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_ "];
if ([normalizedProfileName rangeOfCharacterFromSet:allowedCharacters.invertedSet].location != NSNotFound) { if ([normalizedProfileName rangeOfCharacterFromSet:allowedCharacters.invertedSet].location != NSNotFound) {
return [OWSAlerts showErrorAlertWithMessage:NSLocalizedString(@"Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters", @"")]; return [OWSAlerts showErrorAlertWithMessage:NSLocalizedString(@"Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters", @"")];
} }

@ -1165,12 +1165,10 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
} }
NSString *_Nullable avatarUrlPathAtStart = userProfile.avatarUrlPath; NSString *_Nullable avatarUrlPathAtStart = userProfile.avatarUrlPath;
if (userProfile.profileKey.keyData.length < 1 || userProfile.avatarUrlPath.length < 1) { if (userProfile.avatarUrlPath.length < 1) {
return; return;
} }
OWSAES256Key *profileKeyAtStart = userProfile.profileKey;
NSString *fileName = [self generateAvatarFilename]; NSString *fileName = [self generateAvatarFilename];
NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName];
@ -1188,88 +1186,62 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
NSString *tempDirectory = OWSTemporaryDirectory(); NSString *tempDirectory = OWSTemporaryDirectory();
NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName]; NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName];
void (^completionHandler)(NSURLResponse *_Nonnull, NSURL *_Nullable, NSError *_Nullable) = ^(
NSURLResponse *_Nonnull response, NSURL *_Nullable filePathParam, NSError *_Nullable error) { NSString *profilePictureURL = userProfile.avatarUrlPath;
// Ensure disk IO and decryption occurs off the main thread. NSError *serializationError;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSMutableURLRequest *request =
NSData *_Nullable encryptedData = [NSData dataWithContentsOfFile:tempFilePath]; [self.avatarHTTPManager.requestSerializer requestWithMethod:@"GET"
NSData *_Nullable decryptedData = encryptedData; URLString:profilePictureURL
UIImage *_Nullable image = nil; parameters:nil
if (decryptedData) { error:&serializationError];
BOOL success = [decryptedData writeToFile:filePath atomically:YES]; if (serializationError) {
if (success) { OWSFailDebug(@"serializationError: %@", serializationError);
image = [UIImage imageWithContentsOfFile:filePath]; return;
}
} }
NSURLSession* session = [NSURLSession sharedSession];
NSURLSessionTask* downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
@synchronized(self.currentAvatarDownloads) @synchronized(self.currentAvatarDownloads)
{ {
[self.currentAvatarDownloads removeObject:userProfile.recipientId]; [self.currentAvatarDownloads removeObject:userProfile.recipientId];
} }
OWSUserProfile *latestUserProfile = if (error) {
[OWSUserProfile getOrBuildUserProfileForRecipientId:userProfile.recipientId OWSLogError(@"Dowload failed: %@", error);
dbConnection:self.dbConnection]; return;
if (latestUserProfile.profileKey.keyData.length < 1 }
|| ![latestUserProfile.profileKey isEqual:userProfile.profileKey]) {
OWSLogWarn(@"Ignoring avatar download for obsolete user profile.");
} else if (![avatarUrlPathAtStart isEqualToString:latestUserProfile.avatarUrlPath]) {
OWSLogInfo(@"avatar url has changed during download");
if (latestUserProfile.avatarUrlPath.length > 0) {
[self downloadAvatarForUserProfile:latestUserProfile];
}
} else if (error) {
OWSLogError(@"avatar download for %@ failed with error: %@", userProfile.recipientId, error);
} else if (!encryptedData) {
OWSLogError(@"avatar encrypted data for %@ could not be read.", userProfile.recipientId);
} else if (!decryptedData) {
OWSLogError(@"avatar data for %@ could not be decrypted.", userProfile.recipientId);
} else if (!image) {
OWSLogError(
@"avatar image for %@ could not be loaded with error: %@", userProfile.recipientId, error);
} else {
[self updateProfileAvatarCache:image filename:fileName];
[latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *moveError;
if (![fileManager moveItemAtURL:location toURL:fileURL error:&moveError]) {
OWSLogError(@"MoveItemAtURL for avatar failed: %@", moveError);
return;
} }
// If we're updating the profile that corresponds to our local number, UIImage *image = [UIImage imageWithContentsOfFile:[fileURL path]];
// update the local profile as well. if (image) {
NSString *_Nullable localNumber = self.tsAccountManager.localNumber; dispatch_async(dispatch_get_main_queue(), ^{
if (localNumber && [localNumber isEqualToString:userProfile.recipientId]) {
OWSUserProfile *localUserProfile = self.localUserProfile;
OWSAssertDebug(localUserProfile);
[localUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil];
[self updateProfileAvatarCache:image filename:fileName]; [self updateProfileAvatarCache:image filename:fileName];
}
OWSAssertDebug(backgroundTask); OWSUserProfile *latestUserProfile =
backgroundTask = nil; [OWSUserProfile getOrBuildUserProfileForRecipientId:userProfile.recipientId
}); dbConnection:self.dbConnection];
};
NSString *profilePictureURL = userProfile.avatarUrlPath; [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:^{
NSError *serializationError; [[NSNotificationCenter defaultCenter]
NSMutableURLRequest *request = postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification
[self.avatarHTTPManager.requestSerializer requestWithMethod:@"GET" object:nil];
URLString:profilePictureURL }];
parameters:nil });
error:&serializationError];
if (serializationError) {
OWSFailDebug(@"serializationError: %@", serializationError);
return;
} }
__block *downloadTask = [self.avatarHTTPManager downloadTaskWithRequest:request
progress:^(NSProgress *_Nonnull downloadProgress) { }];
OWSLogVerbose(
@"Downloading avatar for %@ %f", userProfile.recipientId, downloadProgress.fractionCompleted);
}
destination:^NSURL *_Nonnull(NSURL *_Nonnull targetPath, NSURLResponse *_Nonnull response) {
return [NSURL fileURLWithPath:tempFilePath];
}
completionHandler:completionHandler];
[downloadTask resume]; [downloadTask resume];
}); });
} }
@ -1334,8 +1306,11 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
{ {
OWSUserProfile *userProfile = [OWSUserProfile getOrBuildUserProfileForRecipientId:contactID transaction:transaction]; OWSUserProfile *userProfile = [OWSUserProfile getOrBuildUserProfileForRecipientId:contactID transaction:transaction];
NSString *oldProfilePictureURL = userProfile.avatarUrlPath; NSString *oldProfilePictureURL = userProfile.avatarUrlPath;
[userProfile updateWithProfileName:displayName avatarUrlPath:profilePictureURL avatarFileName:@"" transaction:transaction completion:nil]; // Note: we keep using the old file name until we have the new one
if (![oldProfilePictureURL isEqual:profilePictureURL]) { // (otherwise the profile picuture would disspear for a short time)
NSString *oldAvatarFileName = userProfile.avatarFileName;
[userProfile updateWithProfileName:displayName avatarUrlPath:profilePictureURL avatarFileName:oldAvatarFileName transaction:transaction completion:nil];
if (profilePictureURL && ![oldProfilePictureURL isEqual:profilePictureURL]) {
[self downloadAvatarForUserProfile:userProfile]; [self downloadAvatarForUserProfile:userProfile];
} }
} }

@ -30,7 +30,7 @@ typedef void (^OWSAvatarDrawBlock)(CGContextRef context);
OWSAvatarBuilder *avatarBuilder; OWSAvatarBuilder *avatarBuilder;
if ([thread isKindOfClass:[TSContactThread class]]) { if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread; TSContactThread *contactThread = (TSContactThread *)thread;
return [LKIdenticon generateIconWithString:contactThread.contactIdentifier size:((CGFloat)diameter)]; avatarBuilder = [[OWSContactAvatarBuilder alloc] initWithSignalId:contactThread.contactIdentifier colorName:contactThread.conversationColorName diameter:diameter];
} else if ([thread isKindOfClass:[TSGroupThread class]]) { } else if ([thread isKindOfClass:[TSGroupThread class]]) {
avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread diameter:diameter]; avatarBuilder = [[OWSGroupAvatarBuilder alloc] initWithThread:(TSGroupThread *)thread diameter:diameter];
} else { } else {

@ -247,7 +247,7 @@ message DataMessage {
// Loki: A custom message for our profile // Loki: A custom message for our profile
message LokiProfile { message LokiProfile {
optional string displayName = 1; optional string displayName = 1;
optional string profilePicture = 2; optional AttachmentPointer avatar = 2;
} }
optional string body = 1; optional string body = 1;

@ -10,6 +10,7 @@ public final class LokiStorageAPI : LokiDotNetAPI {
@objc public static let server = "https://file.lokinet.org" @objc public static let server = "https://file.lokinet.org"
// #endif // #endif
private static let deviceLinkType = "network.loki.messenger.devicemapping" private static let deviceLinkType = "network.loki.messenger.devicemapping"
private static let attachmentType = "net.app.core.oembed"
// MARK: Database // MARK: Database
override internal class var authTokenCollection: String { return "LokiStorageAuthTokenCollection" } override internal class var authTokenCollection: String { return "LokiStorageAuthTokenCollection" }

@ -99,6 +99,9 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(message).") print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(message).")
return nil return nil
} }
let avatarUrl = value["avatar"] as? String ?? nil;
let displayName = user["name"] as? String ?? NSLocalizedString("Anonymous", comment: "") let displayName = user["name"] as? String ?? NSLocalizedString("Anonymous", comment: "")
let lastMessageServerID = getLastMessageServerID(for: channel, on: server) let lastMessageServerID = getLastMessageServerID(for: channel, on: server)
if serverID > (lastMessageServerID ?? 0) { setLastMessageServerID(for: channel, on: server, to: serverID) } if serverID > (lastMessageServerID ?? 0) { setLastMessageServerID(for: channel, on: server, to: serverID) }
@ -125,7 +128,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
} }
return LokiPublicChatMessage.Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) return LokiPublicChatMessage.Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle)
} }
let result = LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature) let result = LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, avatar: avatarUrl, body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature)
guard result.hasValidSignature() else { guard result.hasValidSignature() else {
print("[Loki] Ignoring public chat message with invalid signature.") print("[Loki] Ignoring public chat message with invalid signature.")
return nil return nil
@ -162,7 +165,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
throw Error.parsingFailed throw Error.parsingFailed
} }
let timestamp = UInt64(date.timeIntervalSince1970) * 1000 let timestamp = UInt64(date.timeIntervalSince1970) * 1000
return LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: userHexEncodedPublicKey, displayName: displayName, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature) return LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: userHexEncodedPublicKey, displayName: displayName, avatar: signedMessage.avatar, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature)
} }
}.recover(on: DispatchQueue.global()) { error -> Promise<LokiPublicChatMessage> in }.recover(on: DispatchQueue.global()) { error -> Promise<LokiPublicChatMessage> in
if let error = error as? NetworkManagerError, error.statusCode == 401 { if let error = error as? NetworkManagerError, error.statusCode == 401 {

@ -5,6 +5,7 @@ public final class LokiPublicChatMessage : NSObject {
public let serverID: UInt64? public let serverID: UInt64?
public let hexEncodedPublicKey: String public let hexEncodedPublicKey: String
public let displayName: String public let displayName: String
public let avatar: String?
public let body: String public let body: String
/// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970. /// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970.
public let timestamp: UInt64 public let timestamp: UInt64
@ -66,10 +67,11 @@ public final class LokiPublicChatMessage : NSObject {
} }
// MARK: Initialization // MARK: Initialization
public init(serverID: UInt64?, hexEncodedPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?) { public init(serverID: UInt64?, hexEncodedPublicKey: String, displayName: String, avatar: String?, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?) {
self.serverID = serverID self.serverID = serverID
self.hexEncodedPublicKey = hexEncodedPublicKey self.hexEncodedPublicKey = hexEncodedPublicKey
self.displayName = displayName self.displayName = displayName
self.avatar = avatar
self.body = body self.body = body
self.type = type self.type = type
self.timestamp = timestamp self.timestamp = timestamp
@ -79,7 +81,7 @@ public final class LokiPublicChatMessage : NSObject {
super.init() super.init()
} }
@objc public convenience init(hexEncodedPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteeHexEncodedPublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64) { @objc public convenience init(hexEncodedPublicKey: String, displayName: String, avatar: String?, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteeHexEncodedPublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64) {
let quote: Quote? let quote: Quote?
if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteeHexEncodedPublicKey, let quotedMessageBody = quotedMessageBody { if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteeHexEncodedPublicKey, let quotedMessageBody = quotedMessageBody {
let quotedMessageServerID = (quotedMessageServerID != 0) ? quotedMessageServerID : nil let quotedMessageServerID = (quotedMessageServerID != 0) ? quotedMessageServerID : nil
@ -93,7 +95,7 @@ public final class LokiPublicChatMessage : NSObject {
} else { } else {
signature = nil signature = nil
} }
self.init(serverID: nil, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature) self.init(serverID: nil, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, avatar: avatar, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature)
} }
// MARK: Crypto // MARK: Crypto
@ -108,7 +110,7 @@ public final class LokiPublicChatMessage : NSObject {
return nil return nil
} }
let signature = Signature(data: signatureData, version: signatureVersion) let signature = Signature(data: signatureData, version: signatureVersion)
return LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature) return LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, avatar: avatar, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature)
} }
internal func hasValidSignature() -> Bool { internal func hasValidSignature() -> Bool {
@ -128,6 +130,11 @@ public final class LokiPublicChatMessage : NSObject {
value["sig"] = signature.data.toHexString() value["sig"] = signature.data.toHexString()
value["sigver"] = signature.version value["sigver"] = signature.version
} }
if let avatar = avatar {
value["avatar"] = avatar;
}
let annotation: JSON = [ "type" : type, "value" : value ] let annotation: JSON = [ "type" : type, "value" : value ]
let attachmentAnnotations: [JSON] = attachments.map { attachment in let attachmentAnnotations: [JSON] = attachments.map { attachment in
let type: String let type: String

@ -120,6 +120,14 @@ public final class LokiPublicChatPoller : NSObject {
signalLinkPreview.setImage(try! attachment.build()) signalLinkPreview.setImage(try! attachment.build())
dataMessage.setPreview([ try! signalLinkPreview.build() ]) dataMessage.setPreview([ try! signalLinkPreview.build() ])
} }
let profile = SSKProtoDataMessageLokiProfile.builder()
if let avatar = message.avatar {
profile.setProfilePicture(avatar)
profile.setDisplayName(message.displayName)
dataMessage.setProfile(try! profile.build())
}
dataMessage.setTimestamp(message.timestamp) dataMessage.setTimestamp(message.timestamp)
dataMessage.setGroup(try! groupContext.build()) dataMessage.setGroup(try! groupContext.build())
if let quote = message.quote { if let quote = message.quote {

@ -1335,6 +1335,14 @@ NS_ASSUME_NONNULL_BEGIN
[newMemberIds addObjectsFromArray:oldGroupThread.groupModel.groupMemberIds]; [newMemberIds addObjectsFromArray:oldGroupThread.groupModel.groupMemberIds];
} }
NSString *hexEncodedPublicKey = ([LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source);
TSContactThread *thread =
[TSContactThread getOrCreateThreadWithContactId:hexEncodedPublicKey transaction:transaction];
NSString *profilePictureURL = dataMessage.profile.profilePicture;
NSString *displayName = dataMessage.profile.displayName;
[self.profileManager updateProfileForContactWithID:thread.contactIdentifier displayName:displayName profilePictureURL:profilePictureURL with:transaction];
switch (dataMessage.group.type) { switch (dataMessage.group.type) {
case SSKProtoGroupContextTypeUpdate: { case SSKProtoGroupContextTypeUpdate: {
// Ensures that the thread exists but doesn't update it. // Ensures that the thread exists but doesn't update it.
@ -1536,6 +1544,7 @@ NS_ASSUME_NONNULL_BEGIN
if (rawProfilePictureURL != nil && rawProfilePictureURL.length > 0) { if (rawProfilePictureURL != nil && rawProfilePictureURL.length > 0) {
profilePictureURL = rawProfilePictureURL; profilePictureURL = rawProfilePictureURL;
} }
[self.profileManager updateProfileForContactWithID:thread.contactIdentifier displayName:displayName profilePictureURL:profilePictureURL with:transaction]; [self.profileManager updateProfileForContactWithID:thread.contactIdentifier displayName:displayName profilePictureURL:profilePictureURL with:transaction];
// Loki: Parse Loki specific properties if needed // Loki: Parse Loki specific properties if needed

@ -1201,6 +1201,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *displayName = SSKEnvironment.shared.profileManager.localProfileName; NSString *displayName = SSKEnvironment.shared.profileManager.localProfileName;
if (displayName == nil) { displayName = @"Anonymous"; } if (displayName == nil) { displayName = @"Anonymous"; }
NSString *avatarUrl = SSKEnvironment.shared.profileManager.profilePictureURL;
TSQuotedMessage *quote = message.quotedMessage; TSQuotedMessage *quote = message.quotedMessage;
uint64_t quoteID = quote.timestamp; uint64_t quoteID = quote.timestamp;
NSString *quoteeHexEncodedPublicKey = quote.authorId; NSString *quoteeHexEncodedPublicKey = quote.authorId;
@ -1211,7 +1212,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}]; }];
} }
NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body
LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName avatar:avatarUrl body:body type:LKPublicChatAPI.publicChatMessageType
timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteeHexEncodedPublicKey:quoteeHexEncodedPublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0]; timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteeHexEncodedPublicKey:quoteeHexEncodedPublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0];
OWSLinkPreview *linkPreview = message.linkPreview; OWSLinkPreview *linkPreview = message.linkPreview;
if (linkPreview != nil) { if (linkPreview != nil) {

Loading…
Cancel
Save