Explain send failures for text and media messages
fixes #1231 Motivation ---------- Previously when messages failed to send, there was no reason given. Furthermore, when media messages failed to send there was no indication that any attempt to send the message even occurred, nor a retry dialog. UX Changes ---------- - Show "uploading" status for media - Show specific error message in retry-send dialog - Only scroll to bottom when new message is inserted - Show specific errors when group creation fails Code Changes ----------- - Updated incorrect references to TSMessageAdapters which were actually references to OWSMessageData - MessageSender was extracted from SSK MessagesManager - access MessagesManager as property - idiomatic init/properties for Env - log contact intersections - Move scroll-to-bottom animation to main thread. // FREEBIE
This commit is contained in:
parent
7c32259a92
commit
33f6a95520
2
Podfile
2
Podfile
|
@ -3,7 +3,7 @@ source 'https://github.com/CocoaPods/Specs.git'
|
||||||
|
|
||||||
target 'Signal' do
|
target 'Signal' do
|
||||||
pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git'
|
pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git'
|
||||||
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git'
|
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git', branch: 'mkirk/outgoing-media-status#1231'
|
||||||
#pod 'SignalServiceKit', path: '../SignalServiceKit'
|
#pod 'SignalServiceKit', path: '../SignalServiceKit'
|
||||||
pod 'OpenSSL'
|
pod 'OpenSSL'
|
||||||
pod 'PastelogKit', '~> 1.3'
|
pod 'PastelogKit', '~> 1.3'
|
||||||
|
|
23
Podfile.lock
23
Podfile.lock
|
@ -33,10 +33,10 @@ PODS:
|
||||||
- JSQMessagesViewController (7.3.4):
|
- JSQMessagesViewController (7.3.4):
|
||||||
- JSQSystemSoundPlayer (~> 2.0.1)
|
- JSQSystemSoundPlayer (~> 2.0.1)
|
||||||
- JSQSystemSoundPlayer (2.0.1)
|
- JSQSystemSoundPlayer (2.0.1)
|
||||||
- libPhoneNumber-iOS (0.8.16)
|
- libPhoneNumber-iOS (0.8.17)
|
||||||
- Mantle (2.0.7):
|
- Mantle (2.1.0):
|
||||||
- Mantle/extobjc (= 2.0.7)
|
- Mantle/extobjc (= 2.1.0)
|
||||||
- Mantle/extobjc (2.0.7)
|
- Mantle/extobjc (2.1.0)
|
||||||
- OpenSSL (1.0.210)
|
- OpenSSL (1.0.210)
|
||||||
- PastelogKit (1.3):
|
- PastelogKit (1.3):
|
||||||
- CocoaLumberjack (~> 2.0)
|
- CocoaLumberjack (~> 2.0)
|
||||||
|
@ -44,7 +44,7 @@ PODS:
|
||||||
- Reachability (3.2)
|
- Reachability (3.2)
|
||||||
- SAMKeychain (1.5.2)
|
- SAMKeychain (1.5.2)
|
||||||
- SCWaveformView (1.0.0)
|
- SCWaveformView (1.0.0)
|
||||||
- SignalServiceKit (0.2.0):
|
- SignalServiceKit (0.3.0):
|
||||||
- '25519'
|
- '25519'
|
||||||
- AFNetworking
|
- AFNetworking
|
||||||
- AxolotlKit
|
- AxolotlKit
|
||||||
|
@ -122,19 +122,20 @@ DEPENDENCIES:
|
||||||
- OpenSSL
|
- OpenSSL
|
||||||
- PastelogKit (~> 1.3)
|
- PastelogKit (~> 1.3)
|
||||||
- SCWaveformView (~> 1.0)
|
- SCWaveformView (~> 1.0)
|
||||||
- SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`)
|
- SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`, branch `mkirk/outgoing-media-status#1231`)
|
||||||
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
|
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
|
||||||
- ZXingObjC
|
- ZXingObjC
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
SignalServiceKit:
|
SignalServiceKit:
|
||||||
|
:branch: mkirk/outgoing-media-status#1231
|
||||||
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
||||||
SocketRocket:
|
SocketRocket:
|
||||||
:git: https://github.com/facebook/SocketRocket.git
|
:git: https://github.com/facebook/SocketRocket.git
|
||||||
|
|
||||||
CHECKOUT OPTIONS:
|
CHECKOUT OPTIONS:
|
||||||
SignalServiceKit:
|
SignalServiceKit:
|
||||||
:commit: d4c55d69404c99927da716c443997415ad7bc6ba
|
:commit: 4ba1e86ec12c4e28de264fea59bd57af0aa3edea
|
||||||
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
||||||
SocketRocket:
|
SocketRocket:
|
||||||
:commit: 41b57bb2fc292a814f758441a05243eb38457027
|
:commit: 41b57bb2fc292a814f758441a05243eb38457027
|
||||||
|
@ -150,15 +151,15 @@ SPEC CHECKSUMS:
|
||||||
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
|
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
|
||||||
JSQMessagesViewController: 39fed975e3c9f8eba7292071e29eeb541d105e66
|
JSQMessagesViewController: 39fed975e3c9f8eba7292071e29eeb541d105e66
|
||||||
JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
|
JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
|
||||||
libPhoneNumber-iOS: acb5805f67892db37adc3440290a367923672b51
|
libPhoneNumber-iOS: 9f083847f8cb9b81064cff2ed2c98cbf18d9f9f2
|
||||||
Mantle: bc40bb061d8c2c6fb48d5083e04d928c3b7f73d9
|
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
|
||||||
OpenSSL: 246ffb948e9d56466727fd318134af35f5aa764e
|
OpenSSL: 246ffb948e9d56466727fd318134af35f5aa764e
|
||||||
PastelogKit: 7b475be4cf577713506a943dd940bcc0499c8bca
|
PastelogKit: 7b475be4cf577713506a943dd940bcc0499c8bca
|
||||||
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
|
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
|
||||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||||
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
|
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
|
||||||
SCWaveformView: 52a96750255d817e300565a80c81fb643e233e07
|
SCWaveformView: 52a96750255d817e300565a80c81fb643e233e07
|
||||||
SignalServiceKit: 4e7a552635e10f4d94f0a047fc6554e932340b30
|
SignalServiceKit: 8b115cfd63f9b814fa03fe61fd5d38ef9a548460
|
||||||
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
|
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
|
||||||
SQLCipher: 4c768761421736a247ed6cf412d9045615d53dff
|
SQLCipher: 4c768761421736a247ed6cf412d9045615d53dff
|
||||||
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
|
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
|
||||||
|
@ -166,6 +167,6 @@ SPEC CHECKSUMS:
|
||||||
YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f
|
YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f
|
||||||
ZXingObjC: bf15b3814f7a105b6d99f47da2333c93a063650a
|
ZXingObjC: bf15b3814f7a105b6d99f47da2333c93a063650a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 93ccdbbb243044904d772ee53e00154890a9f82f
|
PODFILE CHECKSUM: 7dfde19734213e4ff876efa2ea10d536da2e0b47
|
||||||
|
|
||||||
COCOAPODS: 1.0.1
|
COCOAPODS: 1.0.1
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.6.2</string>
|
<string>2.6.3</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.6.2.0</string>
|
<string>2.6.3.4</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LOGS_EMAIL</key>
|
<key>LOGS_EMAIL</key>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#import "Environment.h"
|
#import "Environment.h"
|
||||||
#import "NotificationsManager.h"
|
#import "NotificationsManager.h"
|
||||||
#import "OWSContactsManager.h"
|
#import "OWSContactsManager.h"
|
||||||
|
#import "OWSStaleNotificationObserver.h"
|
||||||
#import "PreferencesUtil.h"
|
#import "PreferencesUtil.h"
|
||||||
#import "PushManager.h"
|
#import "PushManager.h"
|
||||||
#import "Release.h"
|
#import "Release.h"
|
||||||
|
@ -15,9 +16,9 @@
|
||||||
#import "TSSocketManager.h"
|
#import "TSSocketManager.h"
|
||||||
#import "TextSecureKitEnv.h"
|
#import "TextSecureKitEnv.h"
|
||||||
#import "VersionMigrations.h"
|
#import "VersionMigrations.h"
|
||||||
#import "OWSStaleNotificationObserver.h"
|
|
||||||
#import <SignalServiceKit/OWSDisappearingMessagesJob.h>
|
#import <SignalServiceKit/OWSDisappearingMessagesJob.h>
|
||||||
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
|
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
|
|
||||||
static NSString *const kStoryboardName = @"Storyboard";
|
static NSString *const kStoryboardName = @"Storyboard";
|
||||||
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
|
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
|
||||||
|
@ -128,8 +129,16 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
[TextSecureKitEnv sharedEnv].contactsManager = [Environment getCurrent].contactsManager;
|
[TextSecureKitEnv sharedEnv].contactsManager = [Environment getCurrent].contactsManager;
|
||||||
[[TSStorageManager sharedManager] setupDatabase];
|
[[TSStorageManager sharedManager] setupDatabase];
|
||||||
[TextSecureKitEnv sharedEnv].notificationsManager = [[NotificationsManager alloc] init];
|
[TextSecureKitEnv sharedEnv].notificationsManager = [[NotificationsManager alloc] init];
|
||||||
self.incomingMessageReadObserver = [[OWSIncomingMessageReadObserver alloc] initWithStorageManager:[TSStorageManager sharedManager]
|
|
||||||
messagesManager:[TSMessagesManager sharedManager]];
|
OWSMessageSender *messageSender =
|
||||||
|
[[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsManager:[Environment getCurrent].contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
|
||||||
|
self.incomingMessageReadObserver =
|
||||||
|
[[OWSIncomingMessageReadObserver alloc] initWithStorageManager:[TSStorageManager sharedManager]
|
||||||
|
messageSender:messageSender];
|
||||||
[self.incomingMessageReadObserver startObserving];
|
[self.incomingMessageReadObserver startObserving];
|
||||||
|
|
||||||
self.staleNotificationObserver = [OWSStaleNotificationObserver new];
|
self.staleNotificationObserver = [OWSStaleNotificationObserver new];
|
||||||
|
|
|
@ -178,6 +178,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOutgoingAndDelivered
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSUInteger)messageHash
|
- (NSUInteger)messageHash
|
||||||
{
|
{
|
||||||
return self.hash;
|
return self.hash;
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
|
||||||
@property (nonatomic, readonly) TSMessageAdapterType messageType;
|
@property (nonatomic, readonly) TSMessageAdapterType messageType;
|
||||||
@property (nonatomic, readonly) TSInteraction *interaction;
|
@property (nonatomic, readonly) TSInteraction *interaction;
|
||||||
@property (nonatomic, readonly) BOOL isExpiringMessage;
|
@property (nonatomic, readonly) BOOL isExpiringMessage;
|
||||||
|
@property (nonatomic, readonly) BOOL isOutgoingAndDelivered;
|
||||||
@property (nonatomic, readonly) BOOL shouldStartExpireTimer;
|
@property (nonatomic, readonly) BOOL shouldStartExpireTimer;
|
||||||
@property (nonatomic, readonly) uint64_t expiresAtSeconds;
|
@property (nonatomic, readonly) uint64_t expiresAtSeconds;
|
||||||
@property (nonatomic, readonly) uint32_t expiresInSeconds;
|
@property (nonatomic, readonly) uint32_t expiresInSeconds;
|
||||||
|
|
|
@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@property (nonatomic) TSInteraction *interaction;
|
@property (nonatomic) TSInteraction *interaction;
|
||||||
@property (readonly) TSInfoMessageType infoMessageType;
|
@property (readonly) TSInfoMessageType infoMessageType;
|
||||||
|
@property (nonatomic, readonly) CGFloat mediaViewAlpha;
|
||||||
|
@property (nonatomic, readonly) BOOL isOutgoingAndDelivered;
|
||||||
|
@property (nonatomic, readonly) BOOL isMediaBeingSent;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -305,4 +305,31 @@
|
||||||
return self.outgoingMessageStatus;
|
return self.outgoingMessageStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGFloat)mediaViewAlpha
|
||||||
|
{
|
||||||
|
return (CGFloat)(self.isMediaBeingSent ? 0.75 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isMediaBeingSent
|
||||||
|
{
|
||||||
|
if ([self.interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||||
|
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.interaction;
|
||||||
|
if (outgoingMessage.hasAttachments && outgoingMessage.messageState == TSOutgoingMessageStateAttemptingOut) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOutgoingAndDelivered
|
||||||
|
{
|
||||||
|
if ([self.interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||||
|
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.interaction;
|
||||||
|
if (outgoingMessage.messageState == TSOutgoingMessageStateDelivered) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -225,7 +225,7 @@
|
||||||
_maskLayer.hidden = YES;
|
_maskLayer.hidden = YES;
|
||||||
_progressView.hidden = YES;
|
_progressView.hidden = YES;
|
||||||
_videoPlayButton.hidden = NO;
|
_videoPlayButton.hidden = NO;
|
||||||
_attachment.isDownloaded = YES;
|
_attachment.isDownloaded = YES; // TODO isn't this redundant with attachment processor?
|
||||||
[[TSMessagesManager sharedManager]
|
[[TSMessagesManager sharedManager]
|
||||||
.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
[_attachment saveWithTransaction:transaction];
|
[_attachment saveWithTransaction:transaction];
|
||||||
|
|
|
@ -91,13 +91,16 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
||||||
- (void)intersectContacts {
|
- (void)intersectContacts {
|
||||||
[[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.allContacts
|
[[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.allContacts
|
||||||
success:^{
|
success:^{
|
||||||
|
DDLogInfo(@"%@ Successfully intersected contacts.", self.tag);
|
||||||
}
|
}
|
||||||
failure:^(NSError *error) {
|
failure:^(NSError *error) {
|
||||||
[NSTimer scheduledTimerWithTimeInterval:60
|
DDLogWarn(@"%@ Failed to intersect contacts with error: %@. Rescheduling", self.tag, error);
|
||||||
target:self
|
|
||||||
selector:@selector(intersectContacts)
|
[NSTimer scheduledTimerWithTimeInterval:60
|
||||||
userInfo:nil
|
target:self
|
||||||
repeats:NO];
|
selector:@selector(intersectContacts)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:NO];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,4 +426,16 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Logging
|
||||||
|
|
||||||
|
+ (NSString *)tag
|
||||||
|
{
|
||||||
|
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)tag
|
||||||
|
{
|
||||||
|
return self.class.tag;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -29,8 +29,28 @@ static NSString *const kCallSegue = @"2.0_6.0_Call_Segue";
|
||||||
@class PhoneManager;
|
@class PhoneManager;
|
||||||
@class SignalsViewController;
|
@class SignalsViewController;
|
||||||
@class TSGroupThread;
|
@class TSGroupThread;
|
||||||
|
@class ContactsUpdater;
|
||||||
|
@class TSNetworkManager;
|
||||||
|
|
||||||
@interface Environment : NSObject
|
@interface Environment : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithLogging:(id<Logging>)logging
|
||||||
|
errorNoter:(ErrorHandlerBlock)errorNoter
|
||||||
|
serverPort:(in_port_t)serverPort
|
||||||
|
masterServerHostName:(NSString *)masterServerHostName
|
||||||
|
defaultRelayName:(NSString *)defaultRelayName
|
||||||
|
relayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
||||||
|
certificate:(Certificate *)certificate
|
||||||
|
supportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
||||||
|
phoneManager:(PhoneManager *)phoneManager
|
||||||
|
recentCallManager:(RecentCallManager *)recentCallManager
|
||||||
|
testingAndLegacyOptions:(NSArray *)testingAndLegacyOptions
|
||||||
|
zrtpClientId:(NSData *)zrtpClientId
|
||||||
|
zrtpVersionId:(NSData *)zrtpVersionId
|
||||||
|
contactsManager:(OWSContactsManager *)contactsManager
|
||||||
|
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||||
|
networkManager:(TSNetworkManager *)networkManager;
|
||||||
|
|
||||||
@property (nonatomic, readonly) in_port_t serverPort;
|
@property (nonatomic, readonly) in_port_t serverPort;
|
||||||
@property (nonatomic, readonly) id<Logging> logging;
|
@property (nonatomic, readonly) id<Logging> logging;
|
||||||
@property (nonatomic, readonly) SecureEndPoint *masterServerSecureEndPoint;
|
@property (nonatomic, readonly) SecureEndPoint *masterServerSecureEndPoint;
|
||||||
|
@ -45,6 +65,8 @@ static NSString *const kCallSegue = @"2.0_6.0_Call_Segue";
|
||||||
@property (nonatomic, readonly) NSData *zrtpClientId;
|
@property (nonatomic, readonly) NSData *zrtpClientId;
|
||||||
@property (nonatomic, readonly) NSData *zrtpVersionId;
|
@property (nonatomic, readonly) NSData *zrtpVersionId;
|
||||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||||
|
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
|
||||||
|
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||||
|
|
||||||
@property (nonatomic, readonly) SignalsViewController *signalsViewController;
|
@property (nonatomic, readonly) SignalsViewController *signalsViewController;
|
||||||
@property (nonatomic, readonly, weak) UINavigationController *signUpFlowNavigationController;
|
@property (nonatomic, readonly, weak) UINavigationController *signUpFlowNavigationController;
|
||||||
|
@ -53,21 +75,6 @@ static NSString *const kCallSegue = @"2.0_6.0_Call_Segue";
|
||||||
+ (SecureEndPoint *)getSecureEndPointToDefaultRelayServer;
|
+ (SecureEndPoint *)getSecureEndPointToDefaultRelayServer;
|
||||||
+ (SecureEndPoint *)getSecureEndPointToSignalingServerNamed:(NSString *)name;
|
+ (SecureEndPoint *)getSecureEndPointToSignalingServerNamed:(NSString *)name;
|
||||||
|
|
||||||
+ (Environment *)environmentWithLogging:(id<Logging>)logging
|
|
||||||
andErrorNoter:(ErrorHandlerBlock)errorNoter
|
|
||||||
andServerPort:(in_port_t)serverPort
|
|
||||||
andMasterServerHostName:(NSString *)masterServerHostName
|
|
||||||
andDefaultRelayName:(NSString *)defaultRelayName
|
|
||||||
andRelayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
|
||||||
andCertificate:(Certificate *)certificate
|
|
||||||
andSupportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
|
||||||
andPhoneManager:(PhoneManager *)phoneManager
|
|
||||||
andRecentCallManager:(RecentCallManager *)recentCallManager
|
|
||||||
andTestingAndLegacyOptions:(NSArray *)testingAndLegacyOptions
|
|
||||||
andZrtpClientId:(NSData *)zrtpClientId
|
|
||||||
andZrtpVersionId:(NSData *)zrtpVersionId
|
|
||||||
andContactsManager:(OWSContactsManager *)contactsManager;
|
|
||||||
|
|
||||||
+ (Environment *)getCurrent;
|
+ (Environment *)getCurrent;
|
||||||
+ (void)setCurrent:(Environment *)curEnvironment;
|
+ (void)setCurrent:(Environment *)curEnvironment;
|
||||||
+ (id<Logging>)logging;
|
+ (id<Logging>)logging;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
#import "Environment.h"
|
||||||
#import "Constraints.h"
|
#import "Constraints.h"
|
||||||
#import "DH3KKeyAgreementProtocol.h"
|
#import "DH3KKeyAgreementProtocol.h"
|
||||||
#import "DebugLogger.h"
|
#import "DebugLogger.h"
|
||||||
#import "Environment.h"
|
|
||||||
#import "FunctionalUtil.h"
|
#import "FunctionalUtil.h"
|
||||||
#import "KeyAgreementProtocol.h"
|
#import "KeyAgreementProtocol.h"
|
||||||
#import "MessagesViewController.h"
|
#import "MessagesViewController.h"
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
#import "SignalsViewController.h"
|
#import "SignalsViewController.h"
|
||||||
#import "TSContactThread.h"
|
#import "TSContactThread.h"
|
||||||
#import "TSGroupThread.h"
|
#import "TSGroupThread.h"
|
||||||
|
#import <SignalServiceKit/ContactsUpdater.h>
|
||||||
|
|
||||||
#define isRegisteredUserDefaultString @"isRegistered"
|
#define isRegisteredUserDefaultString @"isRegistered"
|
||||||
|
|
||||||
|
@ -17,10 +18,6 @@ static Environment *environment = nil;
|
||||||
|
|
||||||
@implementation Environment
|
@implementation Environment
|
||||||
|
|
||||||
@synthesize testingAndLegacyOptions, errorNoter, keyAgreementProtocolsInDescendingPriority, logging,
|
|
||||||
masterServerSecureEndPoint, defaultRelayName, relayServerHostNameSuffix, certificate, serverPort, zrtpClientId,
|
|
||||||
zrtpVersionId, phoneManager, recentCallManager, contactsManager;
|
|
||||||
|
|
||||||
+ (Environment *)getCurrent {
|
+ (Environment *)getCurrent {
|
||||||
NSAssert((environment != nil), @"Environment is not defined.");
|
NSAssert((environment != nil), @"Environment is not defined.");
|
||||||
return environment;
|
return environment;
|
||||||
|
@ -54,20 +51,23 @@ static Environment *environment = nil;
|
||||||
return [SecureEndPoint secureEndPointForHost:location identifiedByCertificate:env.certificate];
|
return [SecureEndPoint secureEndPointForHost:location identifiedByCertificate:env.certificate];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Environment *)environmentWithLogging:(id<Logging>)logging
|
- (instancetype)initWithLogging:(id<Logging>)logging
|
||||||
andErrorNoter:(ErrorHandlerBlock)errorNoter
|
errorNoter:(ErrorHandlerBlock)errorNoter
|
||||||
andServerPort:(in_port_t)serverPort
|
serverPort:(in_port_t)serverPort
|
||||||
andMasterServerHostName:(NSString *)masterServerHostName
|
masterServerHostName:(NSString *)masterServerHostName
|
||||||
andDefaultRelayName:(NSString *)defaultRelayName
|
defaultRelayName:(NSString *)defaultRelayName
|
||||||
andRelayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
relayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
||||||
andCertificate:(Certificate *)certificate
|
certificate:(Certificate *)certificate
|
||||||
andSupportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
supportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
||||||
andPhoneManager:(PhoneManager *)phoneManager
|
phoneManager:(PhoneManager *)phoneManager
|
||||||
andRecentCallManager:(RecentCallManager *)recentCallManager
|
recentCallManager:(RecentCallManager *)recentCallManager
|
||||||
andTestingAndLegacyOptions:(NSArray *)testingAndLegacyOptions
|
testingAndLegacyOptions:(NSArray *)testingAndLegacyOptions
|
||||||
andZrtpClientId:(NSData *)zrtpClientId
|
zrtpClientId:(NSData *)zrtpClientId
|
||||||
andZrtpVersionId:(NSData *)zrtpVersionId
|
zrtpVersionId:(NSData *)zrtpVersionId
|
||||||
andContactsManager:(OWSContactsManager *)contactsManager {
|
contactsManager:(OWSContactsManager *)contactsManager
|
||||||
|
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||||
|
networkManager:(TSNetworkManager *)networkManager
|
||||||
|
{
|
||||||
ows_require(errorNoter != nil);
|
ows_require(errorNoter != nil);
|
||||||
ows_require(zrtpClientId != nil);
|
ows_require(zrtpClientId != nil);
|
||||||
ows_require(zrtpVersionId != nil);
|
ows_require(zrtpVersionId != nil);
|
||||||
|
@ -82,23 +82,29 @@ static Environment *environment = nil;
|
||||||
return [p isKindOfClass:DH3KKeyAgreementProtocol.class];
|
return [p isKindOfClass:DH3KKeyAgreementProtocol.class];
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
Environment *e = [Environment new];
|
self = [super init];
|
||||||
e->errorNoter = errorNoter;
|
if (!self) {
|
||||||
e->logging = logging;
|
return self;
|
||||||
e->testingAndLegacyOptions = testingAndLegacyOptions;
|
}
|
||||||
e->serverPort = serverPort;
|
|
||||||
e->masterServerSecureEndPoint = [SecureEndPoint
|
_errorNoter = errorNoter;
|
||||||
|
_logging = logging;
|
||||||
|
_testingAndLegacyOptions = testingAndLegacyOptions;
|
||||||
|
_serverPort = serverPort;
|
||||||
|
_masterServerSecureEndPoint = [SecureEndPoint
|
||||||
secureEndPointForHost:[HostNameEndPoint hostNameEndPointWithHostName:masterServerHostName andPort:serverPort]
|
secureEndPointForHost:[HostNameEndPoint hostNameEndPointWithHostName:masterServerHostName andPort:serverPort]
|
||||||
identifiedByCertificate:certificate];
|
identifiedByCertificate:certificate];
|
||||||
e->defaultRelayName = defaultRelayName;
|
|
||||||
e->certificate = certificate;
|
_defaultRelayName = defaultRelayName;
|
||||||
e->relayServerHostNameSuffix = relayServerHostNameSuffix;
|
_certificate = certificate;
|
||||||
e->keyAgreementProtocolsInDescendingPriority = keyAgreementProtocolsInDescendingPriority;
|
_relayServerHostNameSuffix = relayServerHostNameSuffix;
|
||||||
e->phoneManager = phoneManager;
|
_keyAgreementProtocolsInDescendingPriority = keyAgreementProtocolsInDescendingPriority;
|
||||||
e->recentCallManager = recentCallManager;
|
_phoneManager = phoneManager;
|
||||||
e->zrtpClientId = zrtpClientId;
|
_recentCallManager = recentCallManager;
|
||||||
e->zrtpVersionId = zrtpVersionId;
|
_zrtpClientId = zrtpClientId;
|
||||||
e->contactsManager = contactsManager;
|
_zrtpVersionId = zrtpVersionId;
|
||||||
|
_contactsManager = contactsManager;
|
||||||
|
_networkManager = networkManager;
|
||||||
|
|
||||||
if (recentCallManager != nil) {
|
if (recentCallManager != nil) {
|
||||||
// recentCallManagers are nil in unit tests because they would require unnecessary allocations. Detailed
|
// recentCallManagers are nil in unit tests because they would require unnecessary allocations. Detailed
|
||||||
|
@ -107,12 +113,13 @@ static Environment *environment = nil;
|
||||||
[recentCallManager watchForCallsThrough:phoneManager untilCancelled:nil];
|
[recentCallManager watchForCallsThrough:phoneManager untilCancelled:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (PhoneManager *)phoneManager {
|
+ (PhoneManager *)phoneManager {
|
||||||
return Environment.getCurrent.phoneManager;
|
return Environment.getCurrent.phoneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id<Logging>)logging {
|
+ (id<Logging>)logging {
|
||||||
// Many tests create objects that rely on Environment only for logging.
|
// Many tests create objects that rely on Environment only for logging.
|
||||||
// So we bypass the nil check in getCurrent and silently don't log during unit testing, instead of failing hard.
|
// So we bypass the nil check in getCurrent and silently don't log during unit testing, instead of failing hard.
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
#import "Release.h"
|
||||||
#import "DiscardingLog.h"
|
#import "DiscardingLog.h"
|
||||||
#import "PhoneManager.h"
|
#import "PhoneManager.h"
|
||||||
#import "PhoneNumberUtil.h"
|
#import "PhoneNumberUtil.h"
|
||||||
#import "RecentCallManager.h"
|
#import "RecentCallManager.h"
|
||||||
#import "Release.h"
|
#import <SignalServiceKit/ContactsUpdater.h>
|
||||||
|
#import <SignalServiceKit/TSNetworkManager.h>
|
||||||
|
|
||||||
#define RELEASE_ZRTP_CLIENT_ID @"Whisper 000 ".encodedAsAscii
|
#define RELEASE_ZRTP_CLIENT_ID @"Whisper 000 ".encodedAsAscii
|
||||||
#define RELEASE_ZRTP_VERSION_ID @"1.10".encodedAsAscii
|
#define RELEASE_ZRTP_VERSION_ID @"1.10".encodedAsAscii
|
||||||
|
@ -42,23 +44,22 @@ static unsigned char DH3K_PRIME[] = {
|
||||||
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
||||||
};
|
};
|
||||||
|
|
||||||
return [Environment
|
return [[Environment alloc] initWithLogging:logging
|
||||||
environmentWithLogging:logging
|
errorNoter:errorNoter
|
||||||
andErrorNoter:errorNoter
|
serverPort:31337
|
||||||
andServerPort:31337
|
masterServerHostName:@"master.whispersystems.org"
|
||||||
andMasterServerHostName:@"master.whispersystems.org"
|
defaultRelayName:@"relay"
|
||||||
andDefaultRelayName:@"relay"
|
relayServerHostNameSuffix:@"whispersystems.org"
|
||||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
certificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
supportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
||||||
andSupportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
phoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
||||||
andPhoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
recentCallManager:[RecentCallManager new]
|
||||||
andRecentCallManager:[RecentCallManager new]
|
testingAndLegacyOptions:@[ ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER ]
|
||||||
andTestingAndLegacyOptions:@[
|
zrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
||||||
ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER
|
zrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
||||||
]
|
contactsManager:[OWSContactsManager new]
|
||||||
andZrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
contactsUpdater:[ContactsUpdater sharedUpdater]
|
||||||
andZrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
networkManager:[TSNetworkManager sharedManager]];
|
||||||
andContactsManager:[OWSContactsManager new]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Environment *)stagingEnvironmentWithLogging:(id<Logging>)logging {
|
+ (Environment *)stagingEnvironmentWithLogging:(id<Logging>)logging {
|
||||||
|
@ -66,23 +67,22 @@ static unsigned char DH3K_PRIME[] = {
|
||||||
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
||||||
};
|
};
|
||||||
|
|
||||||
return [Environment
|
return [[Environment alloc] initWithLogging:logging
|
||||||
environmentWithLogging:logging
|
errorNoter:errorNoter
|
||||||
andErrorNoter:errorNoter
|
serverPort:31337
|
||||||
andServerPort:31337
|
masterServerHostName:@"redphone-staging.whispersystems.org"
|
||||||
andMasterServerHostName:@"redphone-staging.whispersystems.org"
|
defaultRelayName:@"redphone-staging-relay"
|
||||||
andDefaultRelayName:@"redphone-staging-relay"
|
relayServerHostNameSuffix:@"whispersystems.org"
|
||||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
certificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
supportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
||||||
andSupportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
phoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
||||||
andPhoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
recentCallManager:[RecentCallManager new]
|
||||||
andRecentCallManager:[RecentCallManager new]
|
testingAndLegacyOptions:@[ ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER ]
|
||||||
andTestingAndLegacyOptions:@[
|
zrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
||||||
ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER
|
zrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
||||||
]
|
contactsManager:[OWSContactsManager new]
|
||||||
andZrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
contactsUpdater:[ContactsUpdater sharedUpdater]
|
||||||
andZrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
networkManager:[TSNetworkManager sharedManager]];
|
||||||
andContactsManager:[OWSContactsManager new]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (Environment *)unitTestEnvironment:(NSArray *)testingAndLegacyOptions {
|
+ (Environment *)unitTestEnvironment:(NSArray *)testingAndLegacyOptions {
|
||||||
|
@ -91,21 +91,23 @@ static unsigned char DH3K_PRIME[] = {
|
||||||
keyAgreementProtocols = @[ [Release supportedDH3KKeyAgreementProtocol] ];
|
keyAgreementProtocols = @[ [Release supportedDH3KKeyAgreementProtocol] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [Environment environmentWithLogging:[DiscardingLog discardingLog]
|
return [[Environment alloc] initWithLogging:[DiscardingLog discardingLog]
|
||||||
andErrorNoter:^(id error, id relatedInfo, bool causedTermination) {
|
errorNoter:^(id error, id relatedInfo, bool causedTermination) {
|
||||||
}
|
}
|
||||||
andServerPort:31337
|
serverPort:31337
|
||||||
andMasterServerHostName:@"master.whispersystems.org"
|
masterServerHostName:@"master.whispersystems.org"
|
||||||
andDefaultRelayName:@"relay"
|
defaultRelayName:@"relay"
|
||||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
relayServerHostNameSuffix:@"whispersystems.org"
|
||||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
certificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||||
andSupportedKeyAgreementProtocols:keyAgreementProtocols
|
supportedKeyAgreementProtocols:keyAgreementProtocols
|
||||||
andPhoneManager:nil
|
phoneManager:nil
|
||||||
andRecentCallManager:nil
|
recentCallManager:nil
|
||||||
andTestingAndLegacyOptions:testingAndLegacyOptions
|
testingAndLegacyOptions:testingAndLegacyOptions
|
||||||
andZrtpClientId:TESTING_ZRTP_CLIENT_ID
|
zrtpClientId:TESTING_ZRTP_CLIENT_ID
|
||||||
andZrtpVersionId:TESTING_ZRTP_VERSION_ID
|
zrtpVersionId:TESTING_ZRTP_VERSION_ID
|
||||||
andContactsManager:nil];
|
contactsManager:nil
|
||||||
|
contactsUpdater:[ContactsUpdater sharedUpdater]
|
||||||
|
networkManager:[TSNetworkManager sharedManager]];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)supportedKeyAgreementProtocols {
|
+ (NSArray *)supportedKeyAgreementProtocols {
|
||||||
|
|
|
@ -6,17 +6,18 @@
|
||||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#import "PushManager.h"
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "OWSContactsManager.h"
|
|
||||||
#import "InCallViewController.h"
|
#import "InCallViewController.h"
|
||||||
#import "NSData+ows_StripToken.h"
|
#import "NSData+ows_StripToken.h"
|
||||||
#import "NSDate+millisecondTimeStamp.h"
|
#import "NSDate+millisecondTimeStamp.h"
|
||||||
#import "NotificationTracker.h"
|
#import "NotificationTracker.h"
|
||||||
|
#import "OWSContactsManager.h"
|
||||||
#import "PreferencesUtil.h"
|
#import "PreferencesUtil.h"
|
||||||
#import "PushManager.h"
|
|
||||||
#import "RPServerRequestsManager.h"
|
#import "RPServerRequestsManager.h"
|
||||||
#import "TSMessagesManager+sendMessages.h"
|
#import "TSOutgoingMessage.h"
|
||||||
#import "TSSocketManager.h"
|
#import "TSSocketManager.h"
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
|
|
||||||
#define pushManagerDomain @"org.whispersystems.pushmanager"
|
#define pushManagerDomain @"org.whispersystems.pushmanager"
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
@property (nonatomic, retain) NSMutableArray *currentNotifications;
|
@property (nonatomic, retain) NSMutableArray *currentNotifications;
|
||||||
@property (nonatomic) UIBackgroundTaskIdentifier callBackgroundTask;
|
@property (nonatomic) UIBackgroundTaskIdentifier callBackgroundTask;
|
||||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||||
|
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -38,19 +40,38 @@
|
||||||
static PushManager *sharedManager = nil;
|
static PushManager *sharedManager = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
sharedManager = [self new];
|
sharedManager = [[self alloc] initDefault];
|
||||||
});
|
});
|
||||||
return sharedManager;
|
return sharedManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)initDefault
|
||||||
|
{
|
||||||
|
return [self initWithContactsManager:[Environment getCurrent].contactsManager
|
||||||
|
notificationTracker:[NotificationTracker notificationTracker]
|
||||||
|
networkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithContactsManager:(OWSContactsManager *)contactsManager
|
||||||
|
notificationTracker:(NotificationTracker *)notificationTracker
|
||||||
|
networkManager:(TSNetworkManager *)networkManager
|
||||||
|
storageManager:(TSStorageManager *)storageManager
|
||||||
|
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||||
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (!self) {
|
if (!self) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
_contactsManager = [Environment getCurrent].contactsManager;
|
_contactsManager = contactsManager;
|
||||||
_notificationTracker = [NotificationTracker notificationTracker];
|
_notificationTracker = notificationTracker;
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager
|
||||||
|
storageManager:storageManager
|
||||||
|
contactsManager:contactsManager
|
||||||
|
contactsUpdater:contactsUpdater];
|
||||||
|
|
||||||
_missingPermissionsAlertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ACTION_REQUIRED_TITLE", @"")
|
_missingPermissionsAlertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ACTION_REQUIRED_TITLE", @"")
|
||||||
message:NSLocalizedString(@"PUSH_SETTINGS_MESSAGE", @"")
|
message:NSLocalizedString(@"PUSH_SETTINGS_MESSAGE", @"")
|
||||||
delegate:nil
|
delegate:nil
|
||||||
|
@ -107,7 +128,7 @@
|
||||||
notification.category = Signal_Call_Category;
|
notification.category = Signal_Call_Category;
|
||||||
notification.soundName = @"r.caf";
|
notification.soundName = @"r.caf";
|
||||||
|
|
||||||
[[PushManager sharedManager] presentNotification:notification];
|
[self presentNotification:notification];
|
||||||
_lastCallNotification = notification;
|
_lastCallNotification = notification;
|
||||||
|
|
||||||
if (_callBackgroundTask == UIBackgroundTaskInvalid) {
|
if (_callBackgroundTask == UIBackgroundTaskInvalid) {
|
||||||
|
@ -185,19 +206,21 @@
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
inThread:thread
|
inThread:thread
|
||||||
messageBody:responseInfo[UIUserNotificationActionResponseTypedTextKey]];
|
messageBody:responseInfo[UIUserNotificationActionResponseTypedTextKey]];
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message
|
[self.messageSender sendMessage:message
|
||||||
inThread:thread
|
|
||||||
success:^{
|
success:^{
|
||||||
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
||||||
[[[[Environment getCurrent] signalsViewController] tableView] reloadData];
|
[[[[Environment getCurrent] signalsViewController] tableView] reloadData];
|
||||||
}
|
}
|
||||||
failure:^{
|
failure:^(NSError *error) {
|
||||||
UILocalNotification *failedSendNotif = [[UILocalNotification alloc] init];
|
// TODO Surface the specific error in the notification?
|
||||||
failedSendNotif.alertBody =
|
DDLogError(@"Message send failed with error: %@", error);
|
||||||
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]];
|
|
||||||
failedSendNotif.userInfo = @{Signal_Thread_UserInfo_Key : thread.uniqueId};
|
UILocalNotification *failedSendNotif = [[UILocalNotification alloc] init];
|
||||||
[[PushManager sharedManager] presentNotification:failedSendNotif];
|
failedSendNotif.alertBody =
|
||||||
completionHandler();
|
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]];
|
||||||
|
failedSendNotif.userInfo = @{ Signal_Thread_UserInfo_Key : thread.uniqueId };
|
||||||
|
[self presentNotification:failedSendNotif];
|
||||||
|
completionHandler();
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
} else if ([identifier isEqualToString:Signal_Call_Accept_Identifier]) {
|
} else if ([identifier isEqualToString:Signal_Call_Accept_Identifier]) {
|
||||||
|
|
|
@ -38,8 +38,6 @@
|
||||||
#import "TSIncomingMessage.h"
|
#import "TSIncomingMessage.h"
|
||||||
#import "TSInfoMessage.h"
|
#import "TSInfoMessage.h"
|
||||||
#import "TSInvalidIdentityKeyErrorMessage.h"
|
#import "TSInvalidIdentityKeyErrorMessage.h"
|
||||||
#import "TSMessagesManager+attachments.h"
|
|
||||||
#import "TSMessagesManager+sendMessages.h"
|
|
||||||
#import "UIFont+OWS.h"
|
#import "UIFont+OWS.h"
|
||||||
#import "UIUtil.h"
|
#import "UIUtil.h"
|
||||||
#import <AddressBookUI/AddressBookUI.h>
|
#import <AddressBookUI/AddressBookUI.h>
|
||||||
|
@ -53,11 +51,16 @@
|
||||||
#import <JSQSystemSoundPlayer.h>
|
#import <JSQSystemSoundPlayer.h>
|
||||||
#import <MobileCoreServices/UTCoreTypes.h>
|
#import <MobileCoreServices/UTCoreTypes.h>
|
||||||
#import <SignalServiceKit/MimeTypeUtil.h>
|
#import <SignalServiceKit/MimeTypeUtil.h>
|
||||||
|
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
|
||||||
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
||||||
#import <SignalServiceKit/OWSFingerprint.h>
|
#import <SignalServiceKit/OWSFingerprint.h>
|
||||||
#import <SignalServiceKit/OWSFingerprintBuilder.h>
|
#import <SignalServiceKit/OWSFingerprintBuilder.h>
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
#import <SignalServiceKit/SignalRecipient.h>
|
#import <SignalServiceKit/SignalRecipient.h>
|
||||||
#import <SignalServiceKit/TSAccountManager.h>
|
#import <SignalServiceKit/TSAccountManager.h>
|
||||||
|
#import <SignalServiceKit/TSInvalidIdentityKeySendingErrorMessage.h>
|
||||||
|
#import <SignalServiceKit/TSMessagesManager.h>
|
||||||
|
#import <SignalServiceKit/TSNetworkManager.h>
|
||||||
#import <YapDatabase/YapDatabaseView.h>
|
#import <YapDatabase/YapDatabaseView.h>
|
||||||
|
|
||||||
@import Photos;
|
@import Photos;
|
||||||
|
@ -116,7 +119,11 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
||||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||||
|
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
|
||||||
@property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob;
|
@property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob;
|
||||||
|
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
|
||||||
|
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||||
|
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||||
|
|
||||||
@property NSCache *messageAdapterCache;
|
@property NSCache *messageAdapterCache;
|
||||||
|
|
||||||
|
@ -136,9 +143,16 @@ typedef enum : NSUInteger {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
_contactsManager = [[Environment getCurrent] contactsManager];
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
|
_contactsUpdater = [Environment getCurrent].contactsUpdater;
|
||||||
_storageManager = [TSStorageManager sharedManager];
|
_storageManager = [TSStorageManager sharedManager];
|
||||||
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:_storageManager];
|
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:_storageManager];
|
||||||
|
_messagesManager = [TSMessagesManager sharedManager];
|
||||||
|
_networkManager = [TSNetworkManager sharedManager];
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:_networkManager
|
||||||
|
storageManager:_storageManager
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:_contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -150,9 +164,16 @@ typedef enum : NSUInteger {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
_contactsManager = [[Environment getCurrent] contactsManager];
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
|
_contactsUpdater = [Environment getCurrent].contactsUpdater;
|
||||||
_storageManager = [TSStorageManager sharedManager];
|
_storageManager = [TSStorageManager sharedManager];
|
||||||
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:_storageManager];
|
_disappearingMessagesJob = [[OWSDisappearingMessagesJob alloc] initWithStorageManager:_storageManager];
|
||||||
|
_messagesManager = [TSMessagesManager sharedManager];
|
||||||
|
_networkManager = [TSNetworkManager sharedManager];
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:_networkManager
|
||||||
|
storageManager:_storageManager
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:_contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -397,12 +418,12 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
- (void)updateBackButtonAsync {
|
- (void)updateBackButtonAsync {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
NSUInteger count = [[TSMessagesManager sharedManager] unreadMessagesCountExcept:self.thread];
|
NSUInteger count = [self.messagesManager unreadMessagesCountExcept:self.thread];
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (self) {
|
if (self) {
|
||||||
[self setUnreadCount:count];
|
[self setUnreadCount:count];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,13 +671,12 @@ typedef enum : NSUInteger {
|
||||||
messageBody:text];
|
messageBody:text];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message
|
[self.messageSender sendMessage:message
|
||||||
inThread:self.thread
|
|
||||||
success:^{
|
success:^{
|
||||||
DDLogInfo(@"%@ Successfully sent message.", self.tag);
|
DDLogInfo(@"%@ Successfully sent message.", self.tag);
|
||||||
}
|
}
|
||||||
failure:^{
|
failure:^(NSError *error) {
|
||||||
DDLogWarn(@"%@ Failed to deliver message.", self.tag);
|
DDLogWarn(@"%@ Failed to deliver message with error: %@", self.tag, error);
|
||||||
}];
|
}];
|
||||||
[self finishSendingMessage];
|
[self finishSendingMessage];
|
||||||
}
|
}
|
||||||
|
@ -797,7 +817,13 @@ typedef enum : NSUInteger {
|
||||||
[self fixupiOS10EmojiBugForTextView:cell.textView];
|
[self fixupiOS10EmojiBugForTextView:cell.textView];
|
||||||
// END HACK iOS10EmojiBug see: https://github.com/WhisperSystems/Signal-iOS/issues/1368
|
// END HACK iOS10EmojiBug see: https://github.com/WhisperSystems/Signal-iOS/issues/1368
|
||||||
|
|
||||||
if (!message.isMediaMessage) {
|
if (message.isMediaMessage) {
|
||||||
|
if (![message isKindOfClass:[TSMessageAdapter class]]) {
|
||||||
|
DDLogError(@"%@ Unexpected media message:%@", self.tag, message.class);
|
||||||
|
}
|
||||||
|
TSMessageAdapter *messageAdapter = (TSMessageAdapter *)message;
|
||||||
|
cell.mediaView.alpha = messageAdapter.mediaViewAlpha;
|
||||||
|
} else {
|
||||||
cell.textView.textColor = [UIColor whiteColor];
|
cell.textView.textColor = [UIColor whiteColor];
|
||||||
cell.textView.linkTextAttributes = @{
|
cell.textView.linkTextAttributes = @{
|
||||||
NSForegroundColorAttributeName : cell.textView.textColor,
|
NSForegroundColorAttributeName : cell.textView.textColor,
|
||||||
|
@ -937,9 +963,9 @@ typedef enum : NSUInteger {
|
||||||
if (indexPath.row == 0) {
|
if (indexPath.row == 0) {
|
||||||
showDate = YES;
|
showDate = YES;
|
||||||
} else {
|
} else {
|
||||||
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
|
id<OWSMessageData> currentMessage = [self messageAtIndexPath:indexPath];
|
||||||
|
|
||||||
TSMessageAdapter *previousMessage =
|
id<OWSMessageData> previousMessage =
|
||||||
[self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row - 1 inSection:indexPath.section]];
|
[self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row - 1 inSection:indexPath.section]];
|
||||||
|
|
||||||
NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date];
|
NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date];
|
||||||
|
@ -953,7 +979,7 @@ typedef enum : NSUInteger {
|
||||||
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView
|
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView
|
||||||
attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath {
|
attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
if ([self showDateAtIndexPath:indexPath]) {
|
if ([self showDateAtIndexPath:indexPath]) {
|
||||||
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
|
id<OWSMessageData> currentMessage = [self messageAtIndexPath:indexPath];
|
||||||
|
|
||||||
return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:currentMessage.date];
|
return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:currentMessage.date];
|
||||||
}
|
}
|
||||||
|
@ -963,7 +989,7 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
- (BOOL)shouldShowMessageStatusAtIndexPath:(NSIndexPath *)indexPath
|
- (BOOL)shouldShowMessageStatusAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
|
id<OWSMessageData> currentMessage = [self messageAtIndexPath:indexPath];
|
||||||
|
|
||||||
if (currentMessage.isExpiringMessage) {
|
if (currentMessage.isExpiringMessage) {
|
||||||
return YES;
|
return YES;
|
||||||
|
@ -972,13 +998,14 @@ typedef enum : NSUInteger {
|
||||||
return !![self collectionView:self.collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath];
|
return !![self collectionView:self.collectionView attributedTextForCellBottomLabelAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (TSMessageAdapter *)nextOutgoingMessage:(NSIndexPath *)indexPath {
|
- (id<OWSMessageData>)nextOutgoingMessage:(NSIndexPath *)indexPath
|
||||||
TSMessageAdapter *nextMessage =
|
{
|
||||||
|
id<OWSMessageData> nextMessage =
|
||||||
[self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section]];
|
[self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section]];
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
while (indexPath.item + i < [self.collectionView numberOfItemsInSection:indexPath.section] - 1 &&
|
while (indexPath.item + i < [self.collectionView numberOfItemsInSection:indexPath.section] - 1
|
||||||
![self isMessageOutgoingAndDelivered:nextMessage]) {
|
&& !nextMessage.isOutgoingAndDelivered) {
|
||||||
i++;
|
i++;
|
||||||
nextMessage =
|
nextMessage =
|
||||||
[self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row + i inSection:indexPath.section]];
|
[self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row + i inSection:indexPath.section]];
|
||||||
|
@ -987,18 +1014,6 @@ typedef enum : NSUInteger {
|
||||||
return nextMessage;
|
return nextMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isMessageOutgoingAndDelivered:(TSMessageAdapter *)message
|
|
||||||
{
|
|
||||||
if (message.messageType == TSOutgoingMessageAdapter) {
|
|
||||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message;
|
|
||||||
if(outgoingMessage.messageState == TSOutgoingMessageStateDelivered) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView
|
- (NSAttributedString *)collectionView:(JSQMessagesCollectionView *)collectionView
|
||||||
attributedTextForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath
|
attributedTextForCellBottomLabelAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
|
@ -1011,11 +1026,8 @@ typedef enum : NSUInteger {
|
||||||
if (message.messageType == TSOutgoingMessageAdapter) {
|
if (message.messageType == TSOutgoingMessageAdapter) {
|
||||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message.interaction;
|
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message.interaction;
|
||||||
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
|
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
|
||||||
NSAttributedString *failedString =
|
return [[NSAttributedString alloc] initWithString:NSLocalizedString(@"FAILED_SENDING_TEXT", nil)];
|
||||||
[[NSAttributedString alloc] initWithString:NSLocalizedString(@"FAILED_SENDING_TEXT", nil)];
|
} else if (message.isOutgoingAndDelivered) {
|
||||||
|
|
||||||
return failedString;
|
|
||||||
} else if ([self isMessageOutgoingAndDelivered:message]) {
|
|
||||||
NSAttributedString *deliveredString =
|
NSAttributedString *deliveredString =
|
||||||
[[NSAttributedString alloc] initWithString:NSLocalizedString(@"DELIVERED_MESSAGE_TEXT", @"")];
|
[[NSAttributedString alloc] initWithString:NSLocalizedString(@"DELIVERED_MESSAGE_TEXT", @"")];
|
||||||
|
|
||||||
|
@ -1027,10 +1039,13 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
// Or when the next message is *not* an outgoing delivered message.
|
// Or when the next message is *not* an outgoing delivered message.
|
||||||
TSMessageAdapter *nextMessage = [self nextOutgoingMessage:indexPath];
|
TSMessageAdapter *nextMessage = [self nextOutgoingMessage:indexPath];
|
||||||
if (![self isMessageOutgoingAndDelivered:nextMessage]) {
|
if (!nextMessage.isOutgoingAndDelivered) {
|
||||||
[self updateLastDeliveredMessage:message];
|
[self updateLastDeliveredMessage:message];
|
||||||
return deliveredString;
|
return deliveredString;
|
||||||
}
|
}
|
||||||
|
} else if (message.isMediaBeingSent) {
|
||||||
|
return [[NSAttributedString alloc] initWithString:NSLocalizedString(@"UPLOADING_MESSAGE_TEXT",
|
||||||
|
@"message footer while attachment is uploading")];
|
||||||
}
|
}
|
||||||
} else if (message.messageType == TSIncomingMessageAdapter && [self.thread isKindOfClass:[TSGroupThread class]]) {
|
} else if (message.messageType == TSIncomingMessageAdapter && [self.thread isKindOfClass:[TSGroupThread class]]) {
|
||||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message.interaction;
|
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message.interaction;
|
||||||
|
@ -1101,12 +1116,17 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
switch (messageItem.messageType) {
|
switch (messageItem.messageType) {
|
||||||
case TSOutgoingMessageAdapter: {
|
case TSOutgoingMessageAdapter: {
|
||||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)messageItem;
|
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)interaction;
|
||||||
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
|
if (outgoingMessage.messageState == TSOutgoingMessageStateUnsent) {
|
||||||
[self handleUnsentMessageTap:(TSOutgoingMessage *)interaction];
|
[self handleUnsentMessageTap:outgoingMessage];
|
||||||
|
|
||||||
|
// This `break` is intentionally within the if.
|
||||||
|
// We want to activate fullscreen media view for sent items
|
||||||
|
// but not those which failed-to-send
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
// No `break` as we want to fall through to capture tapping on Outgoing media items too
|
||||||
}
|
}
|
||||||
// No `break` as we want to fall through to capture tapping on media items
|
|
||||||
case TSIncomingMessageAdapter: {
|
case TSIncomingMessageAdapter: {
|
||||||
BOOL isMediaMessage = [messageItem isMediaMessage];
|
BOOL isMediaMessage = [messageItem isMediaMessage];
|
||||||
|
|
||||||
|
@ -1306,7 +1326,17 @@ typedef enum : NSUInteger {
|
||||||
// FIXME possible for pointer to get stuck in isDownloading state if app is closed while downloading.
|
// FIXME possible for pointer to get stuck in isDownloading state if app is closed while downloading.
|
||||||
// see: https://github.com/WhisperSystems/Signal-iOS/issues/1254
|
// see: https://github.com/WhisperSystems/Signal-iOS/issues/1254
|
||||||
if (!pointer.isDownloading) {
|
if (!pointer.isDownloading) {
|
||||||
[[TSMessagesManager sharedManager] retrieveAttachment:pointer messageId:message.uniqueId];
|
OWSAttachmentsProcessor *processor =
|
||||||
|
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:pointer
|
||||||
|
networkManager:self.networkManager];
|
||||||
|
[processor fetchAttachmentsForMessage:message
|
||||||
|
success:^(TSAttachmentStream *_Nonnull attachmentStream) {
|
||||||
|
DDLogInfo(
|
||||||
|
@"%@ Successfully redownloaded attachment in thread: %@", self.tag, message.thread);
|
||||||
|
}
|
||||||
|
failure:^(NSError *_Nonnull error) {
|
||||||
|
DDLogWarn(@"%@ Failed to redownload message with error: %@", self.tag, error);
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1401,25 +1431,25 @@ typedef enum : NSUInteger {
|
||||||
- (void)handleUnsentMessageTap:(TSOutgoingMessage *)message {
|
- (void)handleUnsentMessageTap:(TSOutgoingMessage *)message {
|
||||||
[self dismissKeyBoard];
|
[self dismissKeyBoard];
|
||||||
[DJWActionSheet showInView:self.parentViewController.view
|
[DJWActionSheet showInView:self.parentViewController.view
|
||||||
withTitle:nil
|
withTitle:message.mostRecentFailureText
|
||||||
cancelButtonTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
cancelButtonTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
||||||
destructiveButtonTitle:NSLocalizedString(@"TXT_DELETE_TITLE", @"")
|
destructiveButtonTitle:NSLocalizedString(@"TXT_DELETE_TITLE", @"")
|
||||||
otherButtonTitles:@[ NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") ]
|
otherButtonTitles:@[ NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") ]
|
||||||
tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
|
tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
|
||||||
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
|
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
|
||||||
DDLogDebug(@"User Cancelled");
|
DDLogDebug(@"%@ User cancelled unsent dialog", self.tag);
|
||||||
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
|
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
|
||||||
[self.editingDatabaseConnection
|
DDLogInfo(@"%@ User chose to delete unsent message.", self.tag);
|
||||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
[message remove];
|
||||||
[message removeWithTransaction:transaction];
|
} else {
|
||||||
}];
|
[self.messageSender sendMessage:message
|
||||||
} else {
|
success:^{
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message
|
DDLogInfo(@"%@ Successfully resent failed message.", self.tag);
|
||||||
inThread:self.thread
|
}
|
||||||
success:nil
|
failure:^(NSError *_Nonnull error) {
|
||||||
failure:nil];
|
DDLogWarn(@"%@ Failed to send message with error: %@", self.tag, error);
|
||||||
[self finishSendingMessage];
|
}];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,7 +1489,21 @@ typedef enum : NSUInteger {
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
DDLogInfo(@"%@ Remote Key Changed actions: Accepted new identity key", self.tag);
|
DDLogInfo(@"%@ Remote Key Changed actions: Accepted new identity key", self.tag);
|
||||||
|
|
||||||
[errorMessage acceptNewIdentityKey];
|
[errorMessage acceptNewIdentityKey];
|
||||||
|
if ([errorMessage isKindOfClass:[TSInvalidIdentityKeySendingErrorMessage class]]) {
|
||||||
|
[self.messageSender
|
||||||
|
resendMessageFromKeyError:(TSInvalidIdentityKeySendingErrorMessage *)
|
||||||
|
errorMessage
|
||||||
|
success:^{
|
||||||
|
DDLogDebug(@"%@ Successfully resent key-error message.", self.tag);
|
||||||
|
}
|
||||||
|
failure:^(NSError *_Nonnull error) {
|
||||||
|
DDLogError(@"%@ Failed to resend key-error message with error:%@",
|
||||||
|
self.tag,
|
||||||
|
error);
|
||||||
|
}];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DDLogInfo(@"%@ Remote Key Changed actions: Unhandled button pressed: %d",
|
DDLogInfo(@"%@ Remote Key Changed actions: Unhandled button pressed: %d",
|
||||||
|
@ -1564,7 +1608,7 @@ typedef enum : NSUInteger {
|
||||||
// Video picked from library or captured with camera
|
// Video picked from library or captured with camera
|
||||||
|
|
||||||
NSURL *videoURL = info[UIImagePickerControllerMediaURL];
|
NSURL *videoURL = info[UIImagePickerControllerMediaURL];
|
||||||
[self sendQualityAdjustedAttachment:videoURL];
|
[self sendQualityAdjustedAttachmentForVideo:videoURL];
|
||||||
} else if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
} else if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
||||||
// Static Image captured from camera
|
// Static Image captured from camera
|
||||||
|
|
||||||
|
@ -1649,13 +1693,16 @@ typedef enum : NSUInteger {
|
||||||
DDLogVerbose(@"Sending attachment. Size in bytes: %lu, contentType: %@",
|
DDLogVerbose(@"Sending attachment. Size in bytes: %lu, contentType: %@",
|
||||||
(unsigned long)attachmentData.length,
|
(unsigned long)attachmentData.length,
|
||||||
attachmentType);
|
attachmentType);
|
||||||
|
[self.messageSender sendAttachmentData:attachmentData
|
||||||
[[TSMessagesManager sharedManager] sendAttachment:attachmentData
|
contentType:attachmentType
|
||||||
contentType:attachmentType
|
inMessage:message
|
||||||
inMessage:message
|
success:^{
|
||||||
thread:self.thread
|
DDLogDebug(@"%@ Successfully sent message attachment.", self.tag);
|
||||||
success:nil
|
}
|
||||||
failure:nil];
|
failure:^(NSError *error) {
|
||||||
|
DDLogError(
|
||||||
|
@"%@ Failed to send message attachment with error: %@", self.tag, error);
|
||||||
|
}];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1672,7 +1719,7 @@ typedef enum : NSUInteger {
|
||||||
return [NSURL fileURLWithPath:basePath];
|
return [NSURL fileURLWithPath:basePath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendQualityAdjustedAttachment:(NSURL *)movieURL {
|
- (void)sendQualityAdjustedAttachmentForVideo:(NSURL *)movieURL {
|
||||||
AVAsset *video = [AVAsset assetWithURL:movieURL];
|
AVAsset *video = [AVAsset assetWithURL:movieURL];
|
||||||
AVAssetExportSession *exportSession =
|
AVAssetExportSession *exportSession =
|
||||||
[AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
|
[AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
|
||||||
|
@ -1841,7 +1888,6 @@ typedef enum : NSUInteger {
|
||||||
[self.messageAdapterCache removeObjectForKey:collectionKey.key];
|
[self.messageAdapterCache removeObjectForKey:collectionKey.key];
|
||||||
}
|
}
|
||||||
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
|
||||||
scrollToBottom = YES;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1854,7 +1900,9 @@ typedef enum : NSUInteger {
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
}
|
}
|
||||||
if (scrollToBottom) {
|
if (scrollToBottom) {
|
||||||
[self scrollToBottomAnimated:YES];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self scrollToBottomAnimated:YES];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -1997,24 +2045,19 @@ typedef enum : NSUInteger {
|
||||||
- (BOOL)collectionView:(UICollectionView *)collectionView
|
- (BOOL)collectionView:(UICollectionView *)collectionView
|
||||||
canPerformAction:(SEL)action
|
canPerformAction:(SEL)action
|
||||||
forItemAtIndexPath:(NSIndexPath *)indexPath
|
forItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
withSender:(id)sender {
|
withSender:(id)sender
|
||||||
TSMessageAdapter *messageAdapter = [self messageAtIndexPath:indexPath];
|
{
|
||||||
// HACK make sure method exists before calling since messageAtIndexPath doesn't
|
id<OWSMessageData> messageData = [self messageAtIndexPath:indexPath];
|
||||||
// always return TSMessageAdapters - it can also return JSQCall!
|
return [messageData canPerformEditingAction:action];
|
||||||
if ([messageAdapter respondsToSelector:@selector(canPerformEditingAction:)]) {
|
|
||||||
return [messageAdapter canPerformEditingAction:action];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)collectionView:(UICollectionView *)collectionView
|
- (void)collectionView:(UICollectionView *)collectionView
|
||||||
performAction:(SEL)action
|
performAction:(SEL)action
|
||||||
forItemAtIndexPath:(NSIndexPath *)indexPath
|
forItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
withSender:(id)sender {
|
withSender:(id)sender
|
||||||
[[self messageAtIndexPath:indexPath] performEditingAction:action];
|
{
|
||||||
|
id<OWSMessageData> messageData = [self messageAtIndexPath:indexPath];
|
||||||
|
[messageData performEditingAction:action];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateGroupModelTo:(TSGroupModel *)newGroupModel
|
- (void)updateGroupModelTo:(TSGroupModel *)newGroupModel
|
||||||
|
@ -2037,15 +2080,24 @@ typedef enum : NSUInteger {
|
||||||
message.customMessage = updateGroupInfo;
|
message.customMessage = updateGroupInfo;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (newGroupModel.groupImage != nil) {
|
if (newGroupModel.groupImage) {
|
||||||
[[TSMessagesManager sharedManager] sendAttachment:UIImagePNGRepresentation(newGroupModel.groupImage)
|
[self.messageSender sendAttachmentData:UIImagePNGRepresentation(newGroupModel.groupImage)
|
||||||
contentType:OWSMimeTypeImagePng
|
contentType:OWSMimeTypeImagePng
|
||||||
inMessage:message
|
inMessage:message
|
||||||
thread:groupThread
|
success:^{
|
||||||
success:nil
|
DDLogDebug(@"%@ Successfully sent group update with avatar", self.tag);
|
||||||
failure:nil];
|
}
|
||||||
|
failure:^(NSError *_Nonnull error) {
|
||||||
|
DDLogError(@"%@ Failed to send group avatar update with error: %@", self.tag, error);
|
||||||
|
}];
|
||||||
} else {
|
} else {
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message inThread:groupThread success:nil failure:nil];
|
[self.messageSender sendMessage:message
|
||||||
|
success:^{
|
||||||
|
DDLogDebug(@"%@ Successfully sent group update", self.tag);
|
||||||
|
}
|
||||||
|
failure:^(NSError *_Nonnull error) {
|
||||||
|
DDLogError(@"%@ Failed to send group update with error: %@", self.tag, error);
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.thread = groupThread;
|
self.thread = groupThread;
|
||||||
|
|
|
@ -20,20 +20,50 @@
|
||||||
#import <MobileCoreServices/UTCoreTypes.h>
|
#import <MobileCoreServices/UTCoreTypes.h>
|
||||||
#import <SignalServiceKit/MimeTypeUtil.h>
|
#import <SignalServiceKit/MimeTypeUtil.h>
|
||||||
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
|
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
#import <SignalServiceKit/TSAccountManager.h>
|
#import <SignalServiceKit/TSAccountManager.h>
|
||||||
#import <SignalServiceKit/TSMessagesManager+attachments.h>
|
|
||||||
#import <SignalServiceKit/TSMessagesManager+sendMessages.h>
|
|
||||||
|
|
||||||
static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue";
|
static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue";
|
||||||
|
|
||||||
@interface NewGroupViewController () {
|
@interface NewGroupViewController () {
|
||||||
NSArray *contacts;
|
NSArray *contacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property TSGroupThread *thread;
|
@property TSGroupThread *thread;
|
||||||
|
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation NewGroupViewController
|
@implementation NewGroupViewController
|
||||||
|
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsManager:[Environment getCurrent].contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aDecoder];
|
||||||
|
if (!self) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsManager:[Environment getCurrent].contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)configWithThread:(TSGroupThread *)gThread {
|
- (void)configWithThread:(TSGroupThread *)gThread {
|
||||||
_thread = gThread;
|
_thread = gThread;
|
||||||
}
|
}
|
||||||
|
@ -124,76 +154,53 @@ static NSString *const kUnwindToMessagesViewSegue = @"UnwindToMessagesViewSegue"
|
||||||
self.thread = [TSGroupThread getOrCreateThreadWithGroupModel:model transaction:transaction];
|
self.thread = [TSGroupThread getOrCreateThreadWithGroupModel:model transaction:transaction];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
void (^popToThread)() = ^{
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self dismissViewControllerAnimated:YES
|
||||||
|
completion:^{
|
||||||
|
[Environment messageGroup:self.thread];
|
||||||
|
}];
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
void (^removeThreadWithError)(NSError *error) = ^(NSError *error) {
|
||||||
|
[self.thread remove];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self dismissViewControllerAnimated:YES
|
||||||
|
completion:^{
|
||||||
|
SignalAlertView(NSLocalizedString(@"GROUP_CREATING_FAILED", nil),
|
||||||
|
error.localizedDescription);
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
UIAlertController *alertController =
|
UIAlertController *alertController =
|
||||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"GROUP_CREATING", nil)
|
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"GROUP_CREATING", nil)
|
||||||
message:nil
|
message:nil
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[self
|
|
||||||
presentViewController:alertController
|
|
||||||
animated:YES
|
|
||||||
completion:^{
|
|
||||||
TSOutgoingMessage *message =
|
|
||||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
|
||||||
inThread:self.thread
|
|
||||||
messageBody:@""
|
|
||||||
attachmentIds:[NSMutableArray new]];
|
|
||||||
message.groupMetaMessage = TSGroupMessageNew;
|
|
||||||
message.customMessage = NSLocalizedString(@"GROUP_CREATED", nil);
|
|
||||||
if (model.groupImage != nil) {
|
|
||||||
[[TSMessagesManager sharedManager] sendAttachment:UIImagePNGRepresentation(model.groupImage)
|
|
||||||
contentType:OWSMimeTypeImagePng
|
|
||||||
inMessage:message
|
|
||||||
thread:self.thread
|
|
||||||
success:^{
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self dismissViewControllerAnimated:YES
|
|
||||||
completion:^{
|
|
||||||
[Environment messageGroup:self.thread];
|
|
||||||
}];
|
|
||||||
|
|
||||||
});
|
[self presentViewController:alertController
|
||||||
}
|
animated:YES
|
||||||
failure:^{
|
completion:^{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
TSOutgoingMessage *message =
|
||||||
[self
|
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||||
dismissViewControllerAnimated:YES
|
inThread:self.thread
|
||||||
completion:^{
|
messageBody:@""
|
||||||
[TSStorageManager.sharedManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction){
|
attachmentIds:[NSMutableArray new]];
|
||||||
[self.thread removeWithTransaction:transaction];
|
|
||||||
}];
|
|
||||||
|
|
||||||
SignalAlertView(NSLocalizedString(@"GROUP_CREATING_FAILED", nil),
|
message.groupMetaMessage = TSGroupMessageNew;
|
||||||
NSLocalizedString(@"NETWORK_ERROR_RECOVERY", nil));
|
message.customMessage = NSLocalizedString(@"GROUP_CREATED", nil);
|
||||||
}];
|
if (model.groupImage) {
|
||||||
});
|
[self.messageSender sendAttachmentData:UIImagePNGRepresentation(model.groupImage)
|
||||||
}];
|
contentType:OWSMimeTypeImagePng
|
||||||
} else {
|
inMessage:message
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message
|
success:popToThread
|
||||||
inThread:self.thread
|
failure:removeThreadWithError];
|
||||||
success:^{
|
} else {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
[self.messageSender sendMessage:message success:popToThread failure:removeThreadWithError];
|
||||||
[self dismissViewControllerAnimated:YES
|
}
|
||||||
completion:^{
|
}];
|
||||||
[Environment messageGroup:self.thread];
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
failure:^{
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self
|
|
||||||
dismissViewControllerAnimated:YES
|
|
||||||
completion:^{
|
|
||||||
[TSStorageManager.sharedManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction){
|
|
||||||
[self.thread removeWithTransaction:transaction];
|
|
||||||
}];
|
|
||||||
SignalAlertView(NSLocalizedString(@"GROUP_CREATING_FAILED", nil),
|
|
||||||
NSLocalizedString(@"NETWORK_ERROR_RECOVERY", nil));
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,18 @@
|
||||||
#import "OWSContactsManager.h"
|
#import "OWSContactsManager.h"
|
||||||
#import "PhoneNumber.h"
|
#import "PhoneNumber.h"
|
||||||
#import "ShowGroupMembersViewController.h"
|
#import "ShowGroupMembersViewController.h"
|
||||||
#import "UIUtil.h"
|
|
||||||
#import "UIFont+OWS.h"
|
#import "UIFont+OWS.h"
|
||||||
|
#import "UIUtil.h"
|
||||||
#import <25519/Curve25519.h>
|
#import <25519/Curve25519.h>
|
||||||
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
|
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
|
||||||
#import <SignalServiceKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
|
#import <SignalServiceKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
|
||||||
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
||||||
#import <SignalServiceKit/OWSFingerprint.h>
|
#import <SignalServiceKit/OWSFingerprint.h>
|
||||||
#import <SignalServiceKit/OWSFingerprintBuilder.h>
|
#import <SignalServiceKit/OWSFingerprintBuilder.h>
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
#import <SignalServiceKit/OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob.h>
|
#import <SignalServiceKit/OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob.h>
|
||||||
#import <SignalServiceKit/TSGroupThread.h>
|
#import <SignalServiceKit/TSGroupThread.h>
|
||||||
#import <SignalServiceKit/TSMessagesManager+sendMessages.h>
|
#import <SignalServiceKit/TSOutgoingMessage.h>
|
||||||
#import <SignalServiceKit/TSStorageManager.h>
|
#import <SignalServiceKit/TSStorageManager.h>
|
||||||
#import <SignalServiceKit/TSThread.h>
|
#import <SignalServiceKit/TSThread.h>
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupM
|
||||||
|
|
||||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
||||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||||
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
|
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -90,8 +91,11 @@ static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupM
|
||||||
}
|
}
|
||||||
|
|
||||||
_storageManager = [TSStorageManager sharedManager];
|
_storageManager = [TSStorageManager sharedManager];
|
||||||
_contactsManager = [[Environment getCurrent] contactsManager];
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
_messagesManager = [TSMessagesManager sharedManager];
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:_storageManager
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +108,11 @@ static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupM
|
||||||
}
|
}
|
||||||
|
|
||||||
_storageManager = [TSStorageManager sharedManager];
|
_storageManager = [TSStorageManager sharedManager];
|
||||||
_contactsManager = [[Environment getCurrent] contactsManager];
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
_messagesManager = [TSMessagesManager sharedManager];
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:_storageManager
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +214,7 @@ static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupM
|
||||||
[OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob
|
[OWSNotifyRemoteOfUpdatedDisappearingConfigurationJob
|
||||||
runWithConfiguration:self.disappearingMessagesConfiguration
|
runWithConfiguration:self.disappearingMessagesConfiguration
|
||||||
thread:self.thread
|
thread:self.thread
|
||||||
messagesManager:self.messagesManager];
|
messageSender:self.messageSender];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,13 +359,12 @@ static NSString *const OWSConversationSettingsTableViewControllerSegueShowGroupM
|
||||||
inThread:gThread
|
inThread:gThread
|
||||||
messageBody:@""];
|
messageBody:@""];
|
||||||
message.groupMetaMessage = TSGroupMessageQuit;
|
message.groupMetaMessage = TSGroupMessageQuit;
|
||||||
[self.messagesManager sendMessage:message
|
[self.messageSender sendMessage:message
|
||||||
inThread:gThread
|
|
||||||
success:^{
|
success:^{
|
||||||
DDLogInfo(@"%@ Successfully left group.", self.tag);
|
DDLogInfo(@"%@ Successfully left group.", self.tag);
|
||||||
}
|
}
|
||||||
failure:^{
|
failure:^(NSError *error) {
|
||||||
DDLogWarn(@"%@ Failed to leave group", self.tag);
|
DDLogWarn(@"%@ Failed to leave group with error: %@", self.tag, error);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
NSMutableArray *newGroupMemberIds = [NSMutableArray arrayWithArray:gThread.groupModel.groupMemberIds];
|
NSMutableArray *newGroupMemberIds = [NSMutableArray arrayWithArray:gThread.groupModel.groupMemberIds];
|
||||||
|
|
|
@ -18,12 +18,13 @@
|
||||||
#import "TSAccountManager.h"
|
#import "TSAccountManager.h"
|
||||||
#import "TSDatabaseView.h"
|
#import "TSDatabaseView.h"
|
||||||
#import "TSGroupThread.h"
|
#import "TSGroupThread.h"
|
||||||
#import "TSMessagesManager+sendMessages.h"
|
|
||||||
#import "TSStorageManager.h"
|
#import "TSStorageManager.h"
|
||||||
#import "VersionMigrations.h"
|
#import "VersionMigrations.h"
|
||||||
|
#import <SignalServiceKit/OWSMessageSender.h>
|
||||||
|
#import <SignalServiceKit/TSMessagesManager.h>
|
||||||
|
#import <SignalServiceKit/TSOutgoingMessage.h>
|
||||||
#import <YapDatabase/YapDatabaseViewChange.h>
|
#import <YapDatabase/YapDatabaseViewChange.h>
|
||||||
#import "YapDatabaseViewConnection.h"
|
#import <YapDatabase/YapDatabaseViewConnection.h>
|
||||||
|
|
||||||
#define CELL_HEIGHT 72.0f
|
#define CELL_HEIGHT 72.0f
|
||||||
#define HEADER_HEIGHT 44.0f
|
#define HEADER_HEIGHT 44.0f
|
||||||
|
@ -40,6 +41,8 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
|
||||||
@property (nonatomic, retain) UISegmentedControl *segmentedControl;
|
@property (nonatomic, retain) UISegmentedControl *segmentedControl;
|
||||||
@property (nonatomic, strong) id previewingContext;
|
@property (nonatomic, strong) id previewingContext;
|
||||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||||
|
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
|
||||||
|
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -53,6 +56,11 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
|
||||||
}
|
}
|
||||||
|
|
||||||
_contactsManager = [Environment getCurrent].contactsManager;
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
|
_messagesManager = [TSMessagesManager sharedManager];
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +73,11 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
|
||||||
}
|
}
|
||||||
|
|
||||||
_contactsManager = [Environment getCurrent].contactsManager;
|
_contactsManager = [Environment getCurrent].contactsManager;
|
||||||
|
_messagesManager = [TSMessagesManager sharedManager];
|
||||||
|
_messageSender = [[OWSMessageSender alloc] initWithNetworkManager:[Environment getCurrent].networkManager
|
||||||
|
storageManager:[TSStorageManager sharedManager]
|
||||||
|
contactsManager:_contactsManager
|
||||||
|
contactsUpdater:[Environment getCurrent].contactsUpdater];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -284,20 +297,19 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
|
||||||
messageBody:@""
|
messageBody:@""
|
||||||
attachmentIds:[NSMutableArray new]];
|
attachmentIds:[NSMutableArray new]];
|
||||||
message.groupMetaMessage = TSGroupMessageQuit;
|
message.groupMetaMessage = TSGroupMessageQuit;
|
||||||
[[TSMessagesManager sharedManager] sendMessage:message
|
[self.messageSender sendMessage:message
|
||||||
inThread:thread
|
|
||||||
success:^{
|
success:^{
|
||||||
[self dismissViewControllerAnimated:YES
|
[self dismissViewControllerAnimated:YES
|
||||||
completion:^{
|
completion:^{
|
||||||
[self deleteThread:thread];
|
[self deleteThread:thread];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
failure:^{
|
failure:^(NSError *error) {
|
||||||
[self dismissViewControllerAnimated:YES
|
[self dismissViewControllerAnimated:YES
|
||||||
completion:^{
|
completion:^{
|
||||||
SignalAlertView(NSLocalizedString(@"GROUP_REMOVING_FAILED", nil),
|
SignalAlertView(NSLocalizedString(@"GROUP_REMOVING_FAILED", nil),
|
||||||
NSLocalizedString(@"NETWORK_ERROR_RECOVERY", nil));
|
error.localizedRecoverySuggestion);
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
[self deleteThread:thread];
|
[self deleteThread:thread];
|
||||||
|
@ -326,7 +338,7 @@ static NSString *const kShowSignupFlowSegue = @"showSignupFlow";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSNumber *)updateInboxCountLabel {
|
- (NSNumber *)updateInboxCountLabel {
|
||||||
NSUInteger numberOfItems = [[TSMessagesManager sharedManager] unreadMessagesCount];
|
NSUInteger numberOfItems = [self.messagesManager unreadMessagesCount];
|
||||||
NSNumber *badgeNumber = [NSNumber numberWithUnsignedInteger:numberOfItems];
|
NSNumber *badgeNumber = [NSNumber numberWithUnsignedInteger:numberOfItems];
|
||||||
NSString *unreadString = NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil);
|
NSString *unreadString = NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
- (void)prepareForReuse
|
- (void)prepareForReuse
|
||||||
{
|
{
|
||||||
[super prepareForReuse];
|
[super prepareForReuse];
|
||||||
|
self.mediaView.alpha = 1.0;
|
||||||
self.expirationTimerViewWidthConstraint.constant = 0.0f;
|
self.expirationTimerViewWidthConstraint.constant = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
|
|
||||||
#import "TSAttachmentStream.h"
|
#import "TSAttachmentStream.h"
|
||||||
#import "TSContentAdapters.h"
|
#import "TSContentAdapters.h"
|
||||||
#import "TSInteraction.h"
|
#import "TSOutgoingMessage.h"
|
||||||
#import <MobileCoreServices/MobileCoreServices.h>
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
#import <XCTest/XCTest.h>
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
|
||||||
|
|
||||||
@interface TSMessageAdapter (Testing)
|
@interface TSMessageAdapter (Testing)
|
||||||
|
|
||||||
// expose some private setters for ease of testing setup
|
// expose some private setters for ease of testing setup
|
||||||
|
@ -19,7 +17,7 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
@interface TSMessageAdapterTest : XCTestCase
|
@interface TSMessageAdapterTest : XCTestCase
|
||||||
|
|
||||||
@property TSMessageAdapter *messageAdapter;
|
@property TSMessageAdapter *messageAdapter;
|
||||||
@property TSInteraction *interaction;
|
@property TSOutgoingMessage *message;
|
||||||
@property (readonly) NSData *fakeAudioData;
|
@property (readonly) NSData *fakeAudioData;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -42,11 +40,11 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
{
|
{
|
||||||
[super setUp];
|
[super setUp];
|
||||||
|
|
||||||
self.messageAdapter = [[TSMessageAdapter alloc] init];
|
self.message = [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:nil];
|
||||||
|
[self.message save];
|
||||||
|
|
||||||
self.interaction = [[TSInteraction alloc] initWithUniqueId:kTestingInteractionId];
|
self.messageAdapter = [TSMessageAdapter new];
|
||||||
[self.interaction save];
|
self.messageAdapter.interaction = self.message;
|
||||||
self.messageAdapter.interaction = self.interaction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tearDown
|
- (void)tearDown
|
||||||
|
@ -94,7 +92,7 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
|
|
||||||
- (void)testCanPerformEditingActionWithVideoMessage
|
- (void)testCanPerformEditingActionWithVideoMessage
|
||||||
{
|
{
|
||||||
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-video-message" encryptionKey:nil contentType:@"video/mp4"];
|
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4"];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO];
|
||||||
|
|
||||||
XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]);
|
XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]);
|
||||||
|
@ -107,7 +105,7 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
|
|
||||||
- (void)testCanPerformEditingActionWithAudioMessage
|
- (void)testCanPerformEditingActionWithAudioMessage
|
||||||
{
|
{
|
||||||
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-audio-message" encryptionKey:nil contentType:@"audio/mp3"];
|
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
||||||
|
|
||||||
XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]);
|
XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]);
|
||||||
|
@ -124,53 +122,73 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
|
|
||||||
- (void)testPerformDeleteEditingActionWithNonMediaMessage
|
- (void)testPerformDeleteEditingActionWithNonMediaMessage
|
||||||
{
|
{
|
||||||
XCTAssertNotNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
[self.messageAdapter performEditingAction:@selector(delete:)];
|
[self.messageAdapter performEditingAction:@selector(delete:)];
|
||||||
XCTAssertNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testPerformDeleteActionWithPhotoMessage
|
- (void)testPerformDeleteActionWithPhotoMessage
|
||||||
{
|
{
|
||||||
XCTAssertNotNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
|
|
||||||
self.messageAdapter.mediaItem = [[TSPhotoAdapter alloc] init];
|
self.messageAdapter.mediaItem = [[TSPhotoAdapter alloc] init];
|
||||||
[self.messageAdapter performEditingAction:@selector(delete:)];
|
[self.messageAdapter performEditingAction:@selector(delete:)];
|
||||||
XCTAssertNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
// TODO assert files are deleted
|
// TODO assert files are deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testPerformDeleteEditingActionWithAnimatedMessage
|
- (void)testPerformDeleteEditingActionWithAnimatedMessage
|
||||||
{
|
{
|
||||||
XCTAssertNotNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
|
|
||||||
self.messageAdapter.mediaItem = [[TSAnimatedAdapter alloc] init];
|
self.messageAdapter.mediaItem = [[TSAnimatedAdapter alloc] init];
|
||||||
[self.messageAdapter performEditingAction:@selector(delete:)];
|
[self.messageAdapter performEditingAction:@selector(delete:)];
|
||||||
XCTAssertNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
// TODO assert files are deleted
|
// TODO assert files are deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testPerformDeleteEditingActionWithVideoMessage
|
- (void)testPerformDeleteEditingActionWithVideoMessage
|
||||||
{
|
{
|
||||||
XCTAssertNotNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4"];
|
||||||
|
[videoAttachment writeData:[NSData new] error:&error];
|
||||||
|
[videoAttachment save];
|
||||||
|
|
||||||
|
[self.message.attachmentIds addObject:videoAttachment.uniqueId];
|
||||||
|
[self.message save];
|
||||||
|
|
||||||
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-video-message" encryptionKey:nil contentType:@"video/mp4"];
|
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO];
|
||||||
|
|
||||||
|
// Sanity Check
|
||||||
|
XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:videoAttachment.filePath]);
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(delete:)];
|
[self.messageAdapter performEditingAction:@selector(delete:)];
|
||||||
XCTAssertNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
// TODO assert files are deleted
|
XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:videoAttachment.filePath]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testPerformDeleteEditingActionWithAudioMessage
|
- (void)testPerformDeleteEditingActionWithAudioMessage
|
||||||
{
|
{
|
||||||
XCTAssertNotNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"];
|
||||||
|
[audioAttachment writeData:[NSData new] error:&error];
|
||||||
|
[audioAttachment save];
|
||||||
|
|
||||||
|
[self.message.attachmentIds addObject:audioAttachment.uniqueId];
|
||||||
|
[self.message save];
|
||||||
|
|
||||||
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-audio-message" encryptionKey:nil contentType:@"audio/mp3"];
|
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
||||||
|
|
||||||
|
// Sanity Check
|
||||||
|
XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:audioAttachment.filePath]);
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(delete:)];
|
[self.messageAdapter performEditingAction:@selector(delete:)];
|
||||||
XCTAssertNil([TSInteraction fetchObjectWithUniqueID:kTestingInteractionId]);
|
XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]);
|
||||||
// TODO assert files are deleted
|
XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:audioAttachment.filePath]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test Copy
|
// Test Copy
|
||||||
|
@ -201,7 +219,10 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
{
|
{
|
||||||
// reset the paste board for clean slate test
|
// reset the paste board for clean slate test
|
||||||
UIPasteboard.generalPasteboard.items = @[];
|
UIPasteboard.generalPasteboard.items = @[];
|
||||||
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-video" data:self.fakeVideoData key:nil contentType:@"video/mp4"];
|
|
||||||
|
NSError *error;
|
||||||
|
TSAttachmentStream *videoAttachment = [[TSAttachmentStream alloc] initWithContentType:@"video/mp4"];
|
||||||
|
[videoAttachment writeData:self.fakeVideoData error:&error];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:YES];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:YES];
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(copy:)];
|
[self.messageAdapter performEditingAction:@selector(copy:)];
|
||||||
|
@ -215,7 +236,9 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
UIPasteboard.generalPasteboard.items = @[];
|
UIPasteboard.generalPasteboard.items = @[];
|
||||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]);
|
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]);
|
||||||
|
|
||||||
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-audio-message" data:self.fakeAudioData key:nil contentType:@"audio/mp3"];
|
NSError *error;
|
||||||
|
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"];
|
||||||
|
[audioAttachment writeData:self.fakeAudioData error:&error];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(copy:)];
|
[self.messageAdapter performEditingAction:@selector(copy:)];
|
||||||
|
@ -227,7 +250,9 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
UIPasteboard.generalPasteboard.items = @[];
|
UIPasteboard.generalPasteboard.items = @[];
|
||||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4Audio]);
|
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4Audio]);
|
||||||
|
|
||||||
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-audio-message" data:self.fakeAudioData key:nil contentType:@"audio/x-m4a"];
|
NSError *error;
|
||||||
|
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/x-m4a"];
|
||||||
|
[audioAttachment writeData:self.fakeAudioData error:&error];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(copy:)];
|
[self.messageAdapter performEditingAction:@selector(copy:)];
|
||||||
|
@ -239,7 +264,9 @@ static NSString * const kTestingInteractionId = @"some-fake-testing-id";
|
||||||
UIPasteboard.generalPasteboard.items = @[];
|
UIPasteboard.generalPasteboard.items = @[];
|
||||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeAudio]);
|
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeAudio]);
|
||||||
|
|
||||||
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithIdentifier:@"fake-audio-message" data:self.fakeAudioData key:nil contentType:@"audio/wav"];
|
NSError *error;
|
||||||
|
TSAttachmentStream *audioAttachment = [[TSAttachmentStream alloc] initWithContentType:@"audio/wav"];
|
||||||
|
[audioAttachment writeData:self.fakeAudioData error:&error];
|
||||||
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO];
|
||||||
|
|
||||||
[self.messageAdapter performEditingAction:@selector(copy:)];
|
[self.messageAdapter performEditingAction:@selector(copy:)];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
TARGETS="Signal/src Pods/SignalServiceKit Pods/JSQMessagesViewController"
|
TARGETS="Signal/src ../SignalServiceKit/src Pods/JSQMessagesViewController"
|
||||||
TMP="$(mktemp -d)"
|
TMP="$(mktemp -d)"
|
||||||
STRINGFILE="Signal/translations/en.lproj/Localizable.strings"
|
STRINGFILE="Signal/translations/en.lproj/Localizable.strings"
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue