Audio farts.

slight change

modified pbxproj to clean up resources

reset developmentteam in pbxproj back to what it was before

deleted one line
pull/1/head
Joyce Yan 10 years ago committed by Frederic Jacobs
parent ccdc4b5d17
commit b494b71dbc

@ -287,6 +287,10 @@
AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; }; AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; };
AD41D7B51A6F6F0600241130 /* play_button.png in Resources */ = {isa = PBXBuildFile; fileRef = AD41D7B31A6F6F0600241130 /* play_button.png */; }; AD41D7B51A6F6F0600241130 /* play_button.png in Resources */ = {isa = PBXBuildFile; fileRef = AD41D7B31A6F6F0600241130 /* play_button.png */; };
AD41D7B61A6F6F0600241130 /* play_button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AD41D7B41A6F6F0600241130 /* play_button@2x.png */; }; AD41D7B61A6F6F0600241130 /* play_button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AD41D7B41A6F6F0600241130 /* play_button@2x.png */; };
B10C9B5F1A7049EC00ECA2BF /* pause_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B10C9B5B1A7049EC00ECA2BF /* pause_icon.png */; };
B10C9B601A7049EC00ECA2BF /* pause_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B10C9B5C1A7049EC00ECA2BF /* pause_icon@2x.png */; };
B10C9B611A7049EC00ECA2BF /* play_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B10C9B5D1A7049EC00ECA2BF /* play_icon.png */; };
B10C9B621A7049EC00ECA2BF /* play_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B10C9B5E1A7049EC00ECA2BF /* play_icon@2x.png */; };
B6019E971A2492AB001118DF /* NSDate+millisecondTimeStamp.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */; }; B6019E971A2492AB001118DF /* NSDate+millisecondTimeStamp.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */; };
B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C16641988999D00E97A6C /* VersionMigrations.m */; }; B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C16641988999D00E97A6C /* VersionMigrations.m */; };
B60EDE041A05A01700D73516 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B60EDE031A05A01700D73516 /* AudioToolbox.framework */; }; B60EDE041A05A01700D73516 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B60EDE031A05A01700D73516 /* AudioToolbox.framework */; };
@ -881,6 +885,10 @@
A5E9D4BA1A65FAD800E4481C /* TSVideoAttachmentAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSVideoAttachmentAdapter.h; sourceTree = "<group>"; }; A5E9D4BA1A65FAD800E4481C /* TSVideoAttachmentAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSVideoAttachmentAdapter.h; sourceTree = "<group>"; };
AD41D7B31A6F6F0600241130 /* play_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play_button.png; sourceTree = "<group>"; }; AD41D7B31A6F6F0600241130 /* play_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play_button.png; sourceTree = "<group>"; };
AD41D7B41A6F6F0600241130 /* play_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play_button@2x.png"; sourceTree = "<group>"; }; AD41D7B41A6F6F0600241130 /* play_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play_button@2x.png"; sourceTree = "<group>"; };
B10C9B5B1A7049EC00ECA2BF /* pause_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pause_icon.png; sourceTree = "<group>"; };
B10C9B5C1A7049EC00ECA2BF /* pause_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pause_icon@2x.png"; sourceTree = "<group>"; };
B10C9B5D1A7049EC00ECA2BF /* play_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play_icon.png; sourceTree = "<group>"; };
B10C9B5E1A7049EC00ECA2BF /* play_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play_icon@2x.png"; sourceTree = "<group>"; };
B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+millisecondTimeStamp.h"; sourceTree = "<group>"; }; B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+millisecondTimeStamp.h"; sourceTree = "<group>"; };
B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+millisecondTimeStamp.mm"; sourceTree = "<group>"; }; B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+millisecondTimeStamp.mm"; sourceTree = "<group>"; };
B60C16631988999D00E97A6C /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = "<group>"; }; B60C16631988999D00E97A6C /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = "<group>"; };
@ -2128,6 +2136,10 @@
B633C4FD1A1D190B0059AC12 /* Images */ = { B633C4FD1A1D190B0059AC12 /* Images */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B10C9B5B1A7049EC00ECA2BF /* pause_icon.png */,
B10C9B5C1A7049EC00ECA2BF /* pause_icon@2x.png */,
B10C9B5D1A7049EC00ECA2BF /* play_icon.png */,
B10C9B5E1A7049EC00ECA2BF /* play_icon@2x.png */,
AD41D7B31A6F6F0600241130 /* play_button.png */, AD41D7B31A6F6F0600241130 /* play_button.png */,
AD41D7B41A6F6F0600241130 /* play_button@2x.png */, AD41D7B41A6F6F0600241130 /* play_button@2x.png */,
FC3BD9851A30A62D005B96BB /* twitter@2x.png */, FC3BD9851A30A62D005B96BB /* twitter@2x.png */,
@ -2917,6 +2929,7 @@
FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */, FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */,
B633C5851A1D190B0059AC12 /* blue-archive@2x.png in Resources */, B633C5851A1D190B0059AC12 /* blue-archive@2x.png in Resources */,
B633C5D21A1D190B0059AC12 /* savephoto@2x.png in Resources */, B633C5D21A1D190B0059AC12 /* savephoto@2x.png in Resources */,
B10C9B611A7049EC00ECA2BF /* play_icon.png in Resources */,
B633C5921A1D190B0059AC12 /* contacts_tab@2x.png in Resources */, B633C5921A1D190B0059AC12 /* contacts_tab@2x.png in Resources */,
B6416FB8199A0478003C5699 /* Localizable.strings in Resources */, B6416FB8199A0478003C5699 /* Localizable.strings in Resources */,
FCB626A51A3B00FA00FDB504 /* info@2x.png in Resources */, FCB626A51A3B00FA00FDB504 /* info@2x.png in Resources */,
@ -2945,12 +2958,14 @@
FCA52B071A2BBAE400CCADFA /* call_tab@2x.png in Resources */, FCA52B071A2BBAE400CCADFA /* call_tab@2x.png in Resources */,
B633C58D1A1D190B0059AC12 /* contact_default_feed.png in Resources */, B633C58D1A1D190B0059AC12 /* contact_default_feed.png in Resources */,
FC3BD97C1A2CD385005B96BB /* signal_dotted@2x.png in Resources */, FC3BD97C1A2CD385005B96BB /* signal_dotted@2x.png in Resources */,
B10C9B621A7049EC00ECA2BF /* play_icon@2x.png in Resources */,
B633C5CD1A1D190B0059AC12 /* photo@2x.png in Resources */, B633C5CD1A1D190B0059AC12 /* photo@2x.png in Resources */,
A507A3B01A6C60E300BEED0D /* ContactTableViewCell.xib in Resources */, A507A3B01A6C60E300BEED0D /* ContactTableViewCell.xib in Resources */,
B633C5861A1D190B0059AC12 /* call@2x.png in Resources */, B633C5861A1D190B0059AC12 /* call@2x.png in Resources */,
B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */, B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */,
E1370BE418A0686C00826894 /* outring.mp3 in Resources */, E1370BE418A0686C00826894 /* outring.mp3 in Resources */,
B633C5841A1D190B0059AC12 /* backspace@2x.png in Resources */, B633C5841A1D190B0059AC12 /* backspace@2x.png in Resources */,
B10C9B601A7049EC00ECA2BF /* pause_icon@2x.png in Resources */,
B6C6AE551A305ED1006BAF8F /* redphone.cer in Resources */, B6C6AE551A305ED1006BAF8F /* redphone.cer in Resources */,
B633C5B71A1D190B0059AC12 /* logo_intro@2x.png in Resources */, B633C5B71A1D190B0059AC12 /* logo_intro@2x.png in Resources */,
E1370BE518A0686C00826894 /* r.caf in Resources */, E1370BE518A0686C00826894 /* r.caf in Resources */,
@ -2962,6 +2977,7 @@
B633C58F1A1D190B0059AC12 /* contacts@2x.png in Resources */, B633C58F1A1D190B0059AC12 /* contacts@2x.png in Resources */,
E1370BE618A0686C00826894 /* sonarping.mp3 in Resources */, E1370BE618A0686C00826894 /* sonarping.mp3 in Resources */,
B633C5961A1D190B0059AC12 /* DefaultContactImage.png in Resources */, B633C5961A1D190B0059AC12 /* DefaultContactImage.png in Resources */,
B10C9B5F1A7049EC00ECA2BF /* pause_icon.png in Resources */,
E148751218A06AFD002CC4F3 /* HelveticaNeueLTStd-Bd.otf in Resources */, E148751218A06AFD002CC4F3 /* HelveticaNeueLTStd-Bd.otf in Resources */,
FCA52AE61A2B676C00CCADFA /* call_canceled@2x.png in Resources */, FCA52AE61A2B676C00CCADFA /* call_canceled@2x.png in Resources */,
FC3BD9861A30A62D005B96BB /* twitter@2x.png in Resources */, FC3BD9861A30A62D005B96BB /* twitter@2x.png in Resources */,

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -21,7 +21,7 @@
- (BOOL)isImage; - (BOOL)isImage;
- (BOOL)isVideo; - (BOOL)isVideo;
-(NSURL*)videoURL; -(NSURL*)mediaURL;
+ (void)deleteAttachments; + (void)deleteAttachments;
@end @end

@ -62,7 +62,7 @@ NSString * const TSAttachementFileRelationshipEdge = @"TSAttachementFileEdge";
} }
} }
-(NSURL*) videoURL { -(NSURL*) mediaURL {
return [NSURL fileURLWithPath:[self filePath]]; return [NSURL fileURLWithPath:[self filePath]];
} }

@ -48,7 +48,7 @@ dispatch_queue_t attachmentsQueue() {
for (PushMessageContentAttachmentPointer *pointer in attachmentsToRetrieve) { for (PushMessageContentAttachmentPointer *pointer in attachmentsToRetrieve) {
TSAttachmentPointer *attachmentPointer = (content.group != nil && (content.group.type == PushMessageContentGroupContextTypeUpdate)) ? [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay avatarOfGroupId:content.group.id] : [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay]; TSAttachmentPointer *attachmentPointer = (content.group != nil && (content.group.type == PushMessageContentGroupContextTypeUpdate)) ? [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay avatarOfGroupId:content.group.id] : [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay];
if ([attachmentPointer.contentType hasPrefix:@"image/"]||[attachmentPointer.contentType hasPrefix:@"video/"]) { if ([attachmentPointer.contentType hasPrefix:@"image/"]||[attachmentPointer.contentType hasPrefix:@"video/"] || [attachmentPointer.contentType hasPrefix:@"audio/"]) {
[attachmentPointer saveWithTransaction:transaction]; [attachmentPointer saveWithTransaction:transaction];
dispatch_async(attachmentsQueue(), ^{ dispatch_async(attachmentsQueue(), ^{

@ -85,6 +85,7 @@ typedef enum : NSUInteger {
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData; @property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData; @property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingMessageFailedImageData; @property (nonatomic, retain) JSQMessagesBubbleImage *outgoingMessageFailedImageData;
@property (nonatomic, strong) NSTimer *audioPlayerPoller;
@property (nonatomic, retain) NSTimer *readTimer; @property (nonatomic, retain) NSTimer *readTimer;
@ -105,7 +106,7 @@ typedef enum : NSUInteger {
- (void)setupWithTSGroup:(TSGroupModel*)model { - (void)setupWithTSGroup:(TSGroupModel*)model {
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
self.thread = [TSGroupThread getOrCreateThreadWithGroupModel:model transaction:transaction]; self.thread = [TSGroupThread getOrCreateThreadWithGroupModel:model transaction:transaction];
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:@"" attachments:[[NSMutableArray alloc] init]]; TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:@"" attachments:[[NSMutableArray alloc] init]];
message.groupMetaMessage = TSGroupMessageNew; message.groupMetaMessage = TSGroupMessageNew;
if(model.groupImage!=nil) { if(model.groupImage!=nil) {
@ -131,30 +132,32 @@ typedef enum : NSUInteger {
} }
} }
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
[self.navigationController.navigationBar setTranslucent:NO]; [self.navigationController.navigationBar setTranslucent:NO];
[super viewDidLoad];
[self markAllMessagesAsRead]; [self markAllMessagesAsRead];
[self initializeBubbles]; [self initializeBubbles];
[self initializeTextView]; [self initializeTextView];
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[self.thread.uniqueId] self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[self.thread.uniqueId]
view:TSMessageDatabaseViewExtensionName]; view:TSMessageDatabaseViewExtensionName];
self.page = 0; self.page = 0;
[self updateRangeOptionsForPage:self.page]; [self updateRangeOptionsForPage:self.page];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.messageMappings updateWithTransaction:transaction]; [self.messageMappings updateWithTransaction:transaction];
}]; }];
[self initializeToolbars]; [self initializeToolbars];
[self initializeCollectionViewLayout]; [self initializeCollectionViewLayout];
self.senderId = ME_MESSAGE_IDENTIFIER self.senderId = ME_MESSAGE_IDENTIFIER
self.senderDisplayName = ME_MESSAGE_IDENTIFIER self.senderDisplayName = ME_MESSAGE_IDENTIFIER
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startReadTimer) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startReadTimer)
name:UIApplicationWillEnterForegroundNotification object:nil]; name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelReadTimer) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelReadTimer)
@ -170,9 +173,9 @@ typedef enum : NSUInteger {
-(void)viewWillAppear:(BOOL)animated -(void)viewWillAppear:(BOOL)animated
{ {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
NSInteger numberOfMessages = (NSInteger)[self.messageMappings numberOfItemsInGroup:self.thread.uniqueId]; NSInteger numberOfMessages = (NSInteger)[self.messageMappings numberOfItemsInGroup:self.thread.uniqueId];
if (numberOfMessages > 0) { if (numberOfMessages > 0) {
NSIndexPath * lastCellIndexPath = [NSIndexPath indexPathForRow:numberOfMessages-1 inSection:0]; NSIndexPath * lastCellIndexPath = [NSIndexPath indexPathForRow:numberOfMessages-1 inSection:0];
[self.collectionView scrollToItemAtIndexPath:lastCellIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; [self.collectionView scrollToItemAtIndexPath:lastCellIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
@ -218,7 +221,7 @@ typedef enum : NSUInteger {
} }
} }
} }
[self cancelReadTimer]; [self cancelReadTimer];
} }
@ -230,11 +233,11 @@ typedef enum : NSUInteger {
- (IBAction)didSelectShow:(id)sender { - (IBAction)didSelectShow:(id)sender {
UIBarButtonItem *spaceEdge = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; UIBarButtonItem *spaceEdge = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spaceEdge.width = 40; spaceEdge.width = 40;
UIBarButtonItem *spaceMiddleIcons = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; UIBarButtonItem *spaceMiddleIcons = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spaceMiddleIcons.width = 61; spaceMiddleIcons.width = 61;
@ -242,12 +245,12 @@ typedef enum : NSUInteger {
if (!isGroupConversation) { if (!isGroupConversation) {
//UIBarButtonItem* contactAddOrLaunch = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"contact-add@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:nil]; //UIBarButtonItem* contactAddOrLaunch = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"contact-add@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:nil];
UIBarButtonItem* contactSecurity = [[UIBarButtonItem alloc]initWithImage:[[UIImage imageNamed:@"contact-security@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(showFingerprint)]; UIBarButtonItem* contactSecurity = [[UIBarButtonItem alloc]initWithImage:[[UIImage imageNamed:@"contact-security@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(showFingerprint)];
if ([self isRedPhoneReachable] && ![((TSContactThread*)_thread).contactIdentifier isEqualToString:[SignalKeyingStorage.localNumber toE164]]) { if ([self isRedPhoneReachable] && ![((TSContactThread*)_thread).contactIdentifier isEqualToString:[SignalKeyingStorage.localNumber toE164]]) {
UIBarButtonItem * callButton = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"contact-call@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(callAction)]; UIBarButtonItem * callButton = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"contact-call@1x"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(callAction)];
self.navController.dropDownToolbar.items = @[spaceEdge, callButton,spaceMiddleWords, contactSecurity, spaceEdge]; self.navController.dropDownToolbar.items = @[spaceEdge, callButton,spaceMiddleWords, contactSecurity, spaceEdge];
@ -259,9 +262,9 @@ typedef enum : NSUInteger {
else { else {
UIBarButtonItem *groupUpdateButton = [[UIBarButtonItem alloc] initWithTitle:@"Update" style:UIBarButtonItemStylePlain target:self action:@selector(updateGroup)]; UIBarButtonItem *groupUpdateButton = [[UIBarButtonItem alloc] initWithTitle:@"Update" style:UIBarButtonItemStylePlain target:self action:@selector(updateGroup)];
UIBarButtonItem *groupLeaveButton = [[UIBarButtonItem alloc] initWithTitle:@"Leave" style:UIBarButtonItemStylePlain target:self action:@selector(leaveGroup)]; UIBarButtonItem *groupLeaveButton = [[UIBarButtonItem alloc] initWithTitle:@"Leave" style:UIBarButtonItemStylePlain target:self action:@selector(leaveGroup)];
UIBarButtonItem *showGroupMembersButton = [[UIBarButtonItem alloc] initWithTitle:@"Members" style:UIBarButtonItemStylePlain target:self action:@selector(showGroupMembers)]; UIBarButtonItem *showGroupMembersButton = [[UIBarButtonItem alloc] initWithTitle:@"Members" style:UIBarButtonItemStylePlain target:self action:@selector(showGroupMembers)];
self.navController.dropDownToolbar.items =@[spaceEdge, groupUpdateButton, spaceMiddleWords, groupLeaveButton, spaceMiddleWords, showGroupMembersButton, spaceEdge]; self.navController.dropDownToolbar.items =@[spaceEdge, groupUpdateButton, spaceMiddleWords, groupLeaveButton, spaceMiddleWords, showGroupMembersButton, spaceEdge];
} }
for(UIButton *button in self.navController.dropDownToolbar.items) { for(UIButton *button in self.navController.dropDownToolbar.items) {
@ -285,7 +288,7 @@ typedef enum : NSUInteger {
} }
-(void)initializeToolbars { -(void)initializeToolbars {
self.navController = (APNavigationController*)self.navigationController; self.navController = (APNavigationController*)self.navigationController;
//self.navController.activeBarButtonTitle = @"Hide"; //self.navController.activeBarButtonTitle = @"Hide";
[self setNavigationTitle]; [self setNavigationTitle];
@ -295,23 +298,22 @@ typedef enum : NSUInteger {
-(void)initializeBubbles -(void)initializeBubbles
{ {
JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init]; JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];
self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]]; self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]];
self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]]; self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessageFailedBubbleImageWithColor:[UIColor ows_fadedBlueColor]]; self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessageFailedBubbleImageWithColor:[UIColor ows_fadedBlueColor]];
} }
-(void)initializeCollectionViewLayout -(void)initializeCollectionViewLayout
{ {
if (self.collectionView){ if (self.collectionView){
[self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_regularFontWithSize:15.0f]]; [self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_regularFontWithSize:15.0f]];
self.collectionView.showsVerticalScrollIndicator = NO; self.collectionView.showsVerticalScrollIndicator = NO;
self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.showsHorizontalScrollIndicator = NO;
[self updateLoadEarlierVisible]; [self updateLoadEarlierVisible];
self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero; self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero; self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;
} }
@ -350,7 +352,7 @@ typedef enum : NSUInteger {
if ([self isRedPhoneReachable]) { if ([self isRedPhoneReachable]) {
PhoneNumber *number = [self phoneNumberForThread]; PhoneNumber *number = [self phoneNumberForThread];
Contact *contact = [[Environment.getCurrent contactsManager] latestContactForPhoneNumber:number]; Contact *contact = [[Environment.getCurrent contactsManager] latestContactForPhoneNumber:number];
[Environment.phoneManager initiateOutgoingCallToContact:contact atRemoteNumber:number]; [Environment.phoneManager initiateOutgoingCallToContact:contact atRemoteNumber:number];
} else { } else {
DDLogWarn(@"Tried to initiate a call but contact has no RedPhone identifier"); DDLogWarn(@"Tried to initiate a call but contact has no RedPhone identifier");
@ -367,9 +369,9 @@ typedef enum : NSUInteger {
{ {
if (text.length > 0) { if (text.length > 0) {
[JSQSystemSoundPlayer jsq_playMessageSentSound]; [JSQSystemSoundPlayer jsq_playMessageSentSound];
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:text attachments:nil]; TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:text attachments:nil];
[[TSMessagesManager sharedManager] sendMessage:message inThread:self.thread]; [[TSMessagesManager sharedManager] sendMessage:message inThread:self.thread];
[self finishSendingMessage]; [self finishSendingMessage];
} }
@ -386,14 +388,14 @@ typedef enum : NSUInteger {
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath - (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath
{ {
id<JSQMessageData> message = [self messageAtIndexPath:indexPath]; id<JSQMessageData> message = [self messageAtIndexPath:indexPath];
if ([message.senderId isEqualToString:self.senderId]) { if ([message.senderId isEqualToString:self.senderId]) {
if (message.messageState == TSOutgoingMessageStateUnsent || message.messageState == TSOutgoingMessageStateAttemptingOut) { if (message.messageState == TSOutgoingMessageStateUnsent || message.messageState == TSOutgoingMessageStateAttemptingOut) {
return self.outgoingMessageFailedImageData; return self.outgoingMessageFailedImageData;
} }
return self.outgoingBubbleImageData; return self.outgoingBubbleImageData;
} }
return self.incomingBubbleImageData; return self.incomingBubbleImageData;
} }
@ -407,7 +409,7 @@ typedef enum : NSUInteger {
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath - (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{ {
TSMessageAdapter * msg = [self messageAtIndexPath:indexPath]; TSMessageAdapter * msg = [self messageAtIndexPath:indexPath];
switch (msg.messageType) { switch (msg.messageType) {
case TSIncomingMessageAdapter: case TSIncomingMessageAdapter:
return [self loadIncomingMessageCellForMessage:msg atIndexPath:indexPath]; return [self loadIncomingMessageCellForMessage:msg atIndexPath:indexPath];
@ -419,7 +421,7 @@ typedef enum : NSUInteger {
return [self loadInfoMessageCellForMessage:msg atIndexPath:indexPath]; return [self loadInfoMessageCellForMessage:msg atIndexPath:indexPath];
case TSErrorMessageAdapter: case TSErrorMessageAdapter:
return [self loadErrorMessageCellForMessage:msg atIndexPath:indexPath]; return [self loadErrorMessageCellForMessage:msg atIndexPath:indexPath];
default: default:
NSLog(@"Something went wrong"); NSLog(@"Something went wrong");
return nil; return nil;
@ -437,7 +439,7 @@ typedef enum : NSUInteger {
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
} }
return cell; return cell;
} }
@ -451,7 +453,7 @@ typedef enum : NSUInteger {
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
} }
return cell; return cell;
} }
@ -481,7 +483,7 @@ typedef enum : NSUInteger {
if ([self showDateAtIndexPath:indexPath]) { if ([self showDateAtIndexPath:indexPath]) {
return kJSQMessagesCollectionViewCellLabelHeightDefault; return kJSQMessagesCollectionViewCellLabelHeightDefault;
} }
return 0.0f; return 0.0f;
} }
@ -493,9 +495,9 @@ typedef enum : NSUInteger {
} }
else { else {
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
TSMessageAdapter *previousMessage = [self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row-1 inSection:indexPath.section]]; TSMessageAdapter *previousMessage = [self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row-1 inSection:indexPath.section]];
NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date]; NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date];
if (timeDifference > kTSMessageSentDateShowTimeInterval) { if (timeDifference > kTSMessageSentDateShowTimeInterval) {
showDate = YES; showDate = YES;
@ -506,19 +508,19 @@ typedef enum : NSUInteger {
-(NSAttributedString*)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath -(NSAttributedString*)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath
{ {
if ([self showDateAtIndexPath:indexPath]) { if ([self showDateAtIndexPath:indexPath]) {
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:currentMessage.date]; return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:currentMessage.date];
} }
return nil; return nil;
} }
-(BOOL)shouldShowMessageStatusAtIndexPath:(NSIndexPath*)indexPath -(BOOL)shouldShowMessageStatusAtIndexPath:(NSIndexPath*)indexPath
{ {
TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath];
if([self.thread isKindOfClass:[TSGroupThread class]]) { if([self.thread isKindOfClass:[TSGroupThread class]]) {
return currentMessage.messageType == TSIncomingMessageAdapter; return currentMessage.messageType == TSIncomingMessageAdapter;
@ -527,11 +529,11 @@ typedef enum : NSUInteger {
if (indexPath.item == [self.collectionView numberOfItemsInSection:indexPath.section]-1) { if (indexPath.item == [self.collectionView numberOfItemsInSection:indexPath.section]-1) {
return [self isMessageOutgoingAndDelivered:currentMessage]; return [self isMessageOutgoingAndDelivered:currentMessage];
} }
if (![self isMessageOutgoingAndDelivered:currentMessage]) { if (![self isMessageOutgoingAndDelivered:currentMessage]) {
return NO; return NO;
} }
TSMessageAdapter *nextMessage = [self nextOutgoingMessage:indexPath]; TSMessageAdapter *nextMessage = [self nextOutgoingMessage:indexPath];
return ![self isMessageOutgoingAndDelivered:nextMessage]; return ![self isMessageOutgoingAndDelivered:nextMessage];
} }
@ -541,12 +543,12 @@ typedef enum : NSUInteger {
{ {
TSMessageAdapter * nextMessage = [self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]]; TSMessageAdapter * nextMessage = [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 && ![self isMessageOutgoingAndDelivered:nextMessage]) { while (indexPath.item+i < [self.collectionView numberOfItemsInSection:indexPath.section]-1 && ![self isMessageOutgoingAndDelivered:nextMessage]) {
i++; i++;
nextMessage = [self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+i inSection:indexPath.section]]; nextMessage = [self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+i inSection:indexPath.section]];
} }
return nextMessage; return nextMessage;
} }
@ -566,7 +568,7 @@ typedef enum : NSUInteger {
name = name ? name : msg.senderId; name = name ? name : msg.senderId;
NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:name]; NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:name];
[attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]]; [attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
return (NSAttributedString*)attrStr; return (NSAttributedString*)attrStr;
} }
else { else {
@ -575,7 +577,7 @@ typedef enum : NSUInteger {
textAttachment.bounds = CGRectMake(0, 0, 11.0f, 10.0f); textAttachment.bounds = CGRectMake(0, 0, 11.0f, 10.0f);
NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:@"Delivered"]; NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:@"Delivered"];
[attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]]; [attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
return (NSAttributedString*)attrStr; return (NSAttributedString*)attrStr;
} }
} }
@ -594,7 +596,7 @@ typedef enum : NSUInteger {
else if (msg.messageType == TSOutgoingMessageAdapter) { else if (msg.messageType == TSOutgoingMessageAdapter) {
return 16.0f; return 16.0f;
} }
return 0.0f; return 0.0f;
} }
@ -605,20 +607,20 @@ typedef enum : NSUInteger {
{ {
TSMessageAdapter *messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath]; TSMessageAdapter *messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
switch (messageItem.messageType) { switch (messageItem.messageType) {
case TSOutgoingMessageAdapter: case TSOutgoingMessageAdapter:
if (messageItem.messageState == TSOutgoingMessageStateUnsent) { if (messageItem.messageState == TSOutgoingMessageStateUnsent) {
[self handleUnsentMessageTap:(TSOutgoingMessage*)interaction]; [self handleUnsentMessageTap:(TSOutgoingMessage*)interaction];
} }
case TSIncomingMessageAdapter:{ case TSIncomingMessageAdapter:{
BOOL isMediaMessage = [messageItem isMediaMessage]; BOOL isMediaMessage = [messageItem isMediaMessage];
if (isMediaMessage) { if (isMediaMessage) {
if([[messageItem media] isKindOfClass:[TSAttachmentAdapter class]]) { if([[messageItem media] isKindOfClass:[TSAttachmentAdapter class]]) {
TSAttachmentAdapter* messageMedia = (TSAttachmentAdapter*)[messageItem media]; TSAttachmentAdapter* messageMedia = (TSAttachmentAdapter*)[messageItem media];
if ([messageMedia isImage]) { if ([messageMedia isImage]) {
tappedImage = ((UIImageView*)[messageMedia mediaView]).image; tappedImage = ((UIImageView*)[messageMedia mediaView]).image;
CGRect convertedRect = [self.collectionView convertRect:[collectionView cellForItemAtIndexPath:indexPath].frame toView:nil]; CGRect convertedRect = [self.collectionView convertRect:[collectionView cellForItemAtIndexPath:indexPath].frame toView:nil];
@ -626,11 +628,11 @@ typedef enum : NSUInteger {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction]; attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction];
}]; }];
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
TSAttachmentStream *attStream = (TSAttachmentStream*)attachment; TSAttachmentStream *attStream = (TSAttachmentStream*)attachment;
FullImageViewController * vc = [[FullImageViewController alloc] initWithAttachment:attStream fromRect:convertedRect forInteraction:[self interactionAtIndexPath:indexPath]]; FullImageViewController * vc = [[FullImageViewController alloc] initWithAttachment:attStream fromRect:convertedRect forInteraction:[self interactionAtIndexPath:indexPath]];
[self presentViewController:vc animated:YES completion:^{ [self presentViewController:vc animated:YES completion:^{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}]; }];
@ -643,39 +645,84 @@ typedef enum : NSUInteger {
// fileurl disappeared should look up in db as before. will do refactor // fileurl disappeared should look up in db as before. will do refactor
// full screen, check this setup with a .mov // full screen, check this setup with a .mov
TSVideoAttachmentAdapter* messageMedia = (TSVideoAttachmentAdapter*)[messageItem media]; TSVideoAttachmentAdapter* messageMedia = (TSVideoAttachmentAdapter*)[messageItem media];
__block TSAttachment *attachment = nil; __block TSAttachment *attachment = nil;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction]; attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction];
}]; }];
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
TSAttachmentStream *attStream = (TSAttachmentStream*)attachment; TSAttachmentStream *attStream = (TSAttachmentStream*)attachment;
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
if([messageMedia isVideo]) { if([messageMedia isVideo]) {
if ([fileManager fileExistsAtPath:[attStream.videoURL path]]) { if ([fileManager fileExistsAtPath:[attStream.mediaURL path]]) {
_videoPlayer = [[MPMoviePlayerController alloc] initWithContentURL:attStream.videoURL]; _videoPlayer = [[MPMoviePlayerController alloc] initWithContentURL:attStream.mediaURL];
[_videoPlayer prepareToPlay]; [_videoPlayer prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackDidFinish:) selector:@selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification name:MPMoviePlayerPlaybackDidFinishNotification
object: _videoPlayer]; object: _videoPlayer];
_videoPlayer.controlStyle = MPMovieControlStyleDefault; _videoPlayer.controlStyle = MPMovieControlStyleDefault;
_videoPlayer.shouldAutoplay = YES; _videoPlayer.shouldAutoplay = YES;
[self.view addSubview: _videoPlayer.view]; [self.view addSubview: _videoPlayer.view];
[_videoPlayer setFullscreen:YES animated:YES]; [_videoPlayer setFullscreen:YES animated:YES];
} }
} } else if([messageMedia isAudio]){
else if([messageMedia isAudio]){ if (messageMedia.isAudioPlaying) {
DDLogDebug(@"audio location is %@",attStream.videoURL); // if you had started playing an audio msg and now you're tapping it to pause
NSError *error; messageMedia.isAudioPlaying = NO;
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:attStream.videoURL error:&error]; [_audioPlayer pause];
DDLogDebug(@"audio debug is %@",error); messageMedia.isPaused = YES;
[_audioPlayer prepareToPlay]; [_audioPlayerPoller invalidate];
[_audioPlayer play]; double current = [_audioPlayer currentTime]/[_audioPlayer duration];
[messageMedia setAudioProgressFromFloat:(float)current];
[messageMedia setAudioIconToPlay];
} else {
BOOL isResuming = NO;
[_audioPlayerPoller invalidate];
// loop through all the other bubbles and set their isPlaying to false
NSInteger num_bubbles = [self collectionView:collectionView numberOfItemsInSection:0];
for (NSInteger i=0; i<num_bubbles; i++) {
NSIndexPath *index_path = [NSIndexPath indexPathForRow:i inSection:0];
TSMessageAdapter *msgAdapter = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:index_path];
if (msgAdapter.messageType == TSIncomingMessageAdapter && msgAdapter.isMediaMessage) {
TSVideoAttachmentAdapter* msgMedia = (TSVideoAttachmentAdapter*)[msgAdapter media];
if ([msgMedia isAudio]) {
if (msgMedia == messageMedia && messageMedia.isPaused) {
isResuming = YES;
} else {
msgMedia.isAudioPlaying = NO;
msgMedia.isPaused = NO;
[msgMedia setAudioIconToPlay];
[msgMedia setAudioProgressFromFloat:0];
}
}
}
}
if (isResuming) {
// if you had paused an audio msg and now you're tapping to resume
[_audioPlayer prepareToPlay];
[_audioPlayer play];
[messageMedia setAudioIconToPause];
messageMedia.isAudioPlaying = YES;
messageMedia.isPaused = NO;
_audioPlayerPoller = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(audioPlayerUpdated:) userInfo:@{@"adapter": messageMedia} repeats:YES];
} else {
// if you are tapping an audio msg for the first time to play
messageMedia.isAudioPlaying = YES;
NSError *error;
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:attStream.mediaURL error:&error];
[_audioPlayer prepareToPlay];
[_audioPlayer play];
[messageMedia setAudioIconToPause];
_audioPlayer.delegate = self;
_audioPlayerPoller = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(audioPlayerUpdated:) userInfo:@{@"adapter": messageMedia} repeats:YES];
}
}
} }
} }
} }
@ -694,7 +741,6 @@ typedef enum : NSUInteger {
} }
} }
-(NSURL*) changeFile:(NSURL*)originalFile toHaveExtension:(NSString*)extension { -(NSURL*) changeFile:(NSURL*)originalFile toHaveExtension:(NSString*)extension {
NSFileManager *fileManager = [NSFileManager defaultManager]; NSFileManager *fileManager = [NSFileManager defaultManager];
NSString* newPath = [[originalFile path] stringByAppendingPathExtension:extension]; NSString* newPath = [[originalFile path] stringByAppendingPathExtension:extension];
@ -714,47 +760,47 @@ typedef enum : NSUInteger {
if ([self shouldShowLoadEarlierMessages]) { if ([self shouldShowLoadEarlierMessages]) {
self.page++; self.page++;
} }
NSInteger item = (NSInteger)[self scrollToItem]; NSInteger item = (NSInteger)[self scrollToItem];
[self updateRangeOptionsForPage:self.page]; [self updateRangeOptionsForPage:self.page];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.messageMappings updateWithTransaction:transaction]; [self.messageMappings updateWithTransaction:transaction];
}]; }];
[self updateLayoutForEarlierMessagesWithOffset:item]; [self updateLayoutForEarlierMessagesWithOffset:item];
} }
-(BOOL)shouldShowLoadEarlierMessages -(BOOL)shouldShowLoadEarlierMessages
{ {
__block BOOL show = YES; __block BOOL show = YES;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){ [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
show = [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId] < [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:self.thread.uniqueId]; show = [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId] < [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:self.thread.uniqueId];
}]; }];
return show; return show;
} }
-(NSUInteger)scrollToItem -(NSUInteger)scrollToItem
{ {
__block NSUInteger item = kYapDatabaseRangeLength*(self.page+1) - [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId]; __block NSUInteger item = kYapDatabaseRangeLength*(self.page+1) - [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
NSUInteger numberOfVisibleMessages = [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId] ; NSUInteger numberOfVisibleMessages = [self.messageMappings numberOfItemsInGroup:self.thread.uniqueId] ;
NSUInteger numberOfTotalMessages = [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:self.thread.uniqueId] ; NSUInteger numberOfTotalMessages = [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:self.thread.uniqueId] ;
NSUInteger numberOfMessagesToLoad = numberOfTotalMessages - numberOfVisibleMessages ; NSUInteger numberOfMessagesToLoad = numberOfTotalMessages - numberOfVisibleMessages ;
BOOL canLoadFullRange = numberOfMessagesToLoad >= kYapDatabaseRangeLength; BOOL canLoadFullRange = numberOfMessagesToLoad >= kYapDatabaseRangeLength;
if (!canLoadFullRange) { if (!canLoadFullRange) {
item = numberOfMessagesToLoad; item = numberOfMessagesToLoad;
} }
}]; }];
return item == 0 ? item : item - 1; return item == 0 ? item : item - 1;
} }
@ -767,21 +813,21 @@ typedef enum : NSUInteger {
{ {
[self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]]; [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
[self.collectionView reloadData]; [self.collectionView reloadData];
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:offset inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:offset inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
[self updateLoadEarlierVisible]; [self updateLoadEarlierVisible];
} }
-(void)updateRangeOptionsForPage:(NSUInteger)page -(void)updateRangeOptionsForPage:(NSUInteger)page
{ {
YapDatabaseViewRangeOptions *rangeOptions = [YapDatabaseViewRangeOptions flexibleRangeWithLength:kYapDatabaseRangeLength*(page+1) offset:0 from:YapDatabaseViewEnd]; YapDatabaseViewRangeOptions *rangeOptions = [YapDatabaseViewRangeOptions flexibleRangeWithLength:kYapDatabaseRangeLength*(page+1) offset:0 from:YapDatabaseViewEnd];
rangeOptions.maxLength = kYapDatabaseRangeMaxLength; rangeOptions.maxLength = kYapDatabaseRangeMaxLength;
rangeOptions.minLength = kYapDatabaseRangeMinLength; rangeOptions.minLength = kYapDatabaseRangeMinLength;
[self.messageMappings setRangeOptions:rangeOptions forGroup:self.thread.uniqueId]; [self.messageMappings setRangeOptions:rangeOptions forGroup:self.thread.uniqueId];
} }
#pragma mark Bubble User Actions #pragma mark Bubble User Actions
@ -815,7 +861,7 @@ typedef enum : NSUInteger {
NSString *newKeyFingerprint = [errorMessage newIdentityKey]; NSString *newKeyFingerprint = [errorMessage newIdentityKey];
NSString *messageString = [NSString stringWithFormat:@"Do you want to accept %@'s new identity key: %@", _thread.name, newKeyFingerprint]; NSString *messageString = [NSString stringWithFormat:@"Do you want to accept %@'s new identity key: %@", _thread.name, newKeyFingerprint];
NSArray *actions = @[@"Accept new identity key", @"Copy new identity key to pasteboard"]; NSArray *actions = @[@"Accept new identity key", @"Copy new identity key to pasteboard"];
[self.inputToolbar.contentView.textView resignFirstResponder]; [self.inputToolbar.contentView.textView resignFirstResponder];
[DJWActionSheet showInView:self.parentViewController.view withTitle:messageString cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:actions tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) { [DJWActionSheet showInView:self.parentViewController.view withTitle:messageString cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:actions tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
@ -844,7 +890,7 @@ typedef enum : NSUInteger {
#pragma mark - Navigation #pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:kFingerprintSegueIdentifier]){ if ([segue.identifier isEqualToString:kFingerprintSegueIdentifier]){
FingerprintViewController *vc = [segue destinationViewController]; FingerprintViewController *vc = [segue destinationViewController];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
@ -878,13 +924,13 @@ typedef enum : NSUInteger {
picker.delegate = self; picker.delegate = self;
picker.allowsEditing = NO; picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera; picker.sourceType = UIImagePickerControllerSourceTypeCamera;
if ([UIImagePickerController isSourceTypeAvailable: if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera]) { UIImagePickerControllerSourceTypeCamera]) {
picker.mediaTypes = @[(NSString*)kUTTypeImage,(NSString*)kUTTypeMovie]; picker.mediaTypes = @[(NSString*)kUTTypeImage,(NSString*)kUTTypeMovie];
[self presentViewController:picker animated:YES completion:NULL]; [self presentViewController:picker animated:YES completion:NULL];
} }
} }
-(void)chooseFromLibrary:(kMediaTypes)mediaType -(void)chooseFromLibrary:(kMediaTypes)mediaType
@ -892,15 +938,15 @@ typedef enum : NSUInteger {
UIImagePickerController *picker = [[UIImagePickerController alloc] init]; UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self; picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{ {
NSArray* pictureTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeImage, nil]; NSArray* pictureTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeImage, nil];
NSArray* videoTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo, nil]; NSArray* videoTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo, nil];
picker.mediaTypes = (mediaType == kMediaTypePicture) ? pictureTypeArray : videoTypeArray; picker.mediaTypes = (mediaType == kMediaTypePicture) ? pictureTypeArray : videoTypeArray;
[self presentViewController:picker animated:YES completion:nil]; [self presentViewController:picker animated:YES completion:nil];
} }
} }
@ -926,24 +972,24 @@ typedef enum : NSUInteger {
[self sendQualityAdjustedAttachment:videoURL]; [self sendQualityAdjustedAttachment:videoURL];
} }
else { else {
UIImage *picture_camera = [[info objectForKey:UIImagePickerControllerOriginalImage] normalizedImage]; UIImage *picture_camera = [[info objectForKey:UIImagePickerControllerOriginalImage] normalizedImage];
if(picture_camera) { if(picture_camera) {
DDLogVerbose(@"Sending picture attachement ..."); DDLogVerbose(@"Sending picture attachement ...");
[self sendMessageAttachment:[self qualityAdjustedAttachmentForImage:picture_camera] ofType:@"image/jpeg"]; [self sendMessageAttachment:[self qualityAdjustedAttachmentForImage:picture_camera] ofType:@"image/jpeg"];
} }
} }
} }
-(void) sendMessageAttachment:(NSData*)attachmentData ofType:(NSString*)attachmentType { -(void) sendMessageAttachment:(NSData*)attachmentData ofType:(NSString*)attachmentType {
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:nil attachments:[NSMutableArray array]]; TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:nil attachments:[NSMutableArray array]];
[[TSMessagesManager sharedManager] sendAttachment:attachmentData contentType:attachmentType inMessage:message thread:self.thread]; [[TSMessagesManager sharedManager] sendAttachment:attachmentData contentType:attachmentType inMessage:message thread:self.thread];
[self finishSendingMessage]; [self finishSendingMessage];
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
} }
-(void)sendQualityAdjustedAttachment:(NSURL*)movieURL { -(void)sendQualityAdjustedAttachment:(NSURL*)movieURL {
@ -952,47 +998,47 @@ typedef enum : NSUInteger {
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality]; AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
exportSession.shouldOptimizeForNetworkUse = YES; exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeMPEG4; exportSession.outputFileType = AVFileTypeMPEG4;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
basePath = [basePath stringByAppendingPathComponent:@"videos"]; basePath = [basePath stringByAppendingPathComponent:@"videos"];
if (![[NSFileManager defaultManager] fileExistsAtPath:basePath]) { if (![[NSFileManager defaultManager] fileExistsAtPath:basePath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil]; [[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil];
} }
NSURL *compressedVideoUrl = [NSURL fileURLWithPath:basePath]; NSURL *compressedVideoUrl = [NSURL fileURLWithPath:basePath];
long currentTime = [[NSDate date] timeIntervalSince1970]; long currentTime = [[NSDate date] timeIntervalSince1970];
NSString *strImageName = [NSString stringWithFormat:@"%ld",currentTime]; NSString *strImageName = [NSString stringWithFormat:@"%ld",currentTime];
compressedVideoUrl=[compressedVideoUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",strImageName]]; compressedVideoUrl=[compressedVideoUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",strImageName]];
exportSession.outputURL = compressedVideoUrl; exportSession.outputURL = compressedVideoUrl;
[exportSession exportAsynchronouslyWithCompletionHandler:^{ [exportSession exportAsynchronouslyWithCompletionHandler:^{
}]; }];
while(exportSession.progress!=1){ while(exportSession.progress!=1){
} }
[self sendMessageAttachment:[NSData dataWithContentsOfURL:compressedVideoUrl] ofType:@"video/mp4"]; [self sendMessageAttachment:[NSData dataWithContentsOfURL:compressedVideoUrl] ofType:@"video/mp4"];
#if 0 #if 0
return [NSData dataWithContentsOfURL:movieURL]; return [NSData dataWithContentsOfURL:movieURL];
#endif #endif
#if 0 #if 0
NSString *serializationQueueDescription = [NSString stringWithFormat:@"%@ serialization queue", self]; NSString *serializationQueueDescription = [NSString stringWithFormat:@"%@ serialization queue", self];
// Create the main serialization queue. // Create the main serialization queue.
self.mainSerializationQueue = dispatch_queue_create([serializationQueueDescription UTF8String], NULL); self.mainSerializationQueue = dispatch_queue_create([serializationQueueDescription UTF8String], NULL);
NSString *rwAudioSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw audio serialization queue", self]; NSString *rwAudioSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw audio serialization queue", self];
// Create the serialization queue to use for reading and writing the audio data. // Create the serialization queue to use for reading and writing the audio data.
self.rwAudioSerializationQueue = dispatch_queue_create([rwAudioSerializationQueueDescription UTF8String], NULL); self.rwAudioSerializationQueue = dispatch_queue_create([rwAudioSerializationQueueDescription UTF8String], NULL);
NSString *rwVideoSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw video serialization queue", self]; NSString *rwVideoSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw video serialization queue", self];
// Create the serialization queue to use for reading and writing the video data. // Create the serialization queue to use for reading and writing the video data.
self.rwVideoSerializationQueue = dispatch_queue_create([rwVideoSerializationQueueDescription UTF8String], NULL); self.rwVideoSerializationQueue = dispatch_queue_create([rwVideoSerializationQueueDescription UTF8String], NULL);
int videoWidth = 1920; int videoWidth = 1920;
int videoHeight = 1920; int videoHeight = 1920;
int desiredKeyframeInterval = 2; int desiredKeyframeInterval = 2;
@ -1004,19 +1050,19 @@ typedef enum : NSUInteger {
error:&error]; error:&error];
NSParameterAssert(videoWriter); NSParameterAssert(videoWriter);
NSDictionary* settings = @{AVVideoCodecKey:AVVideoCodecH264, NSDictionary* settings = @{AVVideoCodecKey:AVVideoCodecH264,
AVVideoCompressionPropertiesKey:@{AVVideoAverageBitRateKey:[NSNumber numberWithInt:desiredBitrate],AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31}, AVVideoCompressionPropertiesKey:@{AVVideoAverageBitRateKey:[NSNumber numberWithInt:desiredBitrate],AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31},
AVVideoWidthKey: [NSNumber numberWithInt:videoWidth], AVVideoWidthKey: [NSNumber numberWithInt:videoWidth],
AVVideoHeightKey:[NSNumber numberWithInt:videoHeight]}; AVVideoHeightKey:[NSNumber numberWithInt:videoHeight]};
AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings]; AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
NSParameterAssert(writerInput); NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]); NSParameterAssert([videoWriter canAddInput:writerInput]);
[videoWriter addInput:writerInput]; [videoWriter addInput:writerInput];
#endif #endif
} }
@ -1031,7 +1077,7 @@ typedef enum : NSUInteger {
switch ([Environment.preferences imageUploadQuality]) { switch ([Environment.preferences imageUploadQuality]) {
case TSImageQualityUncropped: case TSImageQualityUncropped:
return image; return image;
case TSImageQualityHigh: case TSImageQualityHigh:
correctedWidth = 2048; correctedWidth = 2048;
break; break;
@ -1044,7 +1090,7 @@ typedef enum : NSUInteger {
default: default:
break; break;
} }
return [self imageScaled:image toMaxSize:correctedWidth]; return [self imageScaled:image toMaxSize:correctedWidth];
} }
@ -1052,21 +1098,21 @@ typedef enum : NSUInteger {
{ {
CGFloat scaleFactor; CGFloat scaleFactor;
CGFloat aspectRatio = image.size.height / image.size.width; CGFloat aspectRatio = image.size.height / image.size.width;
if( aspectRatio > 1 ) { if( aspectRatio > 1 ) {
scaleFactor = size / image.size.width; scaleFactor = size / image.size.width;
} }
else { else {
scaleFactor = size / image.size.height; scaleFactor = size / image.size.height;
} }
CGSize newSize = CGSizeMake(image.size.width * scaleFactor, image.size.height * scaleFactor); CGSize newSize = CGSizeMake(image.size.width * scaleFactor, image.size.height * scaleFactor);
UIGraphicsBeginImageContext(newSize); UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage* updatedImage = UIGraphicsGetImageFromCurrentImageContext(); UIImage* updatedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); UIGraphicsEndImageContext();
return updatedImage; return updatedImage;
} }
@ -1122,20 +1168,20 @@ typedef enum : NSUInteger {
// and get the change-set(s) as applies to my view and mappings configuration. // and get the change-set(s) as applies to my view and mappings configuration.
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction]; NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
NSArray *messageRowChanges = nil; NSArray *messageRowChanges = nil;
[[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] getSectionChanges:nil [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] getSectionChanges:nil
rowChanges:&messageRowChanges rowChanges:&messageRowChanges
forNotifications:notifications forNotifications:notifications
withMappings:self.messageMappings]; withMappings:self.messageMappings];
__block BOOL scrollToBottom = NO; __block BOOL scrollToBottom = NO;
if (!messageRowChanges) { if (!messageRowChanges) {
return; return;
} }
[self.collectionView performBatchUpdates:^{ [self.collectionView performBatchUpdates:^{
for (YapDatabaseViewRowChange *rowChange in messageRowChanges) for (YapDatabaseViewRowChange *rowChange in messageRowChanges)
{ {
switch (rowChange.type) switch (rowChange.type)
@ -1164,16 +1210,16 @@ typedef enum : NSUInteger {
case YapDatabaseViewChangeUpdate : case YapDatabaseViewChangeUpdate :
{ {
NSMutableArray *rowsToUpdate = [@[rowChange.indexPath] mutableCopy]; NSMutableArray *rowsToUpdate = [@[rowChange.indexPath] mutableCopy];
if (_lastDeliveredMessageIndexPath) { if (_lastDeliveredMessageIndexPath) {
[rowsToUpdate addObject:_lastDeliveredMessageIndexPath]; [rowsToUpdate addObject:_lastDeliveredMessageIndexPath];
} }
for (NSIndexPath* indexPath in rowsToUpdate) { for (NSIndexPath* indexPath in rowsToUpdate) {
TSInteraction * interaction = [self interactionAtIndexPath:indexPath]; TSInteraction * interaction = [self interactionAtIndexPath:indexPath];
[[TSAdapterCacheManager sharedManager] cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId]; [[TSAdapterCacheManager sharedManager] cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId];
} }
[self.collectionView reloadItemsAtIndexPaths:rowsToUpdate]; [self.collectionView reloadItemsAtIndexPaths:rowsToUpdate];
scrollToBottom = YES; scrollToBottom = YES;
break; break;
@ -1208,24 +1254,24 @@ typedef enum : NSUInteger {
NSUInteger row = (NSUInteger)indexPath.row; NSUInteger row = (NSUInteger)indexPath.row;
NSUInteger section = (NSUInteger)indexPath.section; NSUInteger section = (NSUInteger)indexPath.section;
NSUInteger numberOfItemsInSection = [self.messageMappings numberOfItemsInSection:section]; NSUInteger numberOfItemsInSection = [self.messageMappings numberOfItemsInSection:section];
NSAssert(row < numberOfItemsInSection, @"Cannot fetch message because row %d is >= numberOfItemsInSection %d", (int)row, (int)numberOfItemsInSection); NSAssert(row < numberOfItemsInSection, @"Cannot fetch message because row %d is >= numberOfItemsInSection %d", (int)row, (int)numberOfItemsInSection);
message = [viewTransaction objectAtRow:row inSection:section withMappings:self.messageMappings]; message = [viewTransaction objectAtRow:row inSection:section withMappings:self.messageMappings];
NSParameterAssert(message != nil); NSParameterAssert(message != nil);
}]; }];
return message; return message;
} }
- (TSMessageAdapter*)messageAtIndexPath:(NSIndexPath *)indexPath { - (TSMessageAdapter*)messageAtIndexPath:(NSIndexPath *)indexPath {
TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
TSAdapterCacheManager * manager = [TSAdapterCacheManager sharedManager]; TSAdapterCacheManager * manager = [TSAdapterCacheManager sharedManager];
if (![manager containsCacheEntryForInteractionId:interaction.uniqueId]) { if (![manager containsCacheEntryForInteractionId:interaction.uniqueId]) {
[manager cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId]; [manager cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId];
} }
return [manager adapterForInteractionId:interaction.uniqueId]; return [manager adapterForInteractionId:interaction.uniqueId];
} }
@ -1233,15 +1279,80 @@ typedef enum : NSUInteger {
#pragma mark group action view #pragma mark group action view
#pragma mark - Audio
-(void)recordAudio {
// Define the recorder setting
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
[NSString stringWithFormat:@"%lld.m4a",[NSDate ows_millisecondTimeStamp]],
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
_audioRecorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
_audioRecorder.delegate = self;
_audioRecorder.meteringEnabled = YES;
[_audioRecorder prepareToRecord];
}
- (void)audioPlayerUpdated:(NSTimer*)timer {
NSDictionary *dict = [timer userInfo];
TSVideoAttachmentAdapter *messageMedia = dict[@"adapter"];
double current = [_audioPlayer currentTime]/[_audioPlayer duration];
[messageMedia setAudioProgressFromFloat:(float)current];
NSTimeInterval duration = ([_audioPlayer duration] - [_audioPlayer currentTime]);
[messageMedia setDurationOfAudio:duration];
}
- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
// stop audio polling
[_audioPlayerPoller invalidate];
// reset all audio bars to 0
JSQMessagesCollectionView *collectionView = self.collectionView;
NSInteger num_bubbles = [self collectionView:collectionView numberOfItemsInSection:0];
for (NSInteger i=0; i<num_bubbles; i++) {
NSIndexPath *index_path = [NSIndexPath indexPathForRow:i inSection:0];
TSMessageAdapter *msgAdapter = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:index_path];
if (msgAdapter.messageType == TSIncomingMessageAdapter && msgAdapter.isMediaMessage) {
TSVideoAttachmentAdapter* msgMedia = (TSVideoAttachmentAdapter*)[msgAdapter media];
if ([msgMedia isAudio]) {
[msgMedia setAudioProgressFromFloat:0];
[msgMedia setAudioIconToPlay];
[msgMedia removeDurationLabel];
}
}
}
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder
successfully:(BOOL)flag {
if(flag) {
[self sendMessageAttachment:[NSData dataWithContentsOfURL:recorder.url] ofType:@"audio/m4a"];
}
}
#pragma mark Accessory View #pragma mark Accessory View
-(void)didPressAccessoryButton:(UIButton *)sender -(void)didPressAccessoryButton:(UIButton *)sender
{ {
[self.inputToolbar.contentView.textView resignFirstResponder]; [self.inputToolbar.contentView.textView resignFirstResponder];
UIView *presenter = self.parentViewController.view; UIView *presenter = self.parentViewController.view;
[DJWActionSheet showInView:presenter [DJWActionSheet showInView:presenter
withTitle:nil withTitle:nil
cancelButtonTitle:@"Cancel" cancelButtonTitle:@"Cancel"
@ -1274,39 +1385,6 @@ typedef enum : NSUInteger {
}]; }];
} }
-(void)recordAudio {
// Define the recorder setting
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
[NSString stringWithFormat:@"%lld.m4a",[NSDate ows_millisecondTimeStamp]],
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
_audioRecorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
_audioRecorder.delegate = self;
_audioRecorder.meteringEnabled = YES;
[_audioRecorder prepareToRecord];
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder
successfully:(BOOL)flag {
if(flag) {
[self sendMessageAttachment:[NSData dataWithContentsOfURL:recorder.url] ofType:@"audio/m4a"];
}
}
- (void)markAllMessagesAsRead { - (void)markAllMessagesAsRead {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSUnreadDatabaseViewExtensionName]; YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSUnreadDatabaseViewExtensionName];
@ -1326,7 +1404,7 @@ typedef enum : NSUInteger {
if (action == @selector(delete:)) { if (action == @selector(delete:)) {
return YES; return YES;
} }
return [super collectionView:collectionView canPerformAction:action forItemAtIndexPath:indexPath withSender:sender]; return [super collectionView:collectionView canPerformAction:action forItemAtIndexPath:indexPath withSender:sender];
} }
@ -1376,7 +1454,7 @@ typedef enum : NSUInteger {
else { else {
[[TSMessagesManager sharedManager] sendMessage:message inThread:gThread]; [[TSMessagesManager sharedManager] sendMessage:message inThread:gThread];
} }
self.thread = gThread; self.thread = gThread;
}]; }];
} }

@ -48,6 +48,7 @@
- (UIView *)mediaView - (UIView *)mediaView
{ {
NSLog(@"attachment adapter");
if (self.image == nil) { if (self.image == nil) {
return nil; return nil;
} }

@ -14,13 +14,18 @@
@property NSString *attachmentId; @property NSString *attachmentId;
@property (nonatomic,strong) NSString* contentType; @property (nonatomic,strong) NSString* contentType;
@property (nonatomic) BOOL isAudioPlaying;
@property (nonatomic) BOOL isPaused;
- (instancetype)initWithAttachment:(TSAttachmentStream*)attachment; - (instancetype)initWithAttachment:(TSAttachmentStream*)attachment;
- (BOOL)isImage; - (BOOL)isImage;
- (BOOL)isAudio; - (BOOL)isAudio;
- (BOOL)isVideo; - (BOOL)isVideo;
- (void)setAudioProgressFromFloat:(float)progress;
- (void)setAudioIconToPlay;
- (void)setAudioIconToPause;
- (void)setDurationOfAudio:(NSTimeInterval)duration;
- (void)removeDurationLabel;
@end @end

@ -16,31 +16,34 @@
#import "TSNetworkManager.h" #import "TSNetworkManager.h"
#import "UIColor+OWS.h" #import "UIColor+OWS.h"
#define AUDIO_BAR_HEIGHT 30;
@interface TSVideoAttachmentAdapter () @interface TSVideoAttachmentAdapter ()
@property UIImage *image; @property UIImage *image;
@property (strong, nonatomic) UIImageView *cachedImageView; @property (strong, nonatomic) UIImageView *cachedImageView;
@property (strong, nonatomic) UIImageView *playButton; @property (strong, nonatomic) UIImageView *playButton;
@property (strong, nonatomic) CALayer *maskLayer; @property (strong, nonatomic) CALayer *maskLayer;
@property (strong, nonatomic) FFCircularProgressView *progressView; @property (strong, nonatomic) FFCircularProgressView *progressView;
@property (strong, nonatomic) TSAttachmentStream *attachment; @property (strong, nonatomic) TSAttachmentStream *attachment;
@property (strong, nonatomic) NSString *videoURL; @property (strong, nonatomic) UIProgressView *audioProgress;
@property (strong, nonatomic) UIImageView *playPauseButton;
@property (nonatomic) UILabel *durationLabel;
@end @end
@implementation TSVideoAttachmentAdapter @implementation TSVideoAttachmentAdapter
- (instancetype)initWithAttachment:(TSAttachmentStream*)attachment{ - (instancetype)initWithAttachment:(TSAttachmentStream*)attachment{
self = [super initWithFileURL:[attachment videoURL] isReadyToPlay:YES]; self = [super initWithFileURL:[attachment mediaURL] isReadyToPlay:YES];
if (self) { if (self) {;
NSLog(@"attach: %@", attachment);
_image = attachment.image; _image = attachment.image;
_cachedImageView = nil; _cachedImageView = nil;
_attachmentId = attachment.uniqueId; _attachmentId = attachment.uniqueId;
_contentType = attachment.contentType; _contentType = attachment.contentType;
_attachment = attachment; _attachment = attachment;
} }
return self; return self;
} }
@ -58,53 +61,121 @@
return [_contentType containsString:@"video/"]; return [_contentType containsString:@"video/"];
} }
-(void) setAudioProgressFromFloat:(float)progress {
[_audioProgress setProgress:progress];
}
-(void) setAudioIconToPause {
[_playPauseButton removeFromSuperview];
_playPauseButton = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pause_icon"]];
_playPauseButton.frame = CGRectMake(10, 8, 10, 14);
[_audioProgress addSubview:_playPauseButton];
}
-(void) setAudioIconToPlay {
[_playPauseButton removeFromSuperview];
_playPauseButton = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"play_icon"]];
_playPauseButton.frame = CGRectMake(10, 8, 10, 14);
[_audioProgress addSubview:_playPauseButton];
}
-(void) setDurationOfAudio:(NSTimeInterval)duration {
[_durationLabel removeFromSuperview];
double dur = duration;
int minutes = (int) (dur/60);
int seconds = (int) (dur - minutes*60);
NSString *minutes_str = [NSString stringWithFormat:@"%01d", minutes];
NSString *seconds_str = [NSString stringWithFormat:@"%02d", seconds];
NSString *label_text = [NSString stringWithFormat:@"%@:%@", minutes_str, seconds_str];
CGSize size = [self mediaViewDisplaySize];
_durationLabel = [[UILabel alloc] initWithFrame:CGRectMake(size.width - 40, 0, 50, 30)];
_durationLabel.text = label_text;
_durationLabel.textColor = [UIColor whiteColor];
[_audioProgress addSubview:_durationLabel];
}
-(void) removeDurationLabel {
[_durationLabel removeFromSuperview];
}
#pragma mark - JSQMessageMediaData protocol #pragma mark - JSQMessageMediaData protocol
- (UIView *)mediaView - (UIView *)mediaView
{ {
if (self.image == nil) { CGSize size = [self mediaViewDisplaySize];
return nil; if ([self isVideo]) {
} if (self.cachedImageView == nil) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.image];
if (self.cachedImageView == nil) { imageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
CGSize size = [self mediaViewDisplaySize]; imageView.contentMode = UIViewContentModeScaleAspectFill;
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.image]; imageView.clipsToBounds = YES;
imageView.frame = CGRectMake(0.0f, 0.0f, size.width, size.height); [JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing];
imageView.contentMode = UIViewContentModeScaleAspectFill; self.cachedImageView = imageView;
imageView.clipsToBounds = YES; UIImage *img = [UIImage imageNamed:@"play_button"];
[JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView isOutgoing:self.appliesMediaViewMaskAsOutgoing]; _playButton = [[UIImageView alloc] initWithImage:img];
self.cachedImageView = imageView; _playButton.frame = CGRectMake((size.width/2)-18, (size.height/2)-18, 37, 37);
UIImage *img = [UIImage imageNamed:@"play_button"]; [self.cachedImageView addSubview:_playButton];
_playButton = [[UIImageView alloc] initWithImage:img]; _playButton.hidden = YES;
_playButton.frame = CGRectMake((size.width/2)-18, (size.height/2)-18, 37, 37); _maskLayer = [CALayer layer];
[self.cachedImageView addSubview:_playButton]; [_maskLayer setBackgroundColor:[UIColor blackColor].CGColor];
_playButton.hidden = YES; [_maskLayer setOpacity:0.4f];
_maskLayer = [CALayer layer]; [_maskLayer setFrame:self.cachedImageView.frame];
[_maskLayer setBackgroundColor:[UIColor ows_blackColor].CGColor]; [self.cachedImageView.layer addSublayer:_maskLayer];
[_maskLayer setOpacity:0.4f]; _progressView = [[FFCircularProgressView alloc] initWithFrame:CGRectMake((size.width/2)-18, (size.height/2)-18, 37, 37)];
[_maskLayer setFrame:self.cachedImageView.frame]; [_cachedImageView addSubview:_progressView];
[self.cachedImageView.layer addSublayer:_maskLayer]; if (_attachment.isDownloaded) {
_progressView = [[FFCircularProgressView alloc] initWithFrame:CGRectMake((size.width/2)-18, (size.height/2)-18, 37, 37)]; _playButton.hidden = NO;
[_cachedImageView addSubview:_progressView]; _maskLayer.hidden = YES;
if (_attachment.isDownloaded) { _progressView.hidden = YES;
_playButton.hidden = NO; }
_maskLayer.hidden = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(attachmentUploadProgress:) name:@"attachmentUploadProgress" object:nil];
_progressView.hidden = YES;
} }
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(attachmentUploadProgress:) name:@"attachmentUploadProgress" object:nil]; } else if ([self isAudio]) {
UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, 30)];
backgroundImage.backgroundColor = [UIColor colorWithRed:189/255.0f green:190/255.0f blue:194/255.0f alpha:1.0f];
_audioProgress = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, size.width, 4)];
_playPauseButton = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"play_icon"]];
_playPauseButton.frame = CGRectMake(10, 8, 10, 14);
[_audioProgress addSubview:_playPauseButton];
return _audioProgress;
} }
return self.cachedImageView; return self.cachedImageView;
} }
- (CGSize)mediaViewDisplaySize
{
CGSize mediaDisplaySize;
if ([self isVideo]) {
mediaDisplaySize = [super mediaViewDisplaySize];
} else if ([self isAudio]) {
CGSize size = [super mediaViewDisplaySize];
size.height = AUDIO_BAR_HEIGHT;
mediaDisplaySize = size;
}
return mediaDisplaySize;
}
- (UIView *)mediaPlaceholderView
{
return [self mediaView];
}
- (NSUInteger)hash
{
return [super hash];
}
- (void)attachmentUploadProgress:(NSNotification*)notification { - (void)attachmentUploadProgress:(NSNotification*)notification {
NSDictionary *userinfo = [notification userInfo]; NSDictionary *userinfo = [notification userInfo];
double progress = [[userinfo objectForKey:@"progress"] doubleValue]; double progress = [[userinfo objectForKey:@"progress"] doubleValue];
NSString *attachmentID = [userinfo objectForKey:@"attachmentID"]; NSString *attachmentID = [userinfo objectForKey:@"attachmentID"];
if ([_attachmentId isEqualToString:attachmentID]) { if ([_attachmentId isEqualToString:attachmentID]) {
NSLog(@"is downloaded: %d", _attachment.isDownloaded); NSLog(@"is downloaded: %d", _attachment.isDownloaded);
[_progressView setProgress:progress]; [_progressView setProgress: (float)progress];
if (progress >= 1) { if (progress >= 1) {
_maskLayer.hidden = YES; _maskLayer.hidden = YES;
_progressView.hidden = YES; _progressView.hidden = YES;

Loading…
Cancel
Save