Integrating Message View.

This commit is contained in:
Frederic Jacobs 2014-11-25 16:38:33 +01:00
parent 84e12a39c9
commit d73e42beff
22 changed files with 443 additions and 239 deletions

View File

@ -283,8 +283,10 @@
A1C32D5017A06538000A904E /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4F17A06537000A904E /* AddressBookUI.framework */; };
A1C32D5117A06544000A904E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4D17A0652C000A904E /* AddressBook.framework */; };
AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; };
B6019E971A2492AB001118DF /* NSDate+millisecondTimeStamp.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */; };
B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C16641988999D00E97A6C /* VersionMigrations.m */; };
B60EDE041A05A01700D73516 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B60EDE031A05A01700D73516 /* AudioToolbox.framework */; };
B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */; };
B633C5801A1D190B0059AC12 /* archive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C4FE1A1D190B0059AC12 /* archive@2x.png */; };
B633C5831A1D190B0059AC12 /* backspace.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C5011A1D190B0059AC12 /* backspace.png */; };
B633C5841A1D190B0059AC12 /* backspace@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C5021A1D190B0059AC12 /* backspace@2x.png */; };
@ -370,7 +372,7 @@
B6B0966E1A1D25ED008BFAA6 /* TSGroupMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B0960A1A1D25ED008BFAA6 /* TSGroupMessageManager.m */; };
B6B0966F1A1D25ED008BFAA6 /* TSIncomingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B0960C1A1D25ED008BFAA6 /* TSIncomingMessage.m */; };
B6B096701A1D25ED008BFAA6 /* TSInfoMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B0960E1A1D25ED008BFAA6 /* TSInfoMessage.m */; };
B6B096711A1D25ED008BFAA6 /* TSInteraction.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6B096101A1D25ED008BFAA6 /* TSInteraction.mm */; };
B6B096711A1D25ED008BFAA6 /* TSInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B096101A1D25ED008BFAA6 /* TSInteraction.m */; };
B6B096721A1D25ED008BFAA6 /* TSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B096121A1D25ED008BFAA6 /* TSMessage.m */; };
B6B096731A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B096141A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.m */; };
B6B096741A1D25ED008BFAA6 /* TSMessagesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B096161A1D25ED008BFAA6 /* TSMessagesManager.m */; };
@ -853,9 +855,13 @@
A1C32D4D17A0652C000A904E /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
A1C32D4F17A06537000A904E /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; };
A1FDCBEE16DAA6C300868894 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+millisecondTimeStamp.h"; sourceTree = "<group>"; };
B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+millisecondTimeStamp.mm"; sourceTree = "<group>"; };
B60C16631988999D00E97A6C /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = "<group>"; };
B60C16641988999D00E97A6C /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VersionMigrations.m; sourceTree = "<group>"; };
B60EDE031A05A01700D73516 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSMessageAdapter.h; sourceTree = "<group>"; };
B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageAdapter.m; sourceTree = "<group>"; };
B633C4FE1A1D190B0059AC12 /* archive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "archive@2x.png"; sourceTree = "<group>"; };
B633C5011A1D190B0059AC12 /* backspace.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = backspace.png; sourceTree = "<group>"; };
B633C5021A1D190B0059AC12 /* backspace@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "backspace@2x.png"; sourceTree = "<group>"; };
@ -1020,7 +1026,7 @@
B6B0960D1A1D25ED008BFAA6 /* TSInfoMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInfoMessage.h; sourceTree = "<group>"; };
B6B0960E1A1D25ED008BFAA6 /* TSInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInfoMessage.m; sourceTree = "<group>"; };
B6B0960F1A1D25ED008BFAA6 /* TSInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInteraction.h; sourceTree = "<group>"; };
B6B096101A1D25ED008BFAA6 /* TSInteraction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TSInteraction.mm; sourceTree = "<group>"; };
B6B096101A1D25ED008BFAA6 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = "<group>"; };
B6B096111A1D25ED008BFAA6 /* TSMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSMessage.h; sourceTree = "<group>"; };
B6B096121A1D25ED008BFAA6 /* TSMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessage.m; sourceTree = "<group>"; };
B6B096131A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TSMessagesManager+sendMessages.h"; sourceTree = "<group>"; };
@ -2090,6 +2096,15 @@
path = util;
sourceTree = "<group>";
};
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */ = {
isa = PBXGroup;
children = (
B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */,
B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */,
);
name = TSMessageAdapters;
sourceTree = "<group>";
};
B633C4FD1A1D190B0059AC12 /* Images */ = {
isa = PBXGroup;
children = (
@ -2650,7 +2665,7 @@
B6B0960D1A1D25ED008BFAA6 /* TSInfoMessage.h */,
B6B0960E1A1D25ED008BFAA6 /* TSInfoMessage.m */,
B6B0960F1A1D25ED008BFAA6 /* TSInteraction.h */,
B6B096101A1D25ED008BFAA6 /* TSInteraction.mm */,
B6B096101A1D25ED008BFAA6 /* TSInteraction.m */,
B6B096111A1D25ED008BFAA6 /* TSMessage.h */,
B6B096121A1D25ED008BFAA6 /* TSMessage.m */,
B6B096131A1D25ED008BFAA6 /* TSMessagesManager+sendMessages.h */,
@ -2723,6 +2738,8 @@
B6B0965E1A1D25ED008BFAA6 /* NSString+escape.m */,
B6B0965F1A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.h */,
B6B096601A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.m */,
B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */,
B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */,
);
path = Util;
sourceTree = "<group>";
@ -2971,6 +2988,7 @@
FC3196321A08142D0094C78E /* Signals */ = {
isa = PBXGroup;
children = (
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */,
FC3196281A067D8F0094C78E /* MessageComposeTableViewController.h */,
FC3196291A067D8F0094C78E /* MessageComposeTableViewController.m */,
FCAC963A19FEF9280046DFC5 /* SignalsViewController.h */,
@ -3445,6 +3463,7 @@
FC4FA0331A1D46AE00DA100A /* InitialViewController.m in Sources */,
B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */,
76EB05D618170B33006006FC /* ZrtpResponder.m in Sources */,
B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */,
B63AF5C91A1F757900D01AAD /* TSRecipientPrekeyRequest.m in Sources */,
7095B7B018F46D35002C66E2 /* PhoneNumberUtil.m in Sources */,
B63AF5D81A1F889500D01AAD /* SubProtocol.pb.m in Sources */,
@ -3513,6 +3532,7 @@
7038632818F70C0700D4A43F /* EvpSymetricUtil.m in Sources */,
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
B6B096921A1D25ED008BFAA6 /* NSData+hexString.m in Sources */,
B6019E971A2492AB001118DF /* NSDate+millisecondTimeStamp.mm in Sources */,
B63761ED19E1FBE8005735D1 /* HttpRequestOrResponse.m in Sources */,
B63AF5C81A1F757900D01AAD /* TSDeregisterAccountRequest.m in Sources */,
76EB05A018170B33006006FC /* IpAddress.m in Sources */,
@ -3619,7 +3639,7 @@
76EB05E818170B33006006FC /* CallFailedServerMessage.m in Sources */,
76EB05FA18170B33006006FC /* CallConnectUtil_Responder.m in Sources */,
76EB05AE18170B33006006FC /* SrtpStream.m in Sources */,
B6B096711A1D25ED008BFAA6 /* TSInteraction.mm in Sources */,
B6B096711A1D25ED008BFAA6 /* TSInteraction.m in Sources */,
B6B0966D1A1D25ED008BFAA6 /* TSErrorMessage.m in Sources */,
B63AF5CF1A1F757900D01AAD /* TSRequestAttachmentId.m in Sources */,
E197B61318BBEC1A00F073E5 /* DesiredBufferDepthController.m in Sources */,

View File

@ -55,7 +55,7 @@ typedef BOOL (^ContactSearchBlock)(id, NSUInteger, BOOL*);
}
-(void) updatedDirectoryHandler:(NSNotification*) notification {
NSArray *currentUsers = [self getRedPhoneUsersFromContactsArray:latestContactsById.allValues];
NSArray *currentUsers = [self getSignalUsersFromContactsArray:latestContactsById.allValues];
[observableRedPhoneUsersController updateValue:currentUsers];
}
@ -380,9 +380,9 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
#pragma mark - Whisper User Management
-(NSArray*) getRedPhoneUsersFromContactsArray:(NSArray*) contacts {
-(NSArray*) getSignalUsersFromContactsArray:(NSArray*)contacts {
return [contacts filter:^int(Contact* contact) {
return [self isContactRegisteredWithRedPhone:contact];
return [self isContactRegisteredWithRedPhone:contact] || contact.isTextSecureContact;
}];
}
@ -420,7 +420,7 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
return NO;
}
- (BOOL)isPhoneNumberRegisteredWithRedPhone:(PhoneNumber *)phoneNumber {
- (BOOL)isPhoneNumberRegisteredWithRedPhone:(PhoneNumber*)phoneNumber {
PhoneNumberDirectoryFilter* directory = Environment.getCurrent.phoneDirectoryManager.getCurrentFilter;
return phoneNumber != nil && [directory containsPhoneNumber:phoneNumber];
}

View File

@ -39,13 +39,13 @@
[SignalKeyingStorage generateServerAuthPassword];
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_GET;
apiCall.endPoint = @"/users/verification";
apiCall.endPoint = @"/users/verification/sms?client=ios";
return apiCall;
}
+ (RPAPICall*)requestVerificationCodeWithVoice {
RPAPICall *apiCall = [self requestVerificationCode];
apiCall.endPoint = [apiCall.endPoint stringByAppendingString:@"/voice"];
apiCall.endPoint = @"/users/verification/voice?client=ios";
return apiCall;
}

View File

@ -15,6 +15,7 @@
+ (instancetype)threadWithContactId:(NSString*)contactId transaction:(YapDatabaseReadWriteTransaction*)transaction;
- (TSRecipient*)recipient;
- (NSString*)contactIdentifier;
- (TSRecipient *)recipientWithTransaction:(YapDatabaseReadTransaction*)transaction;
@end

View File

@ -11,6 +11,7 @@
#import "Environment.h"
#import "TSStorageManager.h"
#import "ContactsManager.h"
#import "TSRecipient.h"
#define TSContactThreadPrefix @"c"
@ -37,7 +38,7 @@
return thread;
}
- (NSString *)contactIdentifier{
- (NSString*)contactIdentifier{
return [[self class]contactIdFromThreadId:self.uniqueId];
}
@ -64,4 +65,8 @@
return [threadId substringWithRange:NSMakeRange(1, threadId.length-1)];
}
- (TSRecipient *)recipientWithTransaction:(YapDatabaseReadTransaction*)transaction{
return [TSRecipient recipientWithTextSecureIdentifier:self.contactIdentifier withTransaction:transaction];
}
@end

View File

@ -10,4 +10,14 @@
@implementation TSErrorMessage
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread failedMessageType:(TSErrorMessageType)errorMessageType{
self = [super initWithTimestamp:timestamp inThread:thread messageBody:@"Error Message" attachements:nil];
if (self) {
_errorType = errorMessageType;
}
return self;
}
@end

View File

@ -6,8 +6,6 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <chrono>
#import "TSInteraction.h"
const struct TSMessageRelationships TSMessageRelationships = {
@ -31,7 +29,7 @@ const struct TSMessageEdges TSMessageEdges = {
}
#pragma - mark YapDatabaseRelationshipNode
#pragma mark YapDatabaseRelationshipNode
- (NSArray *)yapDatabaseRelationshipEdges
{
@ -53,7 +51,7 @@ const struct TSMessageEdges TSMessageEdges = {
#pragma mark Date operations
- (int64_t)identifierToTimestamp{
- (uint64_t)identifierToTimestamp{
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterNoStyle];
NSNumber * myNumber = [f numberFromString:self.uniqueId];
@ -61,12 +59,12 @@ const struct TSMessageEdges TSMessageEdges = {
}
- (NSDate*)date{
int64_t milliseconds = [self identifierToTimestamp];
int64_t seconds = milliseconds/1000;
uint64_t milliseconds = [self identifierToTimestamp];
uint64_t seconds = milliseconds/1000;
return [NSDate dateWithTimeIntervalSince1970:seconds];
}
- (uint64_t)timeStamp{
- (UInt64)timeStamp{
return [self identifierToTimestamp];
}
@ -74,9 +72,4 @@ const struct TSMessageEdges TSMessageEdges = {
return [[NSNumber numberWithUnsignedLongLong:timestamp] stringValue];
}
- (NSNumber*)nowTimeStamp{
double milliseconds = std::chrono::system_clock::now().time_since_epoch()/std::chrono::milliseconds(1);
return [NSNumber numberWithDouble:milliseconds];
}
@end

View File

@ -9,6 +9,7 @@
#import "TSMessagesManager+sendMessages.h"
#import <AxolotlKit/SessionCipher.h>
#import <Mantle/Mantle.h>
#import "IncomingPushMessageSignal.pb.h"
#import "TSStorageManager.h"
@ -32,8 +33,13 @@
NSLog(@"Currently unsupported");
} else if([thread isKindOfClass:[TSContactThread class]]){
TSContactThread *contactThread = (TSContactThread*)thread;
__block TSRecipient *recipient;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
recipient = [contactThread recipientWithTransaction:transaction];
}];
[self sendMessage:message
toRecipient:contactThread.recipient
toRecipient:recipient
inThread:thread
withAttemps:3];
}
@ -55,6 +61,8 @@
[[TSNetworkManager sharedManager] queueAuthenticatedRequest:request success:^(NSURLSessionDataTask *task, id responseObject) {
[self handleMessageSent:message inThread:thread];
NSLog(@"Message sent");
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
@ -117,7 +125,9 @@
destination:recipient.uniqueId
device:[deviceNumber intValue]
body:serializedMessage];
[messagesArray addObject:serverMessage];
[messagesArray addObject:[MTLJSONAdapter JSONDictionaryFromModel:serverMessage]];
}@catch (NSException *exception) {
[self processException:exception outgoingMessage:message];

View File

@ -7,7 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "IncomingPushMessageSignal.pb.h"
#import "TSOutgoingMessage.h"
@interface TSMessagesManager : NSObject
@ -16,7 +16,7 @@
@property (readonly) YapDatabaseConnection *dbConnection;
- (void)handleMessageSignal:(NSData*)signalData;
- (void)handleMessageSignal:(IncomingPushMessageSignal*)messageSignal;
- (void)processException:(NSException*)exception outgoingMessage:(TSOutgoingMessage*)message;

View File

@ -30,7 +30,7 @@
#import <CocoaLumberjack/DDLog.h>
#define ddLogLevel LOG_LEVEL_DEBUG
#define ddLogLevel LOG_LEVEL_VERBOSE
@implementation TSMessagesManager
@ -53,21 +53,8 @@
return self;
}
- (void)handleMessageSignal:(NSData*)signalData{
NSString *base64String = [[NSString alloc] initWithData:signalData encoding:NSUTF8StringEncoding];
NSData *encryptedSignal = [NSData dataFromBase64String:base64String];
NSData *decryptedPayload = [Cryptography decryptAppleMessagePayload:encryptedSignal
withSignalingKey:TSStorageManager.signalingKey];
if (!decryptedPayload) {
DDLogWarn(@"Failed to decrypt incoming payload or bad HMAC");
return;
}
- (void)handleMessageSignal:(IncomingPushMessageSignal*)messageSignal{
@try {
IncomingPushMessageSignal *messageSignal = [IncomingPushMessageSignal parseFromData:decryptedPayload];
switch (messageSignal.type) {
case IncomingPushMessageSignalTypeCiphertext:
[self handleSecureMessage:messageSignal];
@ -230,6 +217,11 @@
- (void)processException:(NSException*)exception pushSignal:(IncomingPushMessageSignal*)signal{
NSLog(@"Got exception: %@", exception.description);
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSErrorMessage *errorMessage = [[TSErrorMessage alloc] initWithTimestamp:signal.timestamp inThread:[TSContactThread threadWithContactId:signal.source transaction:transaction] failedMessageType:TSErrorMessageNoSession];
[errorMessage saveWithTransaction:transaction];
}];
}

View File

@ -15,6 +15,10 @@
#import "TSStorageManager+keyingMaterial.h"
#import <CocoaLumberjack/DDLog.h>
#import "NSData+Base64.h"
#import "Cryptography.h"
#import "IncomingPushMessageSignal.pb.h"
#define kWebSocketHeartBeat 15
NSString * const SocketOpenedNotification = @"SocketOpenedNotification";
@ -83,7 +87,7 @@ NSString * const SocketConnectingNotification = @"SocketConnectingNotification";
}
+ (void)resignActivity{
SRWebSocket *socket =[[self sharedManager] websocket];
SRWebSocket *socket = [[self sharedManager] websocket];
[socket close];
}
@ -115,8 +119,24 @@ NSString * const SocketConnectingNotification = @"SocketConnectingNotification";
- (void)processWebSocketRequestMessage:(WebSocketRequestMessage*)message {
DDLogInfo(@"Got message with verb: %@ and path: %@", message.verb, message.path);
[self sendWebSocketMessageAcknowledgement:message];
if ([message.path isEqualToString:@"/api/v1/message"] && [message.verb isEqualToString:@"PUT"]){
[[TSMessagesManager sharedManager] handleMessageSignal:message.body];
NSString *base64String = [[NSString alloc] initWithData:message.body encoding:NSUTF8StringEncoding];
NSData *encryptedSignal = [NSData dataFromBase64String:base64String];
NSData *decryptedPayload = [Cryptography decryptAppleMessagePayload:encryptedSignal
withSignalingKey:TSStorageManager.signalingKey];
if (!decryptedPayload) {
DDLogWarn(@"Failed to decrypt incoming payload or bad HMAC");
return;
}
IncomingPushMessageSignal *messageSignal = [IncomingPushMessageSignal parseFromData:decryptedPayload];
[[TSMessagesManager sharedManager] handleMessageSignal:messageSignal];
} else{
DDLogWarn(@"Unsupported WebSocket Request");
}
@ -126,10 +146,16 @@ NSString * const SocketConnectingNotification = @"SocketConnectingNotification";
DDLogWarn(@"Client should not receive WebSocket Respond messages");
}
- (void)sendWebSocketMessageAcknowledgement:(NSString*)messageId {
WebSocketResponseMessageBuilder *message = [WebSocketResponseMessage builder];
[message setStatus:200];
[message setMessage:messageId];
- (void)sendWebSocketMessageAcknowledgement:(WebSocketRequestMessage*)request {
WebSocketResponseMessageBuilder *response = [WebSocketResponseMessage builder];
[response setStatus:200];
[response setMessage:@"OK"];
[response setId:request.id];
WebSocketMessageBuilder *message = [WebSocketMessage builder];
[message setResponse:response.build];
[message setType:WebSocketMessageTypeResponse];
[self.websocket send:message.build.data];
}

View File

@ -0,0 +1,13 @@
//
// NSDate+millisecondTimeStamp.h
// Signal
//
// Created by Frederic Jacobs on 25/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDate (millisecondTimeStamp)
+ (uint64_t)ows_millisecondTimeStamp;
@end

View File

@ -0,0 +1,19 @@
//
// NSDate+millisecondTimeStamp.m
// Signal
//
// Created by Frederic Jacobs on 25/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "NSDate+millisecondTimeStamp.h"
#import <chrono>
@implementation NSDate (millisecondTimeStamp)
+ (uint64_t)ows_millisecondTimeStamp{
uint64_t milliseconds = std::chrono::system_clock::now().time_since_epoch()/std::chrono::milliseconds(1);
return milliseconds;
}
@end

View File

@ -24,10 +24,7 @@ enum {kDemoDataModelCase0, kDemoDataModelCase1,kDemoDataModelCase2, kDemoDataMod
{
[self loadFakeMessages];
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleBlueColor]];
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
}
return self;
}

View File

@ -17,8 +17,6 @@
#import "JSQMessagesKeyboardController.h"
@interface MessageComposeTableViewController : UITableViewController
@end

View File

@ -140,8 +140,6 @@
s.contactFromCompose = [self contactForIndexPath:indexPath];
[self.searchController dismissViewControllerAnimated:NO completion:nil];
[self dismissViewControllerAnimated:YES completion:^(){
[s performSegueWithIdentifier:@"showSegue" sender:nil];
}];

View File

@ -15,8 +15,8 @@
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@property (strong, nonatomic) NSString* _senderTitleString;
@property DemoDataModel *demoData;
@property (strong, nonatomic) NSString* senderTitleString;
@property TSThread *thread;
- (void)setupWithThread:(TSThread*)thread;

View File

@ -20,6 +20,20 @@
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "TSStorageManager.h"
#import "TSDatabaseView.h"
#import <YapDatabase/YapDatabaseView.h>
#import "TSInteraction.h"
#import "TSMessageAdapter.h"
#import "TSMessagesManager+sendMessages.h"
#import "NSDate+millisecondTimeStamp.h"
static NSTimeInterval const kTSMessageSentDateShowTimeInterval = 5 * 60;
typedef enum : NSUInteger {
kMediaTypePicture,
kMediaTypeVideo,
@ -30,6 +44,11 @@ typedef enum : NSUInteger {
BOOL isGroupConversation;
}
@property (nonatomic, strong) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, strong) YapDatabaseViewMappings *messageMappings;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData;
@end
@implementation MessagesViewController
@ -38,22 +57,32 @@ typedef enum : NSUInteger {
[super viewDidLoad];
// Do any additional setup after loading the view.
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleBlueColor]];
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[self.thread.uniqueId] view:TSMessageDatabaseViewExtensionName];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.messageMappings updateWithTransaction:transaction];
NSLog(@"Total messages: %lu", (unsigned long)[self.messageMappings numberOfItemsInAllGroups]);
}];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"lock.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showFingerprint)];
[self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_lightFontWithSize:16.0f]];
self.collectionView.showsVerticalScrollIndicator = NO;
self.collectionView.showsHorizontalScrollIndicator = NO;
//DEBUG:
isGroupConversation = NO;
self.title = self.senderTitleString;
self.senderId = kJSQDemoAvatarIdDylan;
self.senderDisplayName = kJSQDemoAvatarDisplayNameDylan;
self.demoData = [[DemoDataModel alloc] init];
self.senderId = @"self";
self.senderDisplayName = kJSQDemoAvatarDisplayNameDylan;
self.automaticallyScrollsToMostRecentMessage = YES;
@ -91,12 +120,6 @@ typedef enum : NSUInteger {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
-(void)initWithGroup:(NSArray *)group
{
//Search for an existing group to set self.title & fetch messages for this identifier
//If none found, instantiate new group
}
#pragma mark - Keyboard Handlers
-(void)keyboardWillShow:(id)sender
@ -120,7 +143,7 @@ typedef enum : NSUInteger {
-(void)updateMessageStatus:(JSQMessage*)message {
if ([message.senderId isEqualToString:self.senderId])
message.status = kMessageReceived;
message.status = kMessageReceived;
}
#pragma mark - JSQMessagesViewController method overrides
@ -134,16 +157,13 @@ typedef enum : NSUInteger {
if ([button.titleLabel.text isEqualToString:@"Call"])
{
NSLog(@"Let's call !");
} else if (text.length > 0) {
[JSQSystemSoundPlayer jsq_playMessageSentSound];
JSQMessage *message = [[JSQMessage alloc] initWithSenderId:senderId
senderDisplayName:senderDisplayName
date:date
text:text];
[self.demoData.messages addObject:message];
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:text attachements:nil];
[[TSMessagesManager sharedManager] sendMessage:message inThread:self.thread];
[self finishSendingMessage];
}
}
@ -153,19 +173,18 @@ typedef enum : NSUInteger {
- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
return [TSMessageAdapter messageViewDataWithInteraction:[self messageAtIndexPath:indexPath] inThread:_thread];
}
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessage *message = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
id<JSQMessageData> message = [TSMessageAdapter messageViewDataWithInteraction:[self messageAtIndexPath:indexPath] inThread:_thread];
if ([message.senderId isEqualToString:self.senderId]) {
return self.demoData.outgoingBubbleImageData;
return self.outgoingBubbleImageData;
}
return self.demoData.incomingBubbleImageData;
return self.incomingBubbleImageData;
}
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
@ -173,98 +192,31 @@ typedef enum : NSUInteger {
return nil;
}
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath
{
/**
* This logic should be consistent with what you return from `heightForCellTopLabelAtIndexPath:`
* The other label text delegate methods should follow a similar pattern.
*
* Show a timestamp for every 3rd message
*/
if (indexPath.item % 3 == 0) {
JSQMessage *message = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:message.date];
}
return nil;
}
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessage *message = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
/**
* iOS7-style sender name labels
*/
if ([message.senderId isEqualToString:self.senderId]) {
[self updateMessageStatus:message];
return nil;
}
if (indexPath.item - 1 > 0) {
JSQMessage *previousMessage = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item - 1];
if ([[previousMessage senderId] isEqualToString:message.senderId]) {
return nil;
}
}
/**
* Don't specify attributes to use the defaults.
*/
return [[NSAttributedString alloc] initWithString:message.senderDisplayName];
}
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath
{
JSQMessage * message = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
if (message.status == kMessageRead){
return [[NSAttributedString alloc]initWithString:@"Read" attributes:nil];
} else if (message.status == kMessageSent) {
return [[NSAttributedString alloc]initWithString:@"Sent" attributes:nil];
} else if (message.status == kMessageReceived) {
return [[NSAttributedString alloc]initWithString:@"Received" attributes:nil];
} else {
return nil;
}
}
#pragma mark - UICollectionView DataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return (NSInteger)[self.demoData.messages count];
}
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
/**
* Override point for customizing cells
*/
JSQMessage *msg = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
id<JSQMessageData> msg = [TSMessageAdapter messageViewDataWithInteraction:[self messageAtIndexPath:indexPath] inThread:_thread];
if ([msg isKindOfClass:[JSQMessage class]])
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
if (!msg.isMediaMessage) {
if ([msg.senderId isEqualToString:self.senderId]) {
cell.textView.textColor = [UIColor whiteColor];
}
else {
cell.textView.textColor = [UIColor blackColor];
}
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
if (!msg.isMediaMessage) {
if ([msg.senderId isEqualToString:self.senderId]) {
cell.textView.textColor = [UIColor whiteColor];
}
else {
cell.textView.textColor = [UIColor blackColor];
}
return cell;
} else {
JSQCallCollectionViewCell *cell = (JSQCallCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
return cell;
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
}
return cell;
}
#pragma mark - Adjusting cell label heights
@ -282,32 +234,29 @@ typedef enum : NSUInteger {
*
* Show a timestamp for every 3rd message
*/
if (indexPath.item % 3 == 0) {
if ([self showDateAtIndexPath:indexPath]) {
return kJSQMessagesCollectionViewCellLabelHeightDefault;
}
return 0.0f;
}
- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
layout:(JSQMessagesCollectionViewFlowLayout *)collectionViewLayout heightForMessageBubbleTopLabelAtIndexPath:(NSIndexPath *)indexPath
- (BOOL)showDateAtIndexPath:(NSIndexPath *)indexPath
{
/**
* iOS7-style sender name labels
*/
JSQMessage *currentMessage = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item];
if ([[currentMessage senderId] isEqualToString:self.senderId]) {
return 0.0f;
BOOL showDate = NO;
if (indexPath.row == 0) {
showDate = YES;
}
if (indexPath.item - 1 > 0) {
JSQMessage *previousMessage = [self.demoData.messages objectAtIndex:(NSUInteger)indexPath.item - 1];
if ([[previousMessage senderId] isEqualToString:[currentMessage senderId]]) {
return 0.0f;
else {
TSInteraction *currentMessage = [self messageAtIndexPath:indexPath];
TSInteraction *previousMessage = [self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row-1 inSection:indexPath.section]];
NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date];
if (timeDifference > kTSMessageSentDateShowTimeInterval) {
showDate = YES;
}
}
return kJSQMessagesCollectionViewCellLabelHeightDefault;
return showDate;
}
- (CGFloat)collectionView:(JSQMessagesCollectionView *)collectionView
@ -319,41 +268,6 @@ typedef enum : NSUInteger {
#pragma mark - Actions
-(void)didPressAccessoryButton:(UIButton *)sender
{
[self.inputToolbar.contentView.textView resignFirstResponder];
UIView *presenter = self.parentViewController.view;
[DJWActionSheet showInView:presenter
withTitle:nil
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@[@"Take Photo or Video", @"Choose existing Photo", @"Choose existing Video", @"Send file"]
tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
NSLog(@"User Cancelled");
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
NSLog(@"Destructive button tapped");
}else {
switch (tappedButtonIndex) {
case 0:
[self takePictureOrVideo];
break;
case 1:
[self chooseFromLibrary:kMediaTypePicture];
break;
case 2:
[self chooseFromLibrary:kMediaTypeVideo];
break;
default:
break;
}
}
}];
}
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath
{
id<JSQMessageData> messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
@ -363,12 +277,11 @@ typedef enum : NSUInteger {
if (isMediaMessage) {
id<JSQMessageMediaData> messageMedia = [messageItem media];
if ([messageMedia isKindOfClass:JSQPhotoMediaItem.class]) {
//is a photo
tappedImage = ((JSQPhotoMediaItem*)messageMedia).image ;
[self performSegueWithIdentifier:@"fullImage" sender:self];
} else if ([messageMedia isKindOfClass:JSQVideoMediaItem.class]) {
//is a video
}
@ -408,7 +321,7 @@ typedef enum : NSUInteger {
picker.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *)kUTTypeMovie, kUTTypeImage, kUTTypeVideo, nil];
[self presentViewController:picker animated:YES completion:NULL];
}
}
-(void)chooseFromLibrary:(kMediaTypes)mediaType
@ -424,7 +337,7 @@ typedef enum : NSUInteger {
NSArray* videoTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo, nil];
picker.mediaTypes = (mediaType == kMediaTypePicture) ? pictureTypeArray : videoTypeArray;
[self presentViewController:picker animated:YES completion:nil];
}
}
@ -462,9 +375,9 @@ typedef enum : NSUInteger {
JSQVideoMediaItem * videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES];
JSQMessage * videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdDylan
displayName:kJSQDemoAvatarDisplayNameDylan
media:videoItem];
[self.demoData.messages addObject:videoMessage];
displayName:kJSQDemoAvatarDisplayNameDylan
media:videoItem];
[self finishSendingMessage];
} else if (picture_camera) {
@ -472,14 +385,110 @@ typedef enum : NSUInteger {
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:picture_camera];
JSQMessage *photoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdDylan
displayName:kJSQDemoAvatarDisplayNameDylan
media:photoItem];
[self.demoData.messages addObject:photoMessage];
displayName:kJSQDemoAvatarDisplayNameDylan
media:photoItem];
[self finishSendingMessage];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark Storage access
- (YapDatabaseConnection *)uiDatabaseConnection
{
NSAssert([NSThread isMainThread], @"Must access uiDatabaseConnection on main thread!");
if (!_uiDatabaseConnection) {
_uiDatabaseConnection = [[TSStorageManager sharedManager] newDatabaseConnection];
[_uiDatabaseConnection beginLongLivedReadTransaction];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:nil];
}
return _uiDatabaseConnection;
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
// Process the notification(s),
// and get the change-set(s) as applies to my view and mappings configuration.
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
NSArray *messageRowChanges = nil;
[[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] getSectionChanges:nil
rowChanges:&messageRowChanges
forNotifications:notifications
withMappings:self.messageMappings];
[self.collectionView reloadData];
[self finishReceivingMessage];
}
#pragma mark - UICollectionView DataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
NSInteger numberOfMessages = [self.messageMappings numberOfItemsInSection:section];
return numberOfMessages;
}
- (TSInteraction*)messageAtIndexPath:(NSIndexPath *)indexPath
{
__block TSInteraction *message = nil;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
NSParameterAssert(viewTransaction != nil);
NSParameterAssert(self.messageMappings != nil);
NSParameterAssert(indexPath != nil);
NSUInteger row = indexPath.row;
NSUInteger section = indexPath.section;
NSUInteger numberOfItemsInSection = [self.messageMappings numberOfItemsInSection:section];
NSAssert(row < numberOfItemsInSection, @"Cannot fetch message because row %d is >= numberOfItemsInSection %d", (int)row, (int)numberOfItemsInSection);
message = [viewTransaction objectAtRow:row inSection:section withMappings:self.messageMappings];
NSParameterAssert(message != nil);
}];
return message;
}
#pragma mark Accessory View
-(void)didPressAccessoryButton:(UIButton *)sender
{
[self.inputToolbar.contentView.textView resignFirstResponder];
UIView *presenter = self.parentViewController.view;
[DJWActionSheet showInView:presenter
withTitle:nil
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@[@"Take Photo or Video", @"Choose existing Photo", @"Choose existing Video", @"Send file"]
tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
NSLog(@"User Cancelled");
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
NSLog(@"Destructive button tapped");
}else {
switch (tappedButtonIndex) {
case 0:
[self takePictureOrVideo];
break;
case 1:
[self chooseFromLibrary:kMediaTypePicture];
break;
case 2:
[self chooseFromLibrary:kMediaTypeVideo];
break;
default:
break;
}
}
}];
}
@end

View File

@ -13,13 +13,11 @@
@interface RegistrationViewController : UIViewController<CountryCodeViewControllerDelegate, UITextFieldDelegate>
// Country code
@property(nonatomic, strong) IBOutlet UIButton* countryCodeButton;
@property(nonatomic, strong) IBOutlet UILabel* countryNameLabel;
@property(nonatomic, strong) IBOutlet UILabel* countryCodeLabel;
@property (nonatomic, strong) IBOutlet UIButton * countryCodeButton;
@property (nonatomic, strong) IBOutlet UILabel * countryNameLabel;
@property (nonatomic, strong) IBOutlet UILabel * countryCodeLabel;
//Phone number
@property(nonatomic, strong) IBOutlet UITextField* phoneNumberTextField;
@end

View File

@ -0,0 +1,20 @@
//
// TSMessageAdapter.h
// Signal
//
// Created by Frederic Jacobs on 24/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JSQMessagesViewController/JSQMessageData.h>
#import "TSMessageAdapter.h"
#import "TSInteraction.h"
#import "TSThread.h"
@interface TSMessageAdapter : NSObject <JSQMessageData>
+ (instancetype)messageViewDataWithInteraction:(TSInteraction*)interaction inThread:(TSThread*)thread;
@end

View File

@ -0,0 +1,93 @@
//
// TSMessageAdapter.m
// Signal
//
// Created by Frederic Jacobs on 24/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "TSMessageAdapter.h"
#import "TSIncomingMessage.h"
#import "TSOutgoingMessage.h"
#import "TSCall.h"
#import "TSInfoMessage.h"
#import "TSErrorMessage.h"
@interface TSMessageAdapter ()
// ---
@property (nonatomic, retain) TSContactThread *thread;
// OR for groups
@property (nonatomic, retain) NSString *senderId;
@property (nonatomic, retain) NSString *senderDisplayName;
// ---
@property (nonatomic, copy) NSDate *messageDate;
@property (nonatomic, retain) NSString *messageBody;
@end
@implementation TSMessageAdapter
+ (instancetype)messageViewDataWithInteraction:(TSInteraction*)interaction inThread:(TSThread*)thread{
TSMessageAdapter *adapter = [[TSMessageAdapter alloc] init];
adapter.messageDate = interaction.date;
if ([thread isKindOfClass:[TSContactThread class]]) {
adapter.thread = (TSContactThread*)thread;
} else if ([thread isKindOfClass:[TSGroupThread class]]){
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *message = (TSIncomingMessage*)interaction;
adapter.senderId = message.authorId;
adapter.senderDisplayName = message.authorId;
} else{
adapter.senderId = @"self";
adapter.senderDisplayName = @"Me";
}
}
if ([interaction isKindOfClass:[TSMessage class]]) {
TSMessage *message = (TSMessage*)interaction;
adapter.messageBody = message.body;
} else if ([interaction isKindOfClass:[TSCall class]]){
adapter.messageBody = @"Placeholder for TSCalls";
} else if ([interaction isKindOfClass:[TSInfoMessage class]]){
adapter.messageBody = @"Placeholder for InfoMessage";
} else{
adapter.messageBody = @"Placeholder for ErrorMessage";
}
return adapter;
}
- (NSString*)senderId{
return self.thread.uniqueId;
}
- (NSString *)senderDisplayName{
if (self.thread) {
return _thread.name;
}
return self.senderDisplayName;
}
- (NSDate *)date{
return self.messageDate;
}
- (BOOL)isMediaMessage{
return NO;
}
- (NSString *)text{
return self.messageBody;
}
@end

View File

@ -15,6 +15,7 @@
#import "TSStorageManager.h"
#import "TSDatabaseView.h"
#import "TSSocketManager.h"
#import "TSContactThread.h"
#import <YapDatabase/YapDatabaseViewChange.h>
#import "YapDatabaseViewTransaction.h"
@ -161,14 +162,15 @@ static NSString *const kSegueIndentifier = @"showSegue";
if ([segue.identifier isEqualToString:kSegueIndentifier])
{
MessagesViewController * vc = [segue destinationViewController];
MessagesViewController * vc = [segue destinationViewController];
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
if (selectedIndexPath) {
vc.senderTitleString = ((DemoDataModel*)_dataArray[(NSUInteger)selectedIndexPath.row])._sender;
} else if (_contactFromCompose) {
vc.senderTitleString = _contactFromCompose.fullName;
} else if (_groupFromCompose) {
vc.senderTitleString = _groupFromCompose.groupName;
vc.thread = [self threadForIndexPath:selectedIndexPath];
if (!vc.thread) {
[TSStorageManager.sharedManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
vc.thread = [TSContactThread threadWithContactId:[self.contactFromCompose.userTextPhoneNumbers firstObject] transaction:transaction];
NSLog(@"Thread:%@", vc.thread);
}];
}
}