From b494b71dbc19cb139a105d3cfd3a17cc11192bfb Mon Sep 17 00:00:00 2001 From: Joyce Yan Date: Wed, 21 Jan 2015 18:08:12 -1000 Subject: [PATCH] Audio farts. slight change modified pbxproj to clean up resources reset developmentteam in pbxproj back to what it was before deleted one line --- Signal.xcodeproj/project.pbxproj | 16 + Signal/Images/pause_icon.png | Bin 0 -> 941 bytes Signal/Images/pause_icon@2x.png | Bin 0 -> 955 bytes Signal/Images/play_icon.png | Bin 0 -> 1073 bytes Signal/Images/play_icon@2x.png | Bin 0 -> 1224 bytes .../Attachements/TSAttachmentStream.h | 2 +- .../Attachements/TSAttachmentStream.m | 2 +- .../Messages/TSMessagesManager+attachments.m | 2 +- .../view controllers/MessagesViewController.m | 418 +++++++++++------- .../view controllers/TSAttachmentAdapter.m | 1 + .../TSVideoAttachmentAdapter.h | 9 +- .../TSVideoAttachmentAdapter.m | 149 +++++-- 12 files changed, 385 insertions(+), 214 deletions(-) create mode 100644 Signal/Images/pause_icon.png create mode 100644 Signal/Images/pause_icon@2x.png create mode 100644 Signal/Images/play_icon.png create mode 100644 Signal/Images/play_icon@2x.png diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index bce540c8c..62513eae0 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -287,6 +287,10 @@ AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; }; 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 */; }; + 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 */; }; B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C16641988999D00E97A6C /* VersionMigrations.m */; }; 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 = ""; }; AD41D7B31A6F6F0600241130 /* play_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play_button.png; sourceTree = ""; }; AD41D7B41A6F6F0600241130 /* play_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play_button@2x.png"; sourceTree = ""; }; + B10C9B5B1A7049EC00ECA2BF /* pause_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pause_icon.png; sourceTree = ""; }; + B10C9B5C1A7049EC00ECA2BF /* pause_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pause_icon@2x.png"; sourceTree = ""; }; + B10C9B5D1A7049EC00ECA2BF /* play_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play_icon.png; sourceTree = ""; }; + B10C9B5E1A7049EC00ECA2BF /* play_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play_icon@2x.png"; sourceTree = ""; }; B6019E951A2492AB001118DF /* NSDate+millisecondTimeStamp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+millisecondTimeStamp.h"; sourceTree = ""; }; B6019E961A2492AB001118DF /* NSDate+millisecondTimeStamp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+millisecondTimeStamp.mm"; sourceTree = ""; }; B60C16631988999D00E97A6C /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionMigrations.h; sourceTree = ""; }; @@ -2128,6 +2136,10 @@ B633C4FD1A1D190B0059AC12 /* Images */ = { isa = PBXGroup; children = ( + B10C9B5B1A7049EC00ECA2BF /* pause_icon.png */, + B10C9B5C1A7049EC00ECA2BF /* pause_icon@2x.png */, + B10C9B5D1A7049EC00ECA2BF /* play_icon.png */, + B10C9B5E1A7049EC00ECA2BF /* play_icon@2x.png */, AD41D7B31A6F6F0600241130 /* play_button.png */, AD41D7B41A6F6F0600241130 /* play_button@2x.png */, FC3BD9851A30A62D005B96BB /* twitter@2x.png */, @@ -2917,6 +2929,7 @@ FC5CDF391A3393DD00B47253 /* error_white@2x.png in Resources */, B633C5851A1D190B0059AC12 /* blue-archive@2x.png in Resources */, B633C5D21A1D190B0059AC12 /* savephoto@2x.png in Resources */, + B10C9B611A7049EC00ECA2BF /* play_icon.png in Resources */, B633C5921A1D190B0059AC12 /* contacts_tab@2x.png in Resources */, B6416FB8199A0478003C5699 /* Localizable.strings in Resources */, FCB626A51A3B00FA00FDB504 /* info@2x.png in Resources */, @@ -2945,12 +2958,14 @@ FCA52B071A2BBAE400CCADFA /* call_tab@2x.png in Resources */, B633C58D1A1D190B0059AC12 /* contact_default_feed.png in Resources */, FC3BD97C1A2CD385005B96BB /* signal_dotted@2x.png in Resources */, + B10C9B621A7049EC00ECA2BF /* play_icon@2x.png in Resources */, B633C5CD1A1D190B0059AC12 /* photo@2x.png in Resources */, A507A3B01A6C60E300BEED0D /* ContactTableViewCell.xib in Resources */, B633C5861A1D190B0059AC12 /* call@2x.png in Resources */, B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */, E1370BE418A0686C00826894 /* outring.mp3 in Resources */, B633C5841A1D190B0059AC12 /* backspace@2x.png in Resources */, + B10C9B601A7049EC00ECA2BF /* pause_icon@2x.png in Resources */, B6C6AE551A305ED1006BAF8F /* redphone.cer in Resources */, B633C5B71A1D190B0059AC12 /* logo_intro@2x.png in Resources */, E1370BE518A0686C00826894 /* r.caf in Resources */, @@ -2962,6 +2977,7 @@ B633C58F1A1D190B0059AC12 /* contacts@2x.png in Resources */, E1370BE618A0686C00826894 /* sonarping.mp3 in Resources */, B633C5961A1D190B0059AC12 /* DefaultContactImage.png in Resources */, + B10C9B5F1A7049EC00ECA2BF /* pause_icon.png in Resources */, E148751218A06AFD002CC4F3 /* HelveticaNeueLTStd-Bd.otf in Resources */, FCA52AE61A2B676C00CCADFA /* call_canceled@2x.png in Resources */, FC3BD9861A30A62D005B96BB /* twitter@2x.png in Resources */, diff --git a/Signal/Images/pause_icon.png b/Signal/Images/pause_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7a103ba371fcf8a082d335419e411a2566b642e7 GIT binary patch literal 941 zcmaJ=&x_MQ6pj=Yt*m%ZK@l9Xdr&Yxra#gqHZHMgc7vvrwqS2MO{Q(=CKHpXO?wnP zcyRT9@F;lj>cO-B!u}K97Qu^?ZqxN(4MXP5<9*+IZ{9cWI_<;V;+-PLal7`B*=2iX zU%R}+{6t#vMT()kIcktRv=`COcrMG}uCsH$qlQ7Q>6LP!=N zMX3-bdpU!N6F2rF>XQ&;jA%$^ROeZx=Pd-$hBi#r*TgPNN>L<1QO;V*10Co8p+T^T zPG}cj)ca53q`!!;)Wr#z#V#A%XfI0@Y0VfTO5#2t$N4RGCWMk?LL$)YDd4_?TtCbl z4^{}r(d;mxD0H!H>OA8Rec#ipx>0JGma5h*2w|&Y)D5+6w4iL%)UsM@=2(-svjB%Q z$9fl72H1kl#1KR*vx#H>HTJBS1Yp&)=5Md1wv}&<^|sei--?x3F;X_#zeb(An0_*I zBV2aaNFRqx?=chhA@}tvdldI<)99zC!(ShYX9ZZe@d!MX;q@!l&6B%txl23T>F@nB T;p2;w>;c)Ww)y4B%Qt@j0%sm2 literal 0 HcmV?d00001 diff --git a/Signal/Images/pause_icon@2x.png b/Signal/Images/pause_icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d464613470af6b766b0f73af958c79884c76519c GIT binary patch literal 955 zcmaJ=y^hmB5ccT~grW;H6#Nw{hXN%0o5YE&n8U=$oh2NFBoZlaV{Z~GvDasBh!asD zI^KYjcmOKWA|V7VJq4oS5qJR#*7<|tf@OPWNArF2&CcxWX5%=Uxs_oUCTpFTExKN( z-|Z`x>Ho#g#do^gB(*MS<35?f2r-6>dk9!Q9H170?(FOH+@LZjJR=NwUzfTHkHp{OX*10ai% zEQs_~IH{l&6-_RI^~2I^k=xf=W__KD?sRrYNT>g zATZ&AIJaRiQS3xsNIV>Xlo9sugy<|)x+=jBx3odLJ|=o#LIOiU;>EP2O`vW6Kh*cP z(J^VEzj`kujytmu2`v=kN#xMR^>b;eP^(4=5*&3f9&b*uIm86VLmYx?TLJfM=y*Zu zxW7c$wq^w}fq{c8Q)ej$?|H6f=GC&OlohpHmn5lHFv^BnHfoY+l+?Uhs&23*b|yXw z$Oh|DY`tvAHM71On+}5?(#$4`yywWRN7x6;qBU=~mcni=E3A8gmUSJ)omhd25z^NF z)9Q_j&QEG?2bXTPqmKeQ?-3pBPle0@y%d~f8lB`v@AtKX!w-A8t7mWLZ*IIhtY_~O k!*5@n?jNrVI0lbi?lI=#l6<~6FQwPXsx{2_k56Cy0re>(-2eap literal 0 HcmV?d00001 diff --git a/Signal/Images/play_icon.png b/Signal/Images/play_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..95537e44697dc14c37e1d321f68f6090707f409e GIT binary patch literal 1073 zcmaJ=!B5jr7%y9f1Vsn|qb9~jQ3JuP?Z&#bFxXf@7A;xE5_d3a*FHuA?d#fy8+eeI zn9PIv4;VafGA2fjDv63qh!GQy#*>oh&1gJv!&hM7!P&g@eecWn`+eW{zTdl>p19D` ze6pFMsFu{Ylp(uoA8l$R|6|Mdo{;SX9?juNG=)ow4XK2N@(`p9r2sQf(dLWq;2=eL z&*<44&dHZV6&V4=jR}+ui=ZiLaJXzK>I}pn4-2{(qkq19MFU-n(U-$AD_co8t&cC* zaB^WHt1ir_f<_Myfx)s!2n>i7P&Q^wM=Zza9bS>xuA8C3P6(cf(Yr;QyT%|vN40ee>&OHyqmoB+I7X97cUv&5eOlAm zyC!mBOj)rQF2K4i)dFSt|DlGlAMM}_JgE1d#7=hJf=mWFXwFv2;HJ9WRF;^up@NZ} zMQFBmi|J{Eku!}fkeuW}kF2P=={kCM5V9<$Ob08b3R6;yCL94>*F-5KL|Hx>6ry7s z$Bp(Uq6s0I80FYRL|6H_V+Po~;1FfglRhD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb;hUJ8nFkWk z1ncniwerj>E=kNwPW5!LRRWr!mzkMj4ik4Abk9pIn-onpXnTn}X2mhEp#nG2|8iZFWg5$}CGwaVyHtRRDY1DigO`oN<~5 z)tiFbEiO3q>H{644~kl(sD=pv(+`LVPq;u1Jn5(A0n>XCFkx5mY?;Hrz-Z;^;uunK zYt7}2-iIATj(-ep>L^*+Jb8Eb?AE5)ORPE`UFiGE-xB61$lm^o-9zxAqqty6NvYsM z?^ZF9zsfQ$>?=Dg=G=e5>+XBzXlM`B|e=jQc%8tFZKU0BURWQ~m_yc$B6cyI? zslNnO5Ab{oboBe#vg-4%e7k}+&-r|hjk;F7EXxy+y;XTUYZ_naDf8nSx|w};mqc88 zx6}3Db9uF;9o%mcY*ro)_`S4~Gqb%cD`R2KeI6Fpc7s;iCxxBjCr^~w6}CnKDK~*d z&o}YM7WK2*@GLqUtn 0) { NSIndexPath * lastCellIndexPath = [NSIndexPath indexPathForRow:numberOfMessages-1 inSection:0]; [self.collectionView scrollToItemAtIndexPath:lastCellIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; @@ -218,7 +221,7 @@ typedef enum : NSUInteger { } } } - + [self cancelReadTimer]; } @@ -230,11 +233,11 @@ typedef enum : NSUInteger { - (IBAction)didSelectShow:(id)sender { - + UIBarButtonItem *spaceEdge = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; spaceEdge.width = 40; - + UIBarButtonItem *spaceMiddleIcons = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; spaceMiddleIcons.width = 61; @@ -242,12 +245,12 @@ typedef enum : NSUInteger { if (!isGroupConversation) { - + //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)]; - - + + 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)]; self.navController.dropDownToolbar.items = @[spaceEdge, callButton,spaceMiddleWords, contactSecurity, spaceEdge]; @@ -259,9 +262,9 @@ typedef enum : NSUInteger { else { 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 *showGroupMembersButton = [[UIBarButtonItem alloc] initWithTitle:@"Members" style:UIBarButtonItemStylePlain target:self action:@selector(showGroupMembers)]; - + self.navController.dropDownToolbar.items =@[spaceEdge, groupUpdateButton, spaceMiddleWords, groupLeaveButton, spaceMiddleWords, showGroupMembersButton, spaceEdge]; } for(UIButton *button in self.navController.dropDownToolbar.items) { @@ -285,7 +288,7 @@ typedef enum : NSUInteger { } -(void)initializeToolbars { - + self.navController = (APNavigationController*)self.navigationController; //self.navController.activeBarButtonTitle = @"Hide"; [self setNavigationTitle]; @@ -295,23 +298,22 @@ typedef enum : NSUInteger { -(void)initializeBubbles { JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init]; - + self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]]; self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]]; self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessageFailedBubbleImageWithColor:[UIColor ows_fadedBlueColor]]; - } -(void)initializeCollectionViewLayout { if (self.collectionView){ [self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_regularFontWithSize:15.0f]]; - + self.collectionView.showsVerticalScrollIndicator = NO; self.collectionView.showsHorizontalScrollIndicator = NO; - + [self updateLoadEarlierVisible]; - + self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero; self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero; } @@ -350,7 +352,7 @@ typedef enum : NSUInteger { if ([self isRedPhoneReachable]) { PhoneNumber *number = [self phoneNumberForThread]; Contact *contact = [[Environment.getCurrent contactsManager] latestContactForPhoneNumber:number]; - + [Environment.phoneManager initiateOutgoingCallToContact:contact atRemoteNumber:number]; } else { DDLogWarn(@"Tried to initiate a call but contact has no RedPhone identifier"); @@ -367,9 +369,9 @@ typedef enum : NSUInteger { { if (text.length > 0) { [JSQSystemSoundPlayer jsq_playMessageSentSound]; - + TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:self.thread messageBody:text attachments:nil]; - + [[TSMessagesManager sharedManager] sendMessage:message inThread:self.thread]; [self finishSendingMessage]; } @@ -386,14 +388,14 @@ typedef enum : NSUInteger { - (id)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath { id message = [self messageAtIndexPath:indexPath]; - + if ([message.senderId isEqualToString:self.senderId]) { if (message.messageState == TSOutgoingMessageStateUnsent || message.messageState == TSOutgoingMessageStateAttemptingOut) { return self.outgoingMessageFailedImageData; } return self.outgoingBubbleImageData; } - + return self.incomingBubbleImageData; } @@ -407,7 +409,7 @@ typedef enum : NSUInteger { - (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { TSMessageAdapter * msg = [self messageAtIndexPath:indexPath]; - + switch (msg.messageType) { case TSIncomingMessageAdapter: return [self loadIncomingMessageCellForMessage:msg atIndexPath:indexPath]; @@ -419,7 +421,7 @@ typedef enum : NSUInteger { return [self loadInfoMessageCellForMessage:msg atIndexPath:indexPath]; case TSErrorMessageAdapter: return [self loadErrorMessageCellForMessage:msg atIndexPath:indexPath]; - + default: NSLog(@"Something went wrong"); return nil; @@ -437,7 +439,7 @@ typedef enum : NSUInteger { cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; } - + return cell; } @@ -451,7 +453,7 @@ typedef enum : NSUInteger { cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; } - + return cell; } @@ -481,7 +483,7 @@ typedef enum : NSUInteger { if ([self showDateAtIndexPath:indexPath]) { return kJSQMessagesCollectionViewCellLabelHeightDefault; } - + return 0.0f; } @@ -493,9 +495,9 @@ typedef enum : NSUInteger { } else { TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; - + TSMessageAdapter *previousMessage = [self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row-1 inSection:indexPath.section]]; - + NSTimeInterval timeDifference = [currentMessage.date timeIntervalSinceDate:previousMessage.date]; if (timeDifference > kTSMessageSentDateShowTimeInterval) { showDate = YES; @@ -506,19 +508,19 @@ typedef enum : NSUInteger { -(NSAttributedString*)collectionView:(JSQMessagesCollectionView *)collectionView attributedTextForCellTopLabelAtIndexPath:(NSIndexPath *)indexPath { - + if ([self showDateAtIndexPath:indexPath]) { TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; - + return [[JSQMessagesTimestampFormatter sharedFormatter] attributedTimestampForDate:currentMessage.date]; } - + return nil; } -(BOOL)shouldShowMessageStatusAtIndexPath:(NSIndexPath*)indexPath { - + TSMessageAdapter *currentMessage = [self messageAtIndexPath:indexPath]; if([self.thread isKindOfClass:[TSGroupThread class]]) { return currentMessage.messageType == TSIncomingMessageAdapter; @@ -527,11 +529,11 @@ typedef enum : NSUInteger { if (indexPath.item == [self.collectionView numberOfItemsInSection:indexPath.section]-1) { return [self isMessageOutgoingAndDelivered:currentMessage]; } - + if (![self isMessageOutgoingAndDelivered:currentMessage]) { return NO; } - + TSMessageAdapter *nextMessage = [self nextOutgoingMessage:indexPath]; return ![self isMessageOutgoingAndDelivered:nextMessage]; } @@ -541,12 +543,12 @@ typedef enum : NSUInteger { { TSMessageAdapter * nextMessage = [self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]]; int i = 1; - + while (indexPath.item+i < [self.collectionView numberOfItemsInSection:indexPath.section]-1 && ![self isMessageOutgoingAndDelivered:nextMessage]) { i++; nextMessage = [self messageAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row+i inSection:indexPath.section]]; } - + return nextMessage; } @@ -566,7 +568,7 @@ typedef enum : NSUInteger { name = name ? name : msg.senderId; NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:name]; [attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]]; - + return (NSAttributedString*)attrStr; } else { @@ -575,7 +577,7 @@ typedef enum : NSUInteger { textAttachment.bounds = CGRectMake(0, 0, 11.0f, 10.0f); NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:@"Delivered"]; [attrStr appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]]; - + return (NSAttributedString*)attrStr; } } @@ -594,7 +596,7 @@ typedef enum : NSUInteger { else if (msg.messageType == TSOutgoingMessageAdapter) { return 16.0f; } - + return 0.0f; } @@ -605,20 +607,20 @@ typedef enum : NSUInteger { { TSMessageAdapter *messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath]; TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; - + switch (messageItem.messageType) { case TSOutgoingMessageAdapter: if (messageItem.messageState == TSOutgoingMessageStateUnsent) { [self handleUnsentMessageTap:(TSOutgoingMessage*)interaction]; } case TSIncomingMessageAdapter:{ - + BOOL isMediaMessage = [messageItem isMediaMessage]; - + if (isMediaMessage) { if([[messageItem media] isKindOfClass:[TSAttachmentAdapter class]]) { TSAttachmentAdapter* messageMedia = (TSAttachmentAdapter*)[messageItem media]; - + if ([messageMedia isImage]) { tappedImage = ((UIImageView*)[messageMedia mediaView]).image; CGRect convertedRect = [self.collectionView convertRect:[collectionView cellForItemAtIndexPath:indexPath].frame toView:nil]; @@ -626,11 +628,11 @@ typedef enum : NSUInteger { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction]; }]; - + if ([attachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachmentStream *attStream = (TSAttachmentStream*)attachment; FullImageViewController * vc = [[FullImageViewController alloc] initWithAttachment:attStream fromRect:convertedRect forInteraction:[self interactionAtIndexPath:indexPath]]; - + [self presentViewController:vc animated:YES completion:^{ [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; }]; @@ -643,39 +645,84 @@ typedef enum : NSUInteger { // fileurl disappeared should look up in db as before. will do refactor // full screen, check this setup with a .mov TSVideoAttachmentAdapter* messageMedia = (TSVideoAttachmentAdapter*)[messageItem media]; - + __block TSAttachment *attachment = nil; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { attachment = [TSAttachment fetchObjectWithUniqueID:messageMedia.attachmentId transaction:transaction]; }]; - + if ([attachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachmentStream *attStream = (TSAttachmentStream*)attachment; NSFileManager *fileManager = [NSFileManager defaultManager]; if([messageMedia isVideo]) { - if ([fileManager fileExistsAtPath:[attStream.videoURL path]]) { - _videoPlayer = [[MPMoviePlayerController alloc] initWithContentURL:attStream.videoURL]; + if ([fileManager fileExistsAtPath:[attStream.mediaURL path]]) { + _videoPlayer = [[MPMoviePlayerController alloc] initWithContentURL:attStream.mediaURL]; [_videoPlayer prepareToPlay]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object: _videoPlayer]; - + _videoPlayer.controlStyle = MPMovieControlStyleDefault; _videoPlayer.shouldAutoplay = YES; [self.view addSubview: _videoPlayer.view]; [_videoPlayer setFullscreen:YES animated:YES]; } - } - else if([messageMedia isAudio]){ - DDLogDebug(@"audio location is %@",attStream.videoURL); - NSError *error; - _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:attStream.videoURL error:&error]; - DDLogDebug(@"audio debug is %@",error); - [_audioPlayer prepareToPlay]; - [_audioPlayer play]; - + } else if([messageMedia isAudio]){ + if (messageMedia.isAudioPlaying) { + // if you had started playing an audio msg and now you're tapping it to pause + messageMedia.isAudioPlaying = NO; + [_audioPlayer pause]; + messageMedia.isPaused = YES; + [_audioPlayerPoller invalidate]; + 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= kYapDatabaseRangeLength; - + if (!canLoadFullRange) { item = numberOfMessagesToLoad; } }]; - + return item == 0 ? item : item - 1; } @@ -767,21 +813,21 @@ typedef enum : NSUInteger { { [self.collectionView.collectionViewLayout invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]]; [self.collectionView reloadData]; - + [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:offset inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; - + [self updateLoadEarlierVisible]; } -(void)updateRangeOptionsForPage:(NSUInteger)page { YapDatabaseViewRangeOptions *rangeOptions = [YapDatabaseViewRangeOptions flexibleRangeWithLength:kYapDatabaseRangeLength*(page+1) offset:0 from:YapDatabaseViewEnd]; - + rangeOptions.maxLength = kYapDatabaseRangeMaxLength; rangeOptions.minLength = kYapDatabaseRangeMinLength; - + [self.messageMappings setRangeOptions:rangeOptions forGroup:self.thread.uniqueId]; - + } #pragma mark Bubble User Actions @@ -815,7 +861,7 @@ typedef enum : NSUInteger { NSString *newKeyFingerprint = [errorMessage newIdentityKey]; 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"]; - + [self.inputToolbar.contentView.textView resignFirstResponder]; [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 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - + if ([segue.identifier isEqualToString:kFingerprintSegueIdentifier]){ FingerprintViewController *vc = [segue destinationViewController]; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { @@ -878,13 +924,13 @@ typedef enum : NSUInteger { picker.delegate = self; picker.allowsEditing = NO; picker.sourceType = UIImagePickerControllerSourceTypeCamera; - + if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) { picker.mediaTypes = @[(NSString*)kUTTypeImage,(NSString*)kUTTypeMovie]; [self presentViewController:picker animated:YES completion:NULL]; } - + } -(void)chooseFromLibrary:(kMediaTypes)mediaType @@ -892,15 +938,15 @@ typedef enum : NSUInteger { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - + if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { NSArray* pictureTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeImage, nil]; - + NSArray* videoTypeArray = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo, nil]; - + picker.mediaTypes = (mediaType == kMediaTypePicture) ? pictureTypeArray : videoTypeArray; - + [self presentViewController:picker animated:YES completion:nil]; } } @@ -926,24 +972,24 @@ typedef enum : NSUInteger { [self sendQualityAdjustedAttachment:videoURL]; } else { - + UIImage *picture_camera = [[info objectForKey:UIImagePickerControllerOriginalImage] normalizedImage]; if(picture_camera) { DDLogVerbose(@"Sending picture attachement ..."); [self sendMessageAttachment:[self qualityAdjustedAttachmentForImage:picture_camera] ofType:@"image/jpeg"]; } } - + } -(void) sendMessageAttachment:(NSData*)attachmentData ofType:(NSString*)attachmentType { 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]; [self finishSendingMessage]; - + [self dismissViewControllerAnimated:YES completion:nil]; - + } -(void)sendQualityAdjustedAttachment:(NSURL*)movieURL { @@ -952,47 +998,47 @@ typedef enum : NSUInteger { AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality]; exportSession.shouldOptimizeForNetworkUse = YES; exportSession.outputFileType = AVFileTypeMPEG4; - + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; basePath = [basePath stringByAppendingPathComponent:@"videos"]; if (![[NSFileManager defaultManager] fileExistsAtPath:basePath]) { [[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil]; } - + NSURL *compressedVideoUrl = [NSURL fileURLWithPath:basePath]; long currentTime = [[NSDate date] timeIntervalSince1970]; NSString *strImageName = [NSString stringWithFormat:@"%ld",currentTime]; compressedVideoUrl=[compressedVideoUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",strImageName]]; - + exportSession.outputURL = compressedVideoUrl; [exportSession exportAsynchronouslyWithCompletionHandler:^{ - + }]; while(exportSession.progress!=1){ } [self sendMessageAttachment:[NSData dataWithContentsOfURL:compressedVideoUrl] ofType:@"video/mp4"]; - + #if 0 return [NSData dataWithContentsOfURL:movieURL]; #endif #if 0 NSString *serializationQueueDescription = [NSString stringWithFormat:@"%@ serialization queue", self]; - + // Create the main serialization queue. self.mainSerializationQueue = dispatch_queue_create([serializationQueueDescription UTF8String], NULL); NSString *rwAudioSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw audio serialization queue", self]; - + // Create the serialization queue to use for reading and writing the audio data. self.rwAudioSerializationQueue = dispatch_queue_create([rwAudioSerializationQueueDescription UTF8String], NULL); NSString *rwVideoSerializationQueueDescription = [NSString stringWithFormat:@"%@ rw video serialization queue", self]; - + // Create the serialization queue to use for reading and writing the video data. self.rwVideoSerializationQueue = dispatch_queue_create([rwVideoSerializationQueueDescription UTF8String], NULL); - - + + int videoWidth = 1920; int videoHeight = 1920; int desiredKeyframeInterval = 2; @@ -1004,19 +1050,19 @@ typedef enum : NSUInteger { error:&error]; NSParameterAssert(videoWriter); - + NSDictionary* settings = @{AVVideoCodecKey:AVVideoCodecH264, AVVideoCompressionPropertiesKey:@{AVVideoAverageBitRateKey:[NSNumber numberWithInt:desiredBitrate],AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31}, AVVideoWidthKey: [NSNumber numberWithInt:videoWidth], AVVideoHeightKey:[NSNumber numberWithInt:videoHeight]}; - - + + AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings]; NSParameterAssert(writerInput); NSParameterAssert([videoWriter canAddInput:writerInput]); [videoWriter addInput:writerInput]; #endif - + } @@ -1031,7 +1077,7 @@ typedef enum : NSUInteger { switch ([Environment.preferences imageUploadQuality]) { case TSImageQualityUncropped: return image; - + case TSImageQualityHigh: correctedWidth = 2048; break; @@ -1044,7 +1090,7 @@ typedef enum : NSUInteger { default: break; } - + return [self imageScaled:image toMaxSize:correctedWidth]; } @@ -1052,21 +1098,21 @@ typedef enum : NSUInteger { { CGFloat scaleFactor; CGFloat aspectRatio = image.size.height / image.size.width; - + if( aspectRatio > 1 ) { scaleFactor = size / image.size.width; } else { scaleFactor = size / image.size.height; } - + CGSize newSize = CGSizeMake(image.size.width * scaleFactor, image.size.height * scaleFactor); - + UIGraphicsBeginImageContext(newSize); [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; UIImage* updatedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - + return updatedImage; } @@ -1122,20 +1168,20 @@ typedef enum : NSUInteger { // and get the change-set(s) as applies to my view and mappings configuration. NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction]; NSArray *messageRowChanges = nil; - + [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] getSectionChanges:nil rowChanges:&messageRowChanges forNotifications:notifications withMappings:self.messageMappings]; - + __block BOOL scrollToBottom = NO; - + if (!messageRowChanges) { return; } - + [self.collectionView performBatchUpdates:^{ - + for (YapDatabaseViewRowChange *rowChange in messageRowChanges) { switch (rowChange.type) @@ -1164,16 +1210,16 @@ typedef enum : NSUInteger { case YapDatabaseViewChangeUpdate : { NSMutableArray *rowsToUpdate = [@[rowChange.indexPath] mutableCopy]; - + if (_lastDeliveredMessageIndexPath) { [rowsToUpdate addObject:_lastDeliveredMessageIndexPath]; } - + for (NSIndexPath* indexPath in rowsToUpdate) { TSInteraction * interaction = [self interactionAtIndexPath:indexPath]; [[TSAdapterCacheManager sharedManager] cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId]; } - + [self.collectionView reloadItemsAtIndexPaths:rowsToUpdate]; scrollToBottom = YES; break; @@ -1208,24 +1254,24 @@ typedef enum : NSUInteger { NSUInteger row = (NSUInteger)indexPath.row; NSUInteger section = (NSUInteger)indexPath.section; NSUInteger numberOfItemsInSection = [self.messageMappings numberOfItemsInSection:section]; - + NSAssert(row < numberOfItemsInSection, @"Cannot fetch message because row %d is >= numberOfItemsInSection %d", (int)row, (int)numberOfItemsInSection); - + message = [viewTransaction objectAtRow:row inSection:section withMappings:self.messageMappings]; NSParameterAssert(message != nil); }]; - + return message; } - (TSMessageAdapter*)messageAtIndexPath:(NSIndexPath *)indexPath { TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; TSAdapterCacheManager * manager = [TSAdapterCacheManager sharedManager]; - + if (![manager containsCacheEntryForInteractionId:interaction.uniqueId]) { [manager cacheAdapter:[TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread] forInteractionId:interaction.uniqueId]; } - + return [manager adapterForInteractionId:interaction.uniqueId]; } @@ -1233,15 +1279,80 @@ typedef enum : NSUInteger { #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= 1) { _maskLayer.hidden = YES; _progressView.hidden = YES;