Integrating Message View.
This commit is contained in:
parent
84e12a39c9
commit
d73e42beff
|
@ -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 */,
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
+ (instancetype)threadWithContactId:(NSString*)contactId transaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
|
||||
- (TSRecipient*)recipient;
|
||||
- (NSString*)contactIdentifier;
|
||||
- (TSRecipient *)recipientWithTransaction:(YapDatabaseReadTransaction*)transaction;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#import "JSQMessagesKeyboardController.h"
|
||||
|
||||
|
||||
@interface MessageComposeTableViewController : UITableViewController
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -140,8 +140,6 @@
|
|||
|
||||
s.contactFromCompose = [self contactForIndexPath:indexPath];
|
||||
|
||||
[self.searchController dismissViewControllerAnimated:NO completion:nil];
|
||||
|
||||
[self dismissViewControllerAnimated:YES completion:^(){
|
||||
[s performSegueWithIdentifier:@"showSegue" sender:nil];
|
||||
}];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue