From 80fbc093d978d6190db1ed0eefdb78b2cdd82d44 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 28 Mar 2017 15:29:08 -0400 Subject: [PATCH 1/4] Handle oversize text messages and arbitrary attachments. // FREEBIE --- Signal.xcodeproj/project.pbxproj | 6 + .../file-black-60.imageset/Contents.json | 23 ++ .../file-icon-60@1x.png | Bin 0 -> 1773 bytes .../file-icon-60@2x.png | Bin 0 -> 2397 bytes .../file-icon-60@3x.png | Bin 0 -> 2941 bytes .../file-white-60.imageset/Contents.json | 23 ++ .../file-white-60@1x.png | Bin 0 -> 1786 bytes .../file-white-60@2x.png | Bin 0 -> 2439 bytes .../file-white-60@3x.png | Bin 0 -> 2954 bytes .../Models/OWSMessagesBubblesSizeCalculator.m | 5 +- .../TSMessageAdapaters/AttachmentUploadView.m | 3 + .../TSMessageAdapaters/TSAnimatedAdapter.h | 4 - .../TSMessageAdapaters/TSAnimatedAdapter.m | 14 -- .../TSGenericAttachmentAdapter.h | 14 ++ .../TSGenericAttachmentAdapter.m | 196 ++++++++++++++++++ .../TSMessageAdapaters/TSMessageAdapter.m | 33 ++- .../TSMessageAdapaters/TSPhotoAdapter.h | 4 - .../TSMessageAdapaters/TSPhotoAdapter.m | 14 -- .../TSVideoAttachmentAdapter.h | 1 - .../TSVideoAttachmentAdapter.m | 4 - .../DebugUITableViewController.m | 53 ++++- .../view controllers/SignalAttachment.swift | 28 +++ .../translations/en.lproj/Localizable.strings | 12 ++ 23 files changed, 388 insertions(+), 49 deletions(-) create mode 100644 Signal/Images.xcassets/file-black-60.imageset/Contents.json create mode 100644 Signal/Images.xcassets/file-black-60.imageset/file-icon-60@1x.png create mode 100644 Signal/Images.xcassets/file-black-60.imageset/file-icon-60@2x.png create mode 100644 Signal/Images.xcassets/file-black-60.imageset/file-icon-60@3x.png create mode 100644 Signal/Images.xcassets/file-white-60.imageset/Contents.json create mode 100644 Signal/Images.xcassets/file-white-60.imageset/file-white-60@1x.png create mode 100644 Signal/Images.xcassets/file-white-60.imageset/file-white-60@2x.png create mode 100644 Signal/Images.xcassets/file-white-60.imageset/file-white-60@3x.png create mode 100644 Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.h create mode 100644 Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 319303bf0..85cadd6f9 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 344F2F671E57A932000D9322 /* UIViewController+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 344F2F661E57A932000D9322 /* UIViewController+OWS.m */; }; 34535D821E256BE9008A4747 /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 34535D811E256BE9008A4747 /* UIView+OWS.m */; }; 345671011E89A5F1006EE662 /* ThreadUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 345671001E89A5F1006EE662 /* ThreadUtil.m */; }; + 3456710A1E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 345671091E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m */; }; 34802DD71E899CFB0032EA1D /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34802DD61E899CFB0032EA1D /* DebugUITableViewController.m */; }; 348A08421E6A044E0057E290 /* MessagesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348A08411E6A044E0057E290 /* MessagesViewController.xib */; }; 348A08441E6A1D2C0057E290 /* OWSMessagesToolbarContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348A08431E6A1D2C0057E290 /* OWSMessagesToolbarContentView.xib */; }; @@ -404,6 +405,8 @@ 34535D811E256BE9008A4747 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+OWS.m"; sourceTree = ""; }; 345670FF1E89A5F1006EE662 /* ThreadUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadUtil.h; sourceTree = ""; }; 345671001E89A5F1006EE662 /* ThreadUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadUtil.m; sourceTree = ""; }; + 345671081E8A9F5D006EE662 /* TSGenericAttachmentAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGenericAttachmentAdapter.h; sourceTree = ""; }; + 345671091E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGenericAttachmentAdapter.m; sourceTree = ""; }; 34802DD51E899CFB0032EA1D /* DebugUITableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUITableViewController.h; sourceTree = ""; }; 34802DD61E899CFB0032EA1D /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUITableViewController.m; sourceTree = ""; }; 348A08411E6A044E0057E290 /* MessagesViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessagesViewController.xib; sourceTree = ""; }; @@ -1428,6 +1431,8 @@ 4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */, 4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */, B6D3CBCE1C1376BE00C039DF /* TSContentAdapters.h */, + 345671081E8A9F5D006EE662 /* TSGenericAttachmentAdapter.h */, + 345671091E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m */, B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */, B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */, B6A3EB491A423B3800B2236B /* TSPhotoAdapter.h */, @@ -2156,6 +2161,7 @@ 458E38311D6682450094BD24 /* OWSQRCodeScanningViewController.m in Sources */, 451A13B11E13DED2000A50FD /* CallNotificationsAdapter.swift in Sources */, 76EB062418170B33006006FC /* PriorityQueue.m in Sources */, + 3456710A1E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m in Sources */, 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */, B6BADBE71B88D1AC0086A80D /* LockInteractionController.m in Sources */, 76EB061A18170B33006006FC /* DiscardingLog.m in Sources */, diff --git a/Signal/Images.xcassets/file-black-60.imageset/Contents.json b/Signal/Images.xcassets/file-black-60.imageset/Contents.json new file mode 100644 index 000000000..9dd859a99 --- /dev/null +++ b/Signal/Images.xcassets/file-black-60.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "file-icon-60@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "file-icon-60@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "file-icon-60@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/file-black-60.imageset/file-icon-60@1x.png b/Signal/Images.xcassets/file-black-60.imageset/file-icon-60@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..873b272875b3ef7e8a8ffc1d39bdd693936f0e26 GIT binary patch literal 1773 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8Ea{HEjtmSN`?>!lvI6;>1s;*b z3=G`DAk4@xYmNj^jZ$VvL`j6Nk5zJhu3lnFep0GlMQ#C5HPEmMD* z7iAWdWaj57fXq!y$}cUkRZ;?31P2gzmSmOrNrwBXptL9l?5C7u{nVV)+|<01VxT@ltkwa;7OoM+krjyr5X-=U2=SW@$mLc+ zsm1v@rJx`P&C4vYGqM4D2wfNvA`o59`MCu}sl~-WZFZ(mEy!Z%>LU==*qOuZKo&&T z;9ryp^l2i;q38AY7TN8=P8YBrMjVZ}i#idDEsmUcsu?37XaN2iDOxH&ew$aC` z+6I^stbFrRGSezu5=&C;j0_CTtqhEp^uQ%R{x==!0?*Qm%qzS+FQD&)RVT?S$ojJFZ=`xb`tHFeQ4rIEG}f zzKz=Hci2IIm!&YI#6&=li)(_$i-nDHSygt-6L#!tYP-K+k*kwP!-NIKvaGDULhcs# zJa$hqJ^1?Wjn@{3*L>MB(>Cqd+34eakKCMRzv1GkykLEFmgR%v$+;I*eJw1Q`?{>O zHvMOu-I+7>hW4Zl+3!2DFP$m%`QP|Yuw&^LmYVH8Yifm`U$`-~tX$1P)0VTx{m`z? z$#$N*C06f=JoLT8M#}IPSB>yZ{|7f~)OLqlI$R)esb=33r$0-tN8NWRlHOr7nf-;g zYVM!3vdq@wM&Y9KBU-tYe)H-u86PlpNM5SVJAdX{`IhOvX1QOMPU5q@G&8i*Wa5GM zY6aPU#O>~ts{7aoCop?VzSnp+SeoUKiw@(ZB`^Qo5q{~Y$W!-pf}F~sr4!ZM*Inz+ zf2kVoG-Ec~3%lI>$a}|cKaaFhFPrj`wPGv3Qa$U7gbDMu`!{GdtjkoY=Ml*Z)%NME zXLLE$YJTQ&@`})zzwXFOm+or2+!YjeR^~#my#2yxiDI*T2X|V0dcyl>{a1nJx(gRB z<}tpn{QcVH2kXgs&sFCb{-0%d&opMa^4+O(o-@e4{qpp|9ks>{lNIKN9NMFFDJL{y z)}lH6T4%JC&W5!v)jaic1!cl~p)>9+UJ=cGO7jUX!>`LT??v(J2EAco{i`VFw4?Wo ze&d3!V`<#~RgSF5mythI#=F6**{;zY^&3srap75OY1IrcPNWZQrem@r6`oETG Y|DT=??|lmI^gtDmr>mdKI;Vst0Mr+M=Kufz literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/file-black-60.imageset/file-icon-60@2x.png b/Signal/Images.xcassets/file-black-60.imageset/file-icon-60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fd1009293d2c9bbf28158c326a2c1d1bba6245e0 GIT binary patch literal 2397 zcmeAS@N?(olHy`uVBq!ia0vp^6(G#P1|%(0%q{^bmUKs7M+SzC{oH>NS%G}c0*}aI z1_o|n5N2eUHAe!dMkO;Oq9nrC$0|8LS1&OoKPgqOBDVmjnt{Ql!V1XDO)W`OsL0L9 zE4HezRRXK90GK4GQ<#=IWDQi z$wiq3C7Jno3LtY6lk!VTY?YKi7Qq3;oh6xR2%GYXq22;|P#+|tZ>VRWk4;-@MJ5hy zAQ_z6Qj+1mDkv?=0sAQ>SwA%=H8(Y{q!_5r5UX{-u!Us=@X|;H|DmcSHI?NFQ0yQqM*Fr0Zt1>^#?3-8iWg& zt_n-6T~Z-xH9Np~>X(p|X$MZIUtzr>E*kvz!$%==-W`Xd`VF?1{^i*A*7mVr)Z-tK z&Mpzj>U-|G^U6GlYG}O~ve|6H1l}Fi{}_MDW#yJn|C;|r;^VdH3;s@7aej&&|Hoin z^Bb*oIoFp5Ugk}1TPLevJwG8=_CaKv-?Ph>``aay_fMJ`{pAM(b6nJeTJvKk@~`_G zV3p)OGofPYguQ%xCnm2jU1e0}ASw{+G!yMy9Ds7pTwsbYHw_&wu?Vp-+qEOk}&Gcm2k);3{)PUxznqKy8B{S=Dp`i_O+9c` zd9Lu3hMWV%HX8Oe?OAJ{RPgWqY|(T~SELl^$n-Z~>*G0!4lH*vd+^J__~_05S!cqE z9QJiaO^m&g>y!KyVeO35k6&k560@-8i6>7l`@xx?ygyC+Cq3u+q6>F}4!1Bq z*VH?G+xG1-uDsfc?sLjDP2ZS9YGPY!kJy?mDBF;K#m)YA-lcD5P5*Ch{b;+6!FK!lvI6;>1s;*b z3=G`DAk4@xYmNj^jY?)nL`j6Nk5zJhu3lnFep0GlMQ#C5H3Nf9g%yyQn_7~nP?4LH zS8P>bs{~eI1!RMS^_3LBN=mYAl_Got6rA&mQWZ?~O!N$t?6?#Z6l{u8(yW49+@RWl zJX@uVl9B=|ef{$Ca=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wr!g#b6ir3 zlZ!G7N;32F6hP)CCgqow*eWT3EP?}wJ4-Ut5H{r%L%jv`pgu@O-%!s$ADgz+icB2Z zKr%SBr6j|BRZv=#1NKu&vVLk#YHn&?Nik5LAy(^vVGGxY;>e1`0*GbcK!o_s2IO+9 zpw#00oKjE_gyvGs1{@~boCJkYwXNnb|4F) zYw$111o|`)$`{ zLn;{G&b93q4V7tse=3RTenX13JrnEPXs3RYI#zC}r>@nk;k=@qbq!a$E(Bgs)Mphr za_E*@GE1CQudH3(+X_{~FXZ0P$`_A6?%`7VV4uJjM#-sl-dEW3WE|xu z1b*DE`AT1VUj3$voK;3sH^;x2J!8S|71z`E^L8JdZ+Q4}#5(s5)*Q>~mMyqTBt?yvOzaU$>#kLvdQUGwwo>((f( zelq)f&TqC|J+l^kXU_PzTjc9kG4pLX{w#aX_{i@6Z z?pV!T7vBq#rXn?`?i=1-zELja%njEoEOP^$4lb{e*u1x^R8uUlou!G7lUL^d5xJl% z`_tYmeOaE>bWUTzq~M?{^N+l;%4%A-mFl@d^I;>yNt8d|I=k}*xf4G+E(aWyD4Y1r%Jp`pIra!g2M&A z(*~0o&G~p)-frMIoYt@)cU3ss+?bzJW%o^3F7x#MmvqBNFC$(qKQ^sqiMnKZ@?6cz z6D!lK-?%IPHxg}meI_r#S}o$+<5|JXpPKt+ijKxIroGSn#<*+O-JGzzh6PW%7%g}O zwp=#T*~!>6O`Gk3iNgiI+Z&#+aYU_?Xt>PaXq|g_lC(m`&LjpuW|p^Gc)dq8jRwR3 zqzF}(y^rr0=&WqK`TpsylIlwF`#qQ69f>+^J$Eyg=?3ZIxwEUc2{qm0;LI#ccyNQw z>&J=0H@*doJUnb1RR#yItMLew2ydV03+L`=(tD^s-}lajF7w3915BN>KWJQw-*{=U vY~MegCGMN*ziiJf>%m�IQ*v#_wO!f5lIcm!lvI6;>1s;*b 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 z + +@class TSAttachmentStream; + +@interface TSGenericAttachmentAdapter : JSQMediaItem + +- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming; + +@end diff --git a/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m new file mode 100644 index 000000000..3627ef66e --- /dev/null +++ b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m @@ -0,0 +1,196 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "TSGenericAttachmentAdapter.h" +#import "AttachmentUploadView.h" +#import "TSAttachmentStream.h" +#import "UIColor+JSQMessages.h" +#import "UIColor+OWS.h" +#import "UIFont+OWS.h" +#import +#import +#import +#import + +@interface TSGenericAttachmentAdapter () + +@property (nonatomic) UIView *cachedMediaView; +@property (nonatomic) TSAttachmentStream *attachment; +@property (nonatomic) AttachmentUploadView *attachmentUploadView; +@property (nonatomic) BOOL incoming; +@property (nonatomic) NSString *attachmentId; + +@end + +@implementation TSGenericAttachmentAdapter + +- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming +{ + self = [super init]; + + if (self) { + _attachment = attachment; + _attachmentId = attachment.uniqueId; + _incoming = incoming; + } + + return self; +} + +- (void)clearCachedMediaViews +{ + [super clearCachedMediaViews]; + _cachedMediaView = nil; +} + +- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing +{ + [super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing]; + _cachedMediaView = nil; +} + +// TODO: Should we override hash or mediaHash? +- (NSUInteger)mediaHash +{ + return [self.attachment.uniqueId hash]; +} + +#pragma mark - JSQMessageMediaData protocol + +- (CGFloat)iconSize +{ + return 60.f; +} + +- (CGFloat)hMargin +{ + return 10.f; +} + +- (CGFloat)vMargin +{ + return 10.f; +} + +- (UIFont *)attachmentLabelFont +{ + return [UIFont ows_regularFontWithSize:11.f]; +} + +- (UIFont *)fileTypeLabelFont +{ + return [UIFont ows_mediumFontWithSize:16.f]; +} + +- (UIView *)mediaView +{ + if (_cachedMediaView == nil) { + CGSize viewSize = [self mediaViewDisplaySize]; + UIColor *textColor = (self.incoming ? [UIColor blackColor] : [UIColor whiteColor]); + + JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init]; + JSQMessagesBubbleImage *bubbleImageData = (self.incoming + ? [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]] + : [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]]); + UIImage *bubbleImage = [bubbleImageData messageBubbleImage]; + OWSAssert(bubbleImage); + UIImageView *bubbleImageView = [[UIImageView alloc] initWithImage:bubbleImage]; + _cachedMediaView = bubbleImageView; + _cachedMediaView.frame = CGRectMake(0.f, 0.f, viewSize.width, viewSize.height); + + const CGFloat kBubbleTailWidth = 6.f; + CGRect contentFrame = CGRectMake(self.incoming ? kBubbleTailWidth : 0.f, + self.vMargin, + viewSize.width - kBubbleTailWidth, + viewSize.height - self.vMargin * 2.f); + + UIImage *image = [UIImage imageNamed:(self.incoming ? @"file-black-60" : @"file-white-60")]; + OWSAssert(image); + UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; + CGRect iconFrame = CGRectMake(round(contentFrame.origin.x + (contentFrame.size.width - self.iconSize) * 0.5f), + round(contentFrame.origin.y), + self.iconSize, + self.iconSize); + imageView.frame = iconFrame; + [_cachedMediaView addSubview:imageView]; + + NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:self.attachment.contentType]; + if (fileExtension.length < 1) { + fileExtension = NSLocalizedString(@"GENERIC_ATTACHMENT_DEFAULT_TYPE", + @"A default label for attachment whose file extension cannot be determined."); + } + + UILabel *fileTypeLabel = [UILabel new]; + fileTypeLabel.text = fileExtension.uppercaseString; + fileTypeLabel.textColor = textColor; + fileTypeLabel.lineBreakMode = NSLineBreakByTruncatingTail; + fileTypeLabel.font = [self fileTypeLabelFont]; + CGRect fileTypeLabelFrame = CGRectZero; + fileTypeLabelFrame.size = [fileTypeLabel sizeThatFits:CGSizeZero]; + fileTypeLabelFrame.size.width = floor(MIN(self.iconSize * 0.5f, fileTypeLabelFrame.size.width)); + // Center on icon. + fileTypeLabelFrame.origin.x + = round(iconFrame.origin.x + (iconFrame.size.width - fileTypeLabelFrame.size.width) * 0.5f); + fileTypeLabelFrame.origin.y + = round(iconFrame.origin.y + (iconFrame.size.height - fileTypeLabelFrame.size.height) * 0.5f + 5); + fileTypeLabel.frame = fileTypeLabelFrame; + [_cachedMediaView addSubview:fileTypeLabel]; + + UILabel *attachmentLabel = [UILabel new]; + attachmentLabel.text = NSLocalizedString(@"GENERIC_ATTACHMENT_LABEL", @"A label for generic attachments."); + attachmentLabel.textColor = [textColor colorWithAlphaComponent:0.85f]; + attachmentLabel.lineBreakMode = NSLineBreakByTruncatingTail; + attachmentLabel.font = [self attachmentLabelFont]; + [attachmentLabel sizeToFit]; + CGRect attachmentLabelFrame = CGRectZero; + attachmentLabelFrame.size = attachmentLabel.bounds.size; + attachmentLabelFrame.origin.x + = round(contentFrame.origin.x + (contentFrame.size.width - attachmentLabelFrame.size.width) * 0.5f); + attachmentLabelFrame.origin.y + = round(contentFrame.origin.y + contentFrame.size.height - attachmentLabelFrame.size.height); + attachmentLabel.frame = attachmentLabelFrame; + [_cachedMediaView addSubview:attachmentLabel]; + + if (!self.incoming) { + self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment + superview:_cachedMediaView + attachmentStateCallback:nil]; + } + } + + return _cachedMediaView; +} + +- (CGSize)mediaViewDisplaySize +{ + const CGFloat kVSpacing = 1.f; + return CGSizeMake(100, ceil(self.iconSize + self.attachmentLabelFont.lineHeight + kVSpacing + self.vMargin * 2)); +} + +#pragma mark - OWSMessageEditing Protocol + +- (BOOL)canPerformEditingAction:(SEL)action +{ + if (action == @selector(copy:)) { + NSString *utiType = [MIMETypeUtil utiTypeForMIMEType:self.attachment.contentType]; + return utiType.length > 0; + } + return NO; +} + +- (void)performEditingAction:(SEL)action +{ + if (action == @selector(copy:)) { + NSString *utiType = [MIMETypeUtil utiTypeForMIMEType:self.attachment.contentType]; + OWSAssert(utiType.length > 0); + NSData *data = [NSData dataWithContentsOfURL:self.attachment.mediaURL]; + [UIPasteboard.generalPasteboard setData:data forPasteboardType:utiType]; + } else { + // Shouldn't get here, as only supported actions should be exposed via canPerformEditingAction + NSString *actionString = NSStringFromSelector(action); + DDLogError(@"'%@' action unsupported for %@: attachmentId=%@", actionString, [self class], self.attachmentId); + } +} + +@end diff --git a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m index 92bac48d8..bf3082fa4 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m @@ -4,20 +4,21 @@ #import "AttachmentSharing.h" #import "OWSCall.h" +#import "Signal-Swift.h" #import "TSAttachmentPointer.h" #import "TSAttachmentStream.h" #import "TSCall.h" #import "TSContactThread.h" #import "TSContentAdapters.h" #import "TSErrorMessage.h" +#import "TSGenericAttachmentAdapter.h" #import "TSGroupThread.h" #import "TSIncomingMessage.h" #import "TSInfoMessage.h" #import "TSOutgoingMessage.h" -#import "Signal-Swift.h" +#import "TSOversizeTextAttachmentAdapter.h" #import - @interface TSMessageAdapter () // --- @@ -131,7 +132,25 @@ if ([attachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachmentStream *stream = (TSAttachmentStream *)attachment; - if ([stream isAnimated]) { + if ([attachment.contentType isEqualToString:OWSMimeTypeOversizeTextMessage]) { + NSData *textData = [NSData dataWithContentsOfURL:stream.mediaURL]; + NSString *fullText = [[NSString alloc] initWithData:textData encoding:NSUTF8StringEncoding]; + // TODO: Tune this value. + const NSUInteger kMaxTextDisplayLength = 256; + NSString *displayText = fullText; + if (fullText.length > kMaxTextDisplayLength) { + // Trim whitespace before _AND_ after slicing the snipper from the string. + NSString *snippet = + [[[fullText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] + substringWithRange:NSMakeRange(0, kMaxTextDisplayLength)] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + displayText = + [NSString stringWithFormat:NSLocalizedString(@"OVERSIZE_TEXT_DISPLAY_FORMAT", + @"A display format for oversize text messages."), + snippet]; + } + adapter.messageBody = displayText; + } else if ([stream isAnimated]) { adapter.mediaItem = [[TSAnimatedAdapter alloc] initWithAttachment:stream incoming:isIncomingAttachment]; adapter.mediaItem.appliesMediaViewMaskAsOutgoing = @@ -143,13 +162,19 @@ adapter.mediaItem.appliesMediaViewMaskAsOutgoing = [interaction isKindOfClass:[TSOutgoingMessage class]]; break; - } else { + } else if ([stream isVideo]) { adapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:stream incoming:[interaction isKindOfClass:[TSIncomingMessage class]]]; adapter.mediaItem.appliesMediaViewMaskAsOutgoing = [interaction isKindOfClass:[TSOutgoingMessage class]]; break; + } else { + adapter.mediaItem = [[TSGenericAttachmentAdapter alloc] + initWithAttachment:stream + incoming:[interaction isKindOfClass:[TSIncomingMessage class]]]; + adapter.mediaItem.appliesMediaViewMaskAsOutgoing = YES; + break; } } else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { TSAttachmentPointer *pointer = (TSAttachmentPointer *)attachment; diff --git a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h index 2e40ad11e..b824c2a8c 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h @@ -11,10 +11,6 @@ - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming; -- (BOOL)isImage; -- (BOOL)isAudio; -- (BOOL)isVideo; - @property TSAttachmentStream *attachment; @property NSString *attachmentId; diff --git a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m index 7e3ebbb02..71dcb51e2 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m @@ -80,20 +80,6 @@ return [self ows_adjustBubbleSize:[super mediaViewDisplaySize] forImage:self.image]; } -- (BOOL)isImage { - return YES; -} - - -- (BOOL)isAudio { - return NO; -} - - -- (BOOL)isVideo { - return NO; -} - #pragma mark - OWSMessageEditing Protocol - (BOOL)canPerformEditingAction:(SEL)action diff --git a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h index 51ed816d6..0829cdd0a 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h @@ -15,7 +15,6 @@ - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming; -- (BOOL)isImage; - (BOOL)isAudio; - (BOOL)isVideo; - (void)setAudioProgressFromFloat:(float)progress; diff --git a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m index eec46ed1a..93b7b60e8 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m @@ -46,10 +46,6 @@ return self; } -- (BOOL)isImage { - return NO; -} - - (BOOL)isAudio { return [MIMETypeUtil isSupportedAudioMIMEType:_contentType]; } diff --git a/Signal/src/view controllers/DebugUITableViewController.m b/Signal/src/view controllers/DebugUITableViewController.m index da109a9b9..17e3534c6 100644 --- a/Signal/src/view controllers/DebugUITableViewController.m +++ b/Signal/src/view controllers/DebugUITableViewController.m @@ -3,8 +3,9 @@ // #import "DebugUITableViewController.h" -#import "ThreadUtil.h" #import "Environment.h" +#import "Signal-Swift.h" +#import "ThreadUtil.h" #import NS_ASSUME_NONNULL_BEGIN @@ -220,7 +221,7 @@ NSString * const kDebugUITableCellIdentifier = @"kDebugUITableCellIdentifier"; return self.class.tag; } -#pragma mark - Factory and presentation +#pragma mark - Factory Methods + (void)presentDebugUIForThread:(TSThread *)thread fromViewController:(UIViewController *)fromViewController { @@ -232,11 +233,24 @@ NSString * const kDebugUITableCellIdentifier = @"kDebugUITableCellIdentifier"; [contents addSection:[OWSTableSection sectionWithTitle:@"Messages View" items:@[ - [OWSTableItem actionWithTitle:@"Send 100 messages" + [OWSTableItem actionWithTitle:@"Send 10 messages (1/sec.)" + actionBlock:^{ + [DebugUITableViewController sendTextMessage:10 + thread:thread]; + }], + [OWSTableItem actionWithTitle:@"Send 100 messages (1/sec.)" actionBlock:^{ [DebugUITableViewController sendTextMessage:100 thread:thread]; }], + [OWSTableItem actionWithTitle:@"Send text/x-signal-plain" + actionBlock:^{ + [DebugUITableViewController sendOversizeTextMessage:thread]; + }], + [OWSTableItem actionWithTitle:@"Send unknown/mimetype" + actionBlock:^{ + [DebugUITableViewController sendUnknownMimetypeAttachment:thread]; + }], ]]]; DebugUITableViewController *viewController = [DebugUITableViewController new]; @@ -259,6 +273,39 @@ NSString * const kDebugUITableCellIdentifier = @"kDebugUITableCellIdentifier"; }); } ++ (void)sendOversizeTextMessage:(TSThread *)thread { + OWSMessageSender *messageSender = [Environment getCurrent].messageSender; + NSString *message = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse consequat, ligula et tincidunt mattis, nisl risus ultricies justo, vitae dictum augue risus vel ante. Suspendisse convallis bibendum lectus. Etiam molestie nisi ac orci sodales sollicitudin vitae eu quam. Morbi lacinia scelerisque risus. Quisque sagittis mauris enim, ac vestibulum dui commodo quis. Nullam at commodo nisl, ut pulvinar dui. Nunc tempus volutpat sagittis. Vestibulum eget maximus sem, sit amet tristique ex posuere."; + SignalAttachment *attachment = [SignalAttachment oversizeTextAttachmentWithText:message]; + [ThreadUtil sendMessageWithAttachment:attachment + inThread:thread + messageSender:messageSender]; +} + ++ (NSData*)createRandomNSDataOfSize:(size_t)size +{ + OWSAssert(size % 4 == 0); + + NSMutableData* data = [NSMutableData dataWithCapacity:size]; + for (size_t i = 0; i < size / 4; ++i) + { + u_int32_t randomBits = arc4random(); + [data appendBytes:(void *)&randomBits length:4]; + } + return data; +} + ++ (void)sendUnknownMimetypeAttachment:(TSThread *)thread { + OWSMessageSender *messageSender = [Environment getCurrent].messageSender; + SignalAttachment *attachment = [SignalAttachment genericAttachmentWithData:[self createRandomNSDataOfSize:256] + dataUTI:SignalAttachment.kUnknownTestAttachmentUTI]; + [ThreadUtil sendMessageWithAttachment:attachment + inThread:thread + messageSender:messageSender]; +} + +#pragma mark - Presentation + - (void)presentFromViewController:(UIViewController *)fromViewController { OWSAssert(fromViewController); diff --git a/Signal/src/view controllers/SignalAttachment.swift b/Signal/src/view controllers/SignalAttachment.swift index 27d9cf09c..57f6265f5 100644 --- a/Signal/src/view controllers/SignalAttachment.swift +++ b/Signal/src/view controllers/SignalAttachment.swift @@ -69,6 +69,9 @@ class SignalAttachment: NSObject { // See: https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html let dataUTI: String + static let kOversizeTextAttachmentUTI = "org.whispersystems.oversize-text-attachment" + static let kUnknownTestAttachmentUTI = "org.whispersystems.unknown" + var error: SignalAttachmentError? { didSet { AssertIsOnMainThread() @@ -137,6 +140,12 @@ class SignalAttachment: NSObject { // Returns the MIME type for this attachment or nil if no MIME type // can be identified. var mimeType: String? { + if dataUTI == SignalAttachment.kOversizeTextAttachmentUTI { + return OWSMimeTypeOversizeTextMessage + } + if dataUTI == SignalAttachment.kUnknownTestAttachmentUTI { + return OWSMimeTypeUnknownForTests + } let mimeType = UTTypeCopyPreferredTagWithClass(dataUTI as CFString, kUTTagClassMIMEType) guard mimeType != nil else { return nil @@ -147,6 +156,12 @@ class SignalAttachment: NSObject { // Returns the file extension for this attachment or nil if no file extension // can be identified. var fileExtension: String? { + if dataUTI == SignalAttachment.kOversizeTextAttachmentUTI || + dataUTI == SignalAttachment.kUnknownTestAttachmentUTI { + assert(false) + return "" + } + guard let fileExtension = UTTypeCopyPreferredTagWithClass(dataUTI as CFString, kUTTagClassFilenameExtension) else { return nil @@ -508,6 +523,19 @@ class SignalAttachment: NSObject { maxFileSize : kMaxFileSizeAudio) } + // MARK: Oversize Text Attachments + + // Factory method for oversize text attachments. + // + // NOTE: The attachment returned by this method may not be valid. + // Check the attachment's error property. + public class func oversizeTextAttachment(text: String?) -> SignalAttachment { + return newAttachment(data : text?.data(using: .utf8), + dataUTI : kOversizeTextAttachmentUTI, + validUTISet : nil, + maxFileSize : kMaxFileSizeGeneric) + } + // MARK: Generic Attachments // Factory method for generic attachments. diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 38c5757cb..a9ca26be4 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -97,6 +97,9 @@ /* No comment provided by engineer. */ "ATTACHMENT_QUEUED" = "New attachment queued for retrieval."; +/* A message indicating that an attachment of unknown type was received. */ +"ATTACHMENT_UNKNOWN_TYPE" = "Unknown attachment received"; + /* No comment provided by engineer. */ "AUDIO_PERMISSION_MESSAGE" = "Signal requires access to your microphone to work properly. You can grant this permission in the Settings app >> Privacy >> Microphone >> Signal"; @@ -325,6 +328,12 @@ /* Accessibilty label for finishing new group */ "FINISH_GROUP_CREATION_LABEL" = "Finish creating group"; +/* A default label for attachment whose file extension cannot be determined. */ +"GENERIC_ATTACHMENT_DEFAULT_TYPE" = "?"; + +/* A label for generic attachments. */ +"GENERIC_ATTACHMENT_LABEL" = "Attachment"; + /* No comment provided by engineer. */ "GROUP_AVATAR_CHANGED" = "Avatar changed. "; @@ -601,6 +610,9 @@ /* No comment provided by engineer. */ "OUTGOING_INCOMPLETE_CALL" = "Incomplete outgoing call"; +/* A display format for oversize text messages. */ +"OVERSIZE_TEXT_DISPLAY_FORMAT" = "%@… [Tap For More]"; + /* Alert body when verifying with {{contact name}} */ "PRIVACY_VERIFICATION_FAILED_I_HAVE_WRONG_KEY_FOR_THEM" = "This doesn't look like your safety number with %@. Are you verifying the correct contact?"; From b0aa71fd409e7f30ae0103ce2024a3e8afdf5d7d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 28 Mar 2017 18:13:48 -0400 Subject: [PATCH 2/4] Apply DisplayableTextFilter to oversize text messages. // FREEBIE --- Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m index bf3082fa4..4563cae43 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m @@ -137,11 +137,11 @@ NSString *fullText = [[NSString alloc] initWithData:textData encoding:NSUTF8StringEncoding]; // TODO: Tune this value. const NSUInteger kMaxTextDisplayLength = 256; - NSString *displayText = fullText; - if (fullText.length > kMaxTextDisplayLength) { + NSString *displayText = [[DisplayableTextFilter new] displayableText:fullText]; + if (displayText.length > kMaxTextDisplayLength) { // Trim whitespace before _AND_ after slicing the snipper from the string. NSString *snippet = - [[[fullText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] + [[[displayText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] substringWithRange:NSMakeRange(0, kMaxTextDisplayLength)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; displayText = From 3d451846a61b7c8c184a6912b9ca0f7eb7f26e6c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 29 Mar 2017 14:37:14 -0400 Subject: [PATCH 3/4] Fix build break. // FREEBIE --- Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m index 4563cae43..9e8105094 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m @@ -16,7 +16,6 @@ #import "TSIncomingMessage.h" #import "TSInfoMessage.h" #import "TSOutgoingMessage.h" -#import "TSOversizeTextAttachmentAdapter.h" #import @interface TSMessageAdapter () From 7b84019251807bd5d2d018dd951f107a8728ff7d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 29 Mar 2017 14:49:26 -0400 Subject: [PATCH 4/4] Respond to CR. // FREEBIE --- .../TSMessageAdapaters/TSAnimatedAdapter.h | 4 ++ .../TSMessageAdapaters/TSAnimatedAdapter.m | 10 +++- .../TSGenericAttachmentAdapter.h | 4 ++ .../TSGenericAttachmentAdapter.m | 17 +++++-- .../TSMessageAdapaters/TSMessageAdapter.m | 20 ++++---- .../TSMessageAdapaters/TSPhotoAdapter.h | 4 ++ .../TSMessageAdapaters/TSPhotoAdapter.m | 10 +++- .../TSVideoAttachmentAdapter.h | 9 +++- .../TSVideoAttachmentAdapter.m | 49 ++++++++++--------- .../AttachmentApprovalViewController.swift | 2 +- .../view controllers/SignalAttachment.swift | 8 +-- 11 files changed, 89 insertions(+), 48 deletions(-) diff --git a/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.h index 465e20e16..b5dbffaf0 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.h @@ -5,6 +5,8 @@ #import "OWSMessageEditing.h" #import +NS_ASSUME_NONNULL_BEGIN + @class TSAttachmentStream; @interface TSAnimatedAdapter : JSQMediaItem @@ -15,3 +17,5 @@ @property NSData *fileData; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.m index a74896ead..c5a88879e 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSAnimatedAdapter.m @@ -11,16 +11,20 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @interface TSAnimatedAdapter () -@property (nonatomic) UIImageView *cachedImageView; +@property (nonatomic, nullable) UIImageView *cachedImageView; @property (nonatomic) UIImage *image; @property (nonatomic) TSAttachmentStream *attachment; -@property (nonatomic) AttachmentUploadView *attachmentUploadView; +@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @property (nonatomic) BOOL incoming; @end +#pragma mark - + @implementation TSAnimatedAdapter - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming @@ -124,3 +128,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.h index 947a66d0b..8e8af3a39 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.h @@ -5,6 +5,8 @@ #import "OWSMessageEditing.h" #import +NS_ASSUME_NONNULL_BEGIN + @class TSAttachmentStream; @interface TSGenericAttachmentAdapter : JSQMediaItem @@ -12,3 +14,5 @@ - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m index 3627ef66e..71942fbfc 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSGenericAttachmentAdapter.m @@ -13,16 +13,19 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @interface TSGenericAttachmentAdapter () -@property (nonatomic) UIView *cachedMediaView; +@property (nonatomic, nullable) UIView *cachedMediaView; @property (nonatomic) TSAttachmentStream *attachment; -@property (nonatomic) AttachmentUploadView *attachmentUploadView; +@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @property (nonatomic) BOOL incoming; -@property (nonatomic) NSString *attachmentId; @end +#pragma mark - + @implementation TSGenericAttachmentAdapter - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming @@ -31,13 +34,17 @@ if (self) { _attachment = attachment; - _attachmentId = attachment.uniqueId; _incoming = incoming; } return self; } +- (NSString *)attachmentId +{ + return self.attachment.uniqueId; +} + - (void)clearCachedMediaViews { [super clearCachedMediaViews]; @@ -194,3 +201,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m index 9e8105094..9ca47dd0f 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSMessageAdapter.m @@ -18,6 +18,8 @@ #import "TSOutgoingMessage.h" #import +NS_ASSUME_NONNULL_BEGIN + @interface TSMessageAdapter () // --- @@ -60,6 +62,7 @@ @end +#pragma mark - @implementation TSMessageAdapter @@ -134,8 +137,8 @@ if ([attachment.contentType isEqualToString:OWSMimeTypeOversizeTextMessage]) { NSData *textData = [NSData dataWithContentsOfURL:stream.mediaURL]; NSString *fullText = [[NSString alloc] initWithData:textData encoding:NSUTF8StringEncoding]; - // TODO: Tune this value. - const NSUInteger kMaxTextDisplayLength = 256; + // Only show up to 2kb of text. + const NSUInteger kMaxTextDisplayLength = 2 * 1024; NSString *displayText = [[DisplayableTextFilter new] displayableText:fullText]; if (displayText.length > kMaxTextDisplayLength) { // Trim whitespace before _AND_ after slicing the snipper from the string. @@ -152,27 +155,24 @@ } else if ([stream isAnimated]) { adapter.mediaItem = [[TSAnimatedAdapter alloc] initWithAttachment:stream incoming:isIncomingAttachment]; - adapter.mediaItem.appliesMediaViewMaskAsOutgoing = - [interaction isKindOfClass:[TSOutgoingMessage class]]; + adapter.mediaItem.appliesMediaViewMaskAsOutgoing = !isIncomingAttachment; break; } else if ([stream isImage]) { adapter.mediaItem = [[TSPhotoAdapter alloc] initWithAttachment:stream incoming:isIncomingAttachment]; - adapter.mediaItem.appliesMediaViewMaskAsOutgoing = - [interaction isKindOfClass:[TSOutgoingMessage class]]; + adapter.mediaItem.appliesMediaViewMaskAsOutgoing = !isIncomingAttachment; break; } else if ([stream isVideo]) { adapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:stream incoming:[interaction isKindOfClass:[TSIncomingMessage class]]]; - adapter.mediaItem.appliesMediaViewMaskAsOutgoing = - [interaction isKindOfClass:[TSOutgoingMessage class]]; + adapter.mediaItem.appliesMediaViewMaskAsOutgoing = !isIncomingAttachment; break; } else { adapter.mediaItem = [[TSGenericAttachmentAdapter alloc] initWithAttachment:stream incoming:[interaction isKindOfClass:[TSIncomingMessage class]]]; - adapter.mediaItem.appliesMediaViewMaskAsOutgoing = YES; + adapter.mediaItem.appliesMediaViewMaskAsOutgoing = !isIncomingAttachment; break; } } else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { @@ -402,3 +402,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h index b824c2a8c..5c44c5110 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.h @@ -5,6 +5,8 @@ #import "OWSMessageEditing.h" #import +NS_ASSUME_NONNULL_BEGIN + @class TSAttachmentStream; @interface TSPhotoAdapter : JSQPhotoMediaItem @@ -15,3 +17,5 @@ @property NSString *attachmentId; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m index 71dcb51e2..0788b35d9 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSPhotoAdapter.m @@ -9,14 +9,18 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @interface TSPhotoAdapter () -@property (nonatomic) UIImageView *cachedImageView; -@property (nonatomic) AttachmentUploadView *attachmentUploadView; +@property (nonatomic, nullable) UIImageView *cachedImageView; +@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @property (nonatomic) BOOL incoming; @end +#pragma mark - + @implementation TSPhotoAdapter - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming @@ -126,3 +130,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h index 0829cdd0a..e735d9bfd 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h +++ b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.h @@ -1,9 +1,12 @@ -// Created by Frederic Jacobs on 17/12/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "OWSMessageEditing.h" #import +NS_ASSUME_NONNULL_BEGIN + @class TSAttachmentStream; @interface TSVideoAttachmentAdapter : JSQVideoMediaItem @@ -24,3 +27,5 @@ - (void)resetAudioDuration; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m index 93b7b60e8..c5db763e3 100644 --- a/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m +++ b/Signal/src/Models/TSMessageAdapaters/TSVideoAttachmentAdapter.m @@ -14,22 +14,23 @@ #import #define AUDIO_BAR_HEIGHT 36 +NS_ASSUME_NONNULL_BEGIN + @interface TSVideoAttachmentAdapter () @property (nonatomic) UIImage *image; -@property (nonatomic) UIImageView *cachedImageView; -@property (nonatomic) UIImageView *videoPlayButton; +@property (nonatomic, nullable) UIImageView *cachedImageView; @property (nonatomic) TSAttachmentStream *attachment; -@property (nonatomic) UIProgressView *audioProgress; -@property (nonatomic) SCWaveformView *waveform; -@property (nonatomic) UIButton *audioPlayPauseButton; -@property (nonatomic) UILabel *durationLabel; -@property (nonatomic) UIView *audioBubble; +@property (nonatomic, nullable) SCWaveformView *waveform; +@property (nonatomic, nullable) UIButton *audioPlayPauseButton; +@property (nonatomic, nullable) UILabel *durationLabel; @property (nonatomic) BOOL incoming; -@property (nonatomic) AttachmentUploadView *attachmentUploadView; +@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @end +#pragma mark - + @implementation TSVideoAttachmentAdapter - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming { @@ -113,17 +114,15 @@ isOutgoing:self.appliesMediaViewMaskAsOutgoing]; self.cachedImageView = imageView; UIImage *img = [UIImage imageNamed:@"play_button"]; - _videoPlayButton = [[UIImageView alloc] initWithImage:img]; - _videoPlayButton.frame = CGRectMake((size.width / 2) - 18, (size.height / 2) - 18, 37, 37); - [self.cachedImageView addSubview:_videoPlayButton]; + UIImageView *videoPlayButton = [[UIImageView alloc] initWithImage:img]; + videoPlayButton.frame = CGRectMake((size.width / 2) - 18, (size.height / 2) - 18, 37, 37); + [self.cachedImageView addSubview:videoPlayButton]; if (!_incoming) { - __weak TSVideoAttachmentAdapter *weakSelf = self; self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment superview:imageView attachmentStateCallback:^(BOOL isAttachmentReady) { - weakSelf.videoPlayButton.hidden - = !isAttachmentReady; + videoPlayButton.hidden = !isAttachmentReady; }]; } } @@ -143,11 +142,11 @@ self.waveform.progress = 0.0; } - _audioBubble = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, size.width, size.height)]; - _audioBubble.backgroundColor = + UIView *audioBubble = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, size.width, size.height)]; + audioBubble.backgroundColor = [UIColor colorWithRed:10 / 255.0f green:130 / 255.0f blue:253 / 255.0f alpha:1.0f]; - _audioBubble.layer.cornerRadius = 18; - _audioBubble.layer.masksToBounds = YES; + audioBubble.layer.cornerRadius = 18; + audioBubble.layer.masksToBounds = YES; _audioPlayPauseButton = [[UIButton alloc] initWithFrame:CGRectMake(3, 3, 30, 30)]; [_audioPlayPauseButton setBackgroundImage:[UIImage imageNamed:@"audio_play_button"] @@ -166,7 +165,7 @@ _durationLabel.textColor = [UIColor whiteColor]; if (_incoming) { - _audioBubble.backgroundColor = + audioBubble.backgroundColor = [UIColor colorWithRed:229 / 255.0f green:228 / 255.0f blue:234 / 255.0f alpha:1.0f]; _waveform.normalColor = [UIColor whiteColor]; _waveform.progressColor = @@ -176,21 +175,21 @@ _durationLabel.textColor = [UIColor darkTextColor]; } - [_audioBubble addSubview:_waveform]; - [_audioBubble addSubview:_audioPlayPauseButton]; - [_audioBubble addSubview:_durationLabel]; + [audioBubble addSubview:_waveform]; + [audioBubble addSubview:_audioPlayPauseButton]; + [audioBubble addSubview:_durationLabel]; if (!_incoming) { __weak TSVideoAttachmentAdapter *weakSelf = self; self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment - superview:_audioBubble + superview:audioBubble attachmentStateCallback:^(BOOL isAttachmentReady) { weakSelf.audioPlayPauseButton.enabled = isAttachmentReady; }]; } - return _audioBubble; + return audioBubble; } else { // Unknown media type. OWSAssert(0); @@ -280,3 +279,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/view controllers/AttachmentApprovalViewController.swift b/Signal/src/view controllers/AttachmentApprovalViewController.swift index db57b8f1b..b6df468b5 100644 --- a/Signal/src/view controllers/AttachmentApprovalViewController.swift +++ b/Signal/src/view controllers/AttachmentApprovalViewController.swift @@ -21,7 +21,7 @@ class AttachmentApprovalViewController: UIViewController { self.attachment = SignalAttachment.genericAttachment(data: nil, dataUTI: kUTTypeContent as String) super.init(coder: aDecoder) - assert(false) + assertionFailure() } required init(attachment: SignalAttachment, successCompletion : @escaping () -> Void) { diff --git a/Signal/src/view controllers/SignalAttachment.swift b/Signal/src/view controllers/SignalAttachment.swift index 57f6265f5..30421e9fb 100644 --- a/Signal/src/view controllers/SignalAttachment.swift +++ b/Signal/src/view controllers/SignalAttachment.swift @@ -116,7 +116,7 @@ class SignalAttachment: NSObject { var errorName: String? { guard let error = error else { // This method should only be called if there is an error. - assert(false) + assertionFailure() return nil } @@ -126,7 +126,7 @@ class SignalAttachment: NSObject { var localizedErrorDescription: String? { guard let error = self.error else { // This method should only be called if there is an error. - assert(false) + assertionFailure() return nil } @@ -158,8 +158,8 @@ class SignalAttachment: NSObject { var fileExtension: String? { if dataUTI == SignalAttachment.kOversizeTextAttachmentUTI || dataUTI == SignalAttachment.kUnknownTestAttachmentUTI { - assert(false) - return "" + assertionFailure() + return nil } guard let fileExtension = UTTypeCopyPreferredTagWithClass(dataUTI as CFString,