Handle oversize text messages and arbitrary attachments.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-03-28 15:29:08 -04:00
parent bf1a790372
commit 80fbc093d9
23 changed files with 388 additions and 49 deletions

View File

@ -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 = "<group>"; };
345670FF1E89A5F1006EE662 /* ThreadUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadUtil.h; sourceTree = "<group>"; };
345671001E89A5F1006EE662 /* ThreadUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadUtil.m; sourceTree = "<group>"; };
345671081E8A9F5D006EE662 /* TSGenericAttachmentAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSGenericAttachmentAdapter.h; sourceTree = "<group>"; };
345671091E8A9F5D006EE662 /* TSGenericAttachmentAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSGenericAttachmentAdapter.m; sourceTree = "<group>"; };
34802DD51E899CFB0032EA1D /* DebugUITableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUITableViewController.h; sourceTree = "<group>"; };
34802DD61E899CFB0032EA1D /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUITableViewController.m; sourceTree = "<group>"; };
348A08411E6A044E0057E290 /* MessagesViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessagesViewController.xib; sourceTree = "<group>"; };
@ -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 */,

View File

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "file-white-60@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "file-white-60@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "file-white-60@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,8 +1,11 @@
// Copyright (c) 2016 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSCall.h"
#import "OWSDisplayedMessageCollectionViewCell.h"
#import "TSGenericAttachmentAdapter.h"
#import "TSMessageAdapter.h"
#import "UIFont+OWS.h"
#import "tgmath.h" // generic math allows fmax to handle CGFLoat correctly on 32 & 64bit.

View File

@ -79,6 +79,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)dealloc
{
[_maskLayer removeFromSuperlayer];
[_progressView removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

View File

@ -11,10 +11,6 @@
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
- (BOOL)isImage;
- (BOOL)isAudio;
- (BOOL)isVideo;
@property NSString *attachmentId;
@property NSData *fileData;

View File

@ -94,20 +94,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

View File

@ -0,0 +1,14 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageEditing.h"
#import <JSQMessagesViewController/JSQMediaItem.h>
@class TSAttachmentStream;
@interface TSGenericAttachmentAdapter : JSQMediaItem <OWSMessageEditing>
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
@end

View File

@ -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 <JSQMessagesViewController/JSQMessagesBubbleImage.h>
#import <JSQMessagesViewController/JSQMessagesBubbleImageFactory.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <SignalServiceKit/MimeTypeUtil.h>
@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

View File

@ -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 <MobileCoreServices/MobileCoreServices.h>
@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;

View File

@ -11,10 +11,6 @@
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
- (BOOL)isImage;
- (BOOL)isAudio;
- (BOOL)isVideo;
@property TSAttachmentStream *attachment;
@property NSString *attachmentId;

View File

@ -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

View File

@ -15,7 +15,6 @@
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
- (BOOL)isImage;
- (BOOL)isAudio;
- (BOOL)isVideo;
- (void)setAudioProgressFromFloat:(float)progress;

View File

@ -46,10 +46,6 @@
return self;
}
- (BOOL)isImage {
return NO;
}
- (BOOL)isAudio {
return [MIMETypeUtil isSupportedAudioMIMEType:_contentType];
}

View File

@ -3,8 +3,9 @@
//
#import "DebugUITableViewController.h"
#import "ThreadUtil.h"
#import "Environment.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
#import <SignalServiceKit/TSThread.h>
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);

View File

@ -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.

View File

@ -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?";