diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index cb7b23672..3d8a5e71c 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -348,6 +348,8 @@ B66DBF4A19D5BBC8006EA940 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B66DBF4919D5BBC8006EA940 /* Images.xcassets */; }; B67ADDC41989FF8700E1A773 /* RPServerRequestsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B67ADDC31989FF8700E1A773 /* RPServerRequestsManager.m */; }; B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B67EBF5C19194AC60084CCFD /* Settings.bundle */; }; + B68112EA1A4D9EC400BA82FF /* UIImage+normalizeImage.m in Sources */ = {isa = PBXBuildFile; fileRef = B68112E91A4D9EC400BA82FF /* UIImage+normalizeImage.m */; }; + B68112ED1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m in Sources */ = {isa = PBXBuildFile; fileRef = B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */; }; B684A46D19C3446200B11029 /* PushManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B684A46C19C3446200B11029 /* PushManagerTest.m */; }; B6850E5A1995A4710068E715 /* whisperFake.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6850E591995A4710068E715 /* whisperFake.cer */; }; B69CD25119773E79005CE69A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B69CD25019773E79005CE69A /* XCTest.framework */; }; @@ -972,6 +974,10 @@ B67ADDC21989FF8700E1A773 /* RPServerRequestsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RPServerRequestsManager.h; sourceTree = ""; }; B67ADDC31989FF8700E1A773 /* RPServerRequestsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RPServerRequestsManager.m; sourceTree = ""; }; B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = SettingsBundle/Settings.bundle; sourceTree = SOURCE_ROOT; }; + B68112E81A4D9EC400BA82FF /* UIImage+normalizeImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+normalizeImage.h"; path = "util/UIImage+normalizeImage.h"; sourceTree = ""; }; + B68112E91A4D9EC400BA82FF /* UIImage+normalizeImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+normalizeImage.m"; path = "util/UIImage+normalizeImage.m"; sourceTree = ""; }; + B68112EB1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "JSQMessagesCollectionViewCell+menuBarItems.h"; path = "views/JSQMessagesCollectionViewCell+menuBarItems.h"; sourceTree = ""; }; + B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "JSQMessagesCollectionViewCell+menuBarItems.m"; path = "views/JSQMessagesCollectionViewCell+menuBarItems.m"; sourceTree = ""; }; B684A46C19C3446200B11029 /* PushManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PushManagerTest.m; path = Signal/test/push/PushManagerTest.m; sourceTree = SOURCE_ROOT; }; B6850E591995A4710068E715 /* whisperFake.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = whisperFake.cer; sourceTree = ""; }; B69CD25019773E79005CE69A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; @@ -2711,6 +2717,10 @@ FCFA64B31A24F3880007FB87 /* UIColor+OWS.m */, FCFA64B51A24F6730007FB87 /* UIFont+OWS.h */, FCFA64B61A24F6730007FB87 /* UIFont+OWS.m */, + B68112E81A4D9EC400BA82FF /* UIImage+normalizeImage.h */, + B68112E91A4D9EC400BA82FF /* UIImage+normalizeImage.m */, + B68112EB1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.h */, + B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */, ); name = "UI Categories"; path = ..; @@ -3209,6 +3219,7 @@ 76EB05EA18170B33006006FC /* CallProgress.m in Sources */, FCFA64B41A24F3880007FB87 /* UIColor+OWS.m in Sources */, 76EB05C218170B33006006FC /* DhPacketSharedSecretHashes.m in Sources */, + B68112ED1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m in Sources */, B6B096701A1D25ED008BFAA6 /* TSInfoMessage.m in Sources */, B6C93C4E199567AD00EDF894 /* DebugLogger.m in Sources */, 76EB063218170B33006006FC /* Crc32.m in Sources */, @@ -3275,6 +3286,7 @@ B6B0968C1A1D25ED008BFAA6 /* TSDatabaseView.m in Sources */, B6B0966A1A1D25ED008BFAA6 /* IncomingPushMessageSignal.pb.m in Sources */, BFB074C919A5611000F2947C /* ObservableValue.m in Sources */, + B68112EA1A4D9EC400BA82FF /* UIImage+normalizeImage.m in Sources */, B6B0968E1A1D25ED008BFAA6 /* TSStorageManager.m in Sources */, FCB11D8A1A1284BB002F93FB /* SettingsTableViewCell.m in Sources */, 76EB05C818170B33006006FC /* HelloPacket.m in Sources */, diff --git a/Signal/src/environment/PreferencesUtil.h b/Signal/src/environment/PreferencesUtil.h index 0a810a482..d3dfb67f4 100644 --- a/Signal/src/environment/PreferencesUtil.h +++ b/Signal/src/environment/PreferencesUtil.h @@ -10,9 +10,10 @@ typedef NS_ENUM(NSUInteger, NotificationType) { }; typedef NS_ENUM(NSUInteger, TSImageQuality) { - TSImageQualityHigh, - TSImageQualityMedium, - TSImageQualityLow + TSImageQualityUncropped = 1, + TSImageQualityHigh = 2, + TSImageQualityMedium = 3, + TSImageQualityLow = 4 }; @class PhoneNumber; diff --git a/Signal/src/environment/PreferencesUtil.m b/Signal/src/environment/PreferencesUtil.m index 3ccd0d3b9..49a1ef7be 100644 --- a/Signal/src/environment/PreferencesUtil.m +++ b/Signal/src/environment/PreferencesUtil.m @@ -135,7 +135,7 @@ if (preference) { return [preference unsignedIntegerValue]; } else { - return TSImageQualityMedium; + return TSImageQualityUncropped; } } diff --git a/Signal/src/textsecure/Contacts/TSThread.h b/Signal/src/textsecure/Contacts/TSThread.h index 4c5ca03ac..156f7cce8 100644 --- a/Signal/src/textsecure/Contacts/TSThread.h +++ b/Signal/src/textsecure/Contacts/TSThread.h @@ -7,8 +7,6 @@ // #import -#import - #import "TSYapDatabaseObject.h" typedef NS_ENUM(NSInteger, TSLastActionType) { diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h index 2ef09e91e..d315669ca 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.h @@ -8,7 +8,7 @@ #import "TSAttachment.h" -@interface TSAttachmentStream : TSAttachment +@interface TSAttachmentStream : TSAttachment - (instancetype)initWithIdentifier:(NSString*)identifier data:(NSData*)data diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m index 0b9e548f6..53916f867 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentStream.m @@ -7,10 +7,13 @@ // #import "TSAttachmentStream.h" +#import "UIImage+contentTypes.h" + +NSString * const TSAttachementFileRelationshipEdge = @"TSAttachementFileEdge"; @interface TSAttachmentStream () -@property (nonatomic) NSString *path; +@property (nonatomic) NSString *attachmentPath; @end @@ -21,9 +24,8 @@ key:(NSData*)key contentType:(NSString*)contentType{ self = [super initWithIdentifier:identifier encryptionKey:key contentType:contentType]; - - NSString *path = [self filePath]; - [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; + + [[NSFileManager defaultManager] createFileAtPath:_attachmentPath contents:data attributes:nil]; return self; } @@ -32,10 +34,18 @@ return YES; } +- (NSArray *)yapDatabaseRelationshipEdges { + YapDatabaseRelationshipEdge *attachmentFileEdge = [YapDatabaseRelationshipEdge edgeWithName:TSAttachementFileRelationshipEdge + destinationFilePath:[self filePath] + nodeDeleteRules:YDB_DeleteDestinationIfSourceDeleted]; + + return @[attachmentFileEdge]; +} + + (NSString*)attachmentsFolder { - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSURL *fileURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; - NSString *path = [fileURL path]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSURL *fileURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; + NSString *path = [fileURL path]; NSString *attachmentFolder = [path stringByAppendingFormat:@"/Attachments"]; NSError * error = nil; @@ -46,7 +56,7 @@ if (error != nil) { DDLogError(@"Failed to create attachments directory: %@", error.description); } - + return attachmentFolder; } @@ -75,7 +85,7 @@ return nil; } - return [UIImage imageWithContentsOfFile:[self filePath]]; + return [UIImage imageWithContentsOfFile:self.filePath]; } @end diff --git a/Signal/src/textsecure/Messages/TSMessage.h b/Signal/src/textsecure/Messages/TSMessage.h index dd6c416c2..100be43e1 100644 --- a/Signal/src/textsecure/Messages/TSMessage.h +++ b/Signal/src/textsecure/Messages/TSMessage.h @@ -33,6 +33,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage){ - (void)addattachments:(NSArray*)attachments; - (void)addattachment:(NSString*)attachment; -- (BOOL)hasattachments; +- (BOOL)hasAttachments; @end diff --git a/Signal/src/textsecure/Messages/TSMessage.m b/Signal/src/textsecure/Messages/TSMessage.m index c6d8bb5a6..ac86d42fc 100644 --- a/Signal/src/textsecure/Messages/TSMessage.m +++ b/Signal/src/textsecure/Messages/TSMessage.m @@ -7,7 +7,9 @@ // #import "TSMessage.h" +#import "TSAttachment.h" +NSString * const TSAttachementsRelationshipEdgeName = @"TSAttachmentEdge"; @implementation TSMessage @@ -25,10 +27,25 @@ [self.attachments addObject:attachment]; } +- (NSArray *)yapDatabaseRelationshipEdges { + NSMutableArray *edges = [[super yapDatabaseRelationshipEdges] mutableCopy]; + + if ([self hasAttachments]) { + for (NSString *attachmentId in self.attachments) { + YapDatabaseRelationshipEdge *fileEdge = [[YapDatabaseRelationshipEdge alloc] initWithName:TSAttachementsRelationshipEdgeName + destinationKey:attachmentId + collection:[TSAttachment collection] + nodeDeleteRules:YDB_DeleteDestinationIfAllSourcesDeleted]; + [edges addObject:fileEdge]; + } + } + return edges; +} + - (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread*)thread messageBody:(NSString*)body - attachments:(NSArray*)attachments + attachments:(NSArray*)attachments { self = [super initWithTimestamp:timestamp inThread:thread]; @@ -39,13 +56,13 @@ return self; } -- (BOOL)hasattachments{ +- (BOOL)hasAttachments{ return self.attachments?(self.attachments.count>0):false; } - (NSString *)description{ if(self.attachments > 0){ - return @"attachment"; + return @"Attachment"; } else { return self.body; } diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m index 45d129fdd..11c9acca1 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m @@ -46,6 +46,7 @@ dispatch_queue_t attachmentsQueue() { for (PushMessageContentAttachmentPointer *pointer in content.attachments) { TSAttachmentPointer *attachmentPointer = [[TSAttachmentPointer alloc] initWithIdentifier:pointer.id key:pointer.key contentType:pointer.contentType relay:message.relay]; [attachmentPointer saveWithTransaction:transaction]; + dispatch_async(attachmentsQueue(), ^{ [self retrieveAttachment:attachmentPointer]; }); @@ -57,7 +58,7 @@ dispatch_queue_t attachmentsQueue() { } - (void)sendAttachment:(NSData*)attachmentData contentType:(NSString*)contentType thread:(TSThread*)thread { - + TSRequest *allocateAttachment = [[TSAllocAttachmentRequest alloc] init]; [[TSNetworkManager sharedManager] queueAuthenticatedRequest:allocateAttachment success:^(NSURLSessionDataTask *task, id responseObject) { dispatch_async(attachmentsQueue(), ^{ @@ -174,4 +175,5 @@ dispatch_queue_t attachmentsQueue() { return success; } + @end diff --git a/Signal/src/util/UIImage+normalizeImage.h b/Signal/src/util/UIImage+normalizeImage.h new file mode 100644 index 000000000..6f5746ebe --- /dev/null +++ b/Signal/src/util/UIImage+normalizeImage.h @@ -0,0 +1,15 @@ +// +// UIImage+normalizeImage.h +// Signal +// +// Created by Frederic Jacobs on 26/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import + +@interface UIImage (normalizeImage) + +- (UIImage *)normalizedImage; + +@end diff --git a/Signal/src/util/UIImage+normalizeImage.m b/Signal/src/util/UIImage+normalizeImage.m new file mode 100644 index 000000000..855f80df2 --- /dev/null +++ b/Signal/src/util/UIImage+normalizeImage.m @@ -0,0 +1,23 @@ +// +// UIImage+normalizeImage.m +// Signal +// +// Created by Frederic Jacobs on 26/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "UIImage+normalizeImage.h" + +@implementation UIImage (normalizeImage) + +- (UIImage *)normalizedImage { + if (self.imageOrientation == UIImageOrientationUp) return self; + + UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale); + [self drawInRect:(CGRect){0, 0, self.size}]; + UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return normalizedImage; +} + +@end diff --git a/Signal/src/util/UIUtil.h b/Signal/src/util/UIUtil.h index d9e2d2106..97d608655 100644 --- a/Signal/src/util/UIUtil.h +++ b/Signal/src/util/UIUtil.h @@ -2,6 +2,8 @@ #import "UIColor+OWS.h" #import "UIFont+OWS.h" +#import "UIImage+normalizeImage.h" +#import "UIImage+contentTypes.h" /** * diff --git a/Signal/src/util/UIUtil.m b/Signal/src/util/UIUtil.m index aadff305c..57e3c06ee 100644 --- a/Signal/src/util/UIUtil.m +++ b/Signal/src/util/UIUtil.m @@ -4,7 +4,6 @@ @implementation UIUtil - + (void)applyRoundedBorderToImageView:(UIImageView *__strong*)imageView { [[*imageView layer] setBorderWidth:CONTACT_PICTURE_VIEW_BORDER_WIDTH]; [[*imageView layer] setBorderColor:[[UIColor lightGrayColor] CGColor]]; diff --git a/Signal/src/view controllers/FullImageViewController.h b/Signal/src/view controllers/FullImageViewController.h index d3837070d..a63347cc5 100644 --- a/Signal/src/view controllers/FullImageViewController.h +++ b/Signal/src/view controllers/FullImageViewController.h @@ -7,11 +7,13 @@ // #import +#import "TSAttachmentStream.h" +#import "TSInteraction.h" @interface FullImageViewController : UIViewController -- (instancetype)initWithImage:(UIImage*)image fromRect:(CGRect)rect; +- (instancetype)initWithAttachment:(TSAttachmentStream*)attachment fromRect:(CGRect)rect forInteraction:(TSInteraction*)interaction; --(void)presentFromViewController:(UIViewController*)viewController; +- (void)presentFromViewController:(UIViewController*)viewController; @end diff --git a/Signal/src/view controllers/FullImageViewController.m b/Signal/src/view controllers/FullImageViewController.m index f2b6765d6..b6d82463e 100644 --- a/Signal/src/view controllers/FullImageViewController.m +++ b/Signal/src/view controllers/FullImageViewController.m @@ -8,6 +8,7 @@ #import "FullImageViewController.h" #import "DJWActionSheet.h" +#import "TSAttachmentStream.h" #define kImageViewCornerRadius 5.0f @@ -24,7 +25,6 @@ @property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic, strong) UIImageView *imageView; -@property (nonatomic, strong) UIImage* image; @property (nonatomic, strong) UITapGestureRecognizer *singleTap; @property (nonatomic, strong) UITapGestureRecognizer *doubleTap; @@ -34,23 +34,31 @@ @property CGRect originRect; @property BOOL isPresenting; +@property TSAttachmentStream *attachment; +@property TSInteraction *interaction; + @end @implementation FullImageViewController -- (instancetype)initWithImage:(UIImage*)image fromRect:(CGRect)rect { +- (instancetype)initWithAttachment:(TSAttachmentStream*)attachment fromRect:(CGRect)rect forInteraction:(TSInteraction*)interaction { self = [super initWithNibName:nil bundle:nil]; if (self) { - self.image = image; - self.imageView.image = image; - self.originRect = rect; + self.attachment = attachment; + self.imageView.image = self.image; + self.originRect = rect; + self.interaction = interaction; } return self; } +- (UIImage*)image{ + return self.attachment.image; +} + - (void)viewDidLoad { [super viewDidLoad]; @@ -353,11 +361,14 @@ { [DJWActionSheet showInView:self.view withTitle:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:@[@"Save to Camera Roll", @"Copy"] tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) { if (tappedButtonIndex == actionSheet.cancelButtonIndex) { + + } else if (tappedButtonIndex == actionSheet.destructiveButtonIndex){ + __block TSInteraction *interaction = [self interaction]; + [self dismissViewControllerAnimated:YES completion:^{ + [interaction remove]; + }]; - } else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) { - #warning Unimplemented deleting attachments from FullImageView - NSLog(@"Destructive button tapped"); - }else { + } else { switch (tappedButtonIndex) { case 0: UIImageWriteToSavedPhotosAlbum(self.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); diff --git a/Signal/src/view controllers/MessagesViewController.h b/Signal/src/view controllers/MessagesViewController.h index bb42cb900..adbfa6431 100644 --- a/Signal/src/view controllers/MessagesViewController.h +++ b/Signal/src/view controllers/MessagesViewController.h @@ -11,11 +11,12 @@ #import "GroupModel.h" @class TSThread; -@interface MessagesViewController : JSQMessagesViewController +@interface MessagesViewController : JSQMessagesViewController - (void)setupWithThread:(TSThread*)thread; - (void)setupWithTSIdentifier:(NSString*)identifier; - (void)setupWithTSGroup:(GroupModel*)model; - @end diff --git a/Signal/src/view controllers/MessagesViewController.m b/Signal/src/view controllers/MessagesViewController.m index 5dcda79d5..536507f52 100644 --- a/Signal/src/view controllers/MessagesViewController.m +++ b/Signal/src/view controllers/MessagesViewController.m @@ -133,7 +133,6 @@ typedef enum : NSUInteger { -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - self.automaticallyScrollsToMostRecentMessage = YES; [self scrollToBottomAnimated:NO]; } @@ -164,7 +163,7 @@ typedef enum : NSUInteger { -(void)initializeNavigationBar { self.title = self.thread.name; - + if (!isGroupConversation && [self isRedPhoneReachable]) { UIBarButtonItem * lockButton = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"lock"] style:UIBarButtonItemStylePlain target:self action:@selector(showFingerprint)]; UIBarButtonItem * callButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"call_tab"] style:UIBarButtonItemStylePlain target:self action:@selector(callAction)]; @@ -197,7 +196,7 @@ typedef enum : NSUInteger { self.collectionView.showsVerticalScrollIndicator = NO; self.collectionView.showsHorizontalScrollIndicator = NO; - self.automaticallyScrollsToMostRecentMessage = NO; + self.automaticallyScrollsToMostRecentMessage = YES; self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero; self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero; @@ -298,24 +297,18 @@ typedef enum : NSUInteger { switch (msg.messageType) { case TSIncomingMessageAdapter: return [self loadIncomingMessageCellForMessage:msg atIndexPath:indexPath]; - break; case TSOutgoingMessageAdapter: return [self loadOutgoingCellForMessage:msg atIndexPath:indexPath]; - break; case TSCallAdapter: return [self loadCallCellForCall:msg atIndexPath:indexPath]; - break; case TSInfoMessageAdapter: return [self loadInfoMessageCellForMessage:msg atIndexPath:indexPath]; - break; case TSErrorMessageAdapter: return [self loadErrorMessageCellForMessage:msg atIndexPath:indexPath]; - break; default: NSLog(@"Something went wrong"); return nil; - break; } } @@ -325,7 +318,8 @@ typedef enum : NSUInteger { { JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath]; if (!message.isMediaMessage) { - cell.textView.textColor = [UIColor blackColor]; + cell.textView.textColor = [UIColor blackColor]; + cell.textView.selectable = NO; cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; } @@ -338,7 +332,8 @@ typedef enum : NSUInteger { JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath]; if (!message.isMediaMessage) { - cell.textView.textColor = [UIColor whiteColor]; + cell.textView.textColor = [UIColor whiteColor]; + cell.textView.selectable = NO; cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor, NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) }; } @@ -497,6 +492,7 @@ 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) { @@ -507,15 +503,21 @@ typedef enum : NSUInteger { BOOL isMediaMessage = [messageItem isMediaMessage]; if (isMediaMessage) { - TSAttachmentAdapter * messageMedia = (TSAttachmentAdapter*)[messageItem media]; + TSAttachmentAdapter* messageMedia = (TSAttachmentAdapter*)[messageItem media]; if ([messageMedia isImage]) { - //is a photo - tappedImage = ((UIImageView*)[messageMedia mediaView]).image ; + tappedImage = ((UIImageView*)[messageMedia mediaView]).image; CGRect convertedRect = [self.collectionView convertRect:[collectionView cellForItemAtIndexPath:indexPath].frame toView:nil]; - FullImageViewController * vc = [[FullImageViewController alloc]initWithImage:tappedImage fromRect:convertedRect]; - [vc presentFromViewController:self]; + __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; + FullImageViewController * vc = [[FullImageViewController alloc] initWithAttachment:attStream fromRect:convertedRect forInteraction:[self interactionAtIndexPath:indexPath]]; + [vc presentFromViewController:self]; + } } else { DDLogWarn(@"Currently unsupported"); } @@ -550,6 +552,13 @@ typedef enum : NSUInteger { }]; } +- (void)deleteMessageAtIndexPath:(NSIndexPath*)indexPath { + [self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + TSInteraction *interaction = [self interactionAtIndexPath:indexPath]; + [interaction removeWithTransaction:transaction]; + }]; +} + - (void)handleErrorMessageTap:(TSErrorMessage*)message{ if (message.errorType == TSErrorMessageWrongTrustedIdentityKey) { NSString *newKeyFingerprint = [message newIdentityKey]; @@ -615,9 +624,8 @@ typedef enum : NSUInteger { picker.sourceType = UIImagePickerControllerSourceTypeCamera; if ([UIImagePickerController isSourceTypeAvailable: - UIImagePickerControllerSourceTypeCamera]) - { - picker.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *)kUTTypeMovie, kUTTypeImage, kUTTypeVideo, nil]; + UIImagePickerControllerSourceTypeCamera]) { + picker.mediaTypes = @[(NSString*)kUTTypeImage]; [self presentViewController:picker animated:YES completion:NULL]; } @@ -655,7 +663,7 @@ typedef enum : NSUInteger { -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { - UIImage *picture_camera = [info objectForKey:UIImagePickerControllerOriginalImage]; + UIImage *picture_camera = [[info objectForKey:UIImagePickerControllerOriginalImage] normalizedImage]; NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType]; @@ -680,6 +688,9 @@ typedef enum : NSUInteger { { CGFloat correctedWidth; switch ([Environment.preferences imageUploadQuality]) { + case TSImageQualityUncropped: + return image; + case TSImageQualityHigh: correctedWidth = 2048; break; @@ -721,15 +732,14 @@ typedef enum : NSUInteger { -(CGFloat)compressionRate { switch ([Environment.preferences imageUploadQuality]) { + case TSImageQualityUncropped: + return 1; case TSImageQualityHigh: return 0.9f; - break; case TSImageQualityMedium: return 0.5f; - break; case TSImageQualityLow: return 0.3f; - break; default: break; } @@ -853,7 +863,7 @@ typedef enum : NSUInteger { withTitle:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil - otherButtonTitles:@[@"Update group", @"Leave group", @"Delete thread"] + otherButtonTitles:@[@"Update group", @"Leave group"] tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) { if (tappedButtonIndex == actionSheet.cancelButtonIndex) { NSLog(@"User Cancelled"); @@ -867,12 +877,9 @@ typedef enum : NSUInteger { break; case 1: - DDLogDebug(@"leave group picket"); + DDLogDebug(@"leave group picked"); break; - case 2: - DDLogDebug(@"delete thread"); - break; - + default: break; } @@ -893,12 +900,12 @@ typedef enum : NSUInteger { withTitle:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil - otherButtonTitles:@[@"Take Photo or Video", @"Choose existing Photo", @"Choose existing Video", @"Send file"] + otherButtonTitles:@[@"Take Photo", @"Choose existing Photo"] tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) { if (tappedButtonIndex == actionSheet.cancelButtonIndex) { - NSLog(@"User Cancelled"); + DDLogVerbose(@"User Cancelled"); } else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) { - NSLog(@"Destructive button tapped"); + DDLogVerbose(@"Destructive button tapped"); }else { switch (tappedButtonIndex) { case 0: @@ -907,10 +914,6 @@ typedef enum : NSUInteger { case 1: [self chooseFromLibrary:kMediaTypePicture]; break; - case 2: - [self chooseFromLibrary:kMediaTypeVideo]; - break; - default: break; } @@ -932,6 +935,26 @@ typedef enum : NSUInteger { }]; } + +- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender +{ + if (action == @selector(delete:)) { + return YES; + } + + return [super collectionView:collectionView canPerformAction:action forItemAtIndexPath:indexPath withSender:sender]; +} + +- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender +{ + if (action == @selector(delete:)) { + [self deleteMessageAtIndexPath:indexPath]; + } + else { + [super collectionView:collectionView performAction:action forItemAtIndexPath:indexPath withSender:sender]; + } +} + - (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self]; } diff --git a/Signal/src/view controllers/SettingsTableViewCell.m b/Signal/src/view controllers/SettingsTableViewCell.m index 65a7fbc82..3724e4956 100644 --- a/Signal/src/view controllers/SettingsTableViewCell.m +++ b/Signal/src/view controllers/SettingsTableViewCell.m @@ -43,6 +43,9 @@ -(void)updateImageQualityLabel { switch ([Environment.preferences imageUploadQuality]) { + case TSImageQualityUncropped: + self.detailLabel.text = @"Full"; + break; case TSImageQualityHigh: self.detailLabel.text = @"High"; break; diff --git a/Signal/src/view controllers/SettingsTableViewController.m b/Signal/src/view controllers/SettingsTableViewController.m index 471932411..be8b6a1d4 100644 --- a/Signal/src/view controllers/SettingsTableViewController.m +++ b/Signal/src/view controllers/SettingsTableViewController.m @@ -125,7 +125,7 @@ typedef enum { withTitle:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil - otherButtonTitles:@[@"High", @"Medium", @"Low"] + otherButtonTitles:@[@"Uncompressed", @"High", @"Medium", @"Low"] tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) { [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; if (tappedButtonIndex == actionSheet.cancelButtonIndex) { @@ -136,12 +136,15 @@ typedef enum { }else { switch (tappedButtonIndex) { case 0: - [Environment.preferences setImageUploadQuality:TSImageQualityHigh]; + [Environment.preferences setImageUploadQuality:TSImageQualityUncropped]; break; case 1: - [Environment.preferences setImageUploadQuality:TSImageQualityMedium]; + [Environment.preferences setImageUploadQuality:TSImageQualityHigh]; break; case 2: + [Environment.preferences setImageUploadQuality:TSImageQualityMedium]; + break; + case 3: [Environment.preferences setImageUploadQuality:TSImageQualityLow]; break; default: diff --git a/Signal/src/view controllers/TSAttachmentAdapter.h b/Signal/src/view controllers/TSAttachmentAdapter.h index f3765867a..1e8c0a889 100644 --- a/Signal/src/view controllers/TSAttachmentAdapter.h +++ b/Signal/src/view controllers/TSAttachmentAdapter.h @@ -16,4 +16,6 @@ - (BOOL)isImage; +@property NSString *attachmentId; + @end diff --git a/Signal/src/view controllers/TSAttachmentAdapter.m b/Signal/src/view controllers/TSAttachmentAdapter.m index 917d9e3e1..c5c1babbd 100644 --- a/Signal/src/view controllers/TSAttachmentAdapter.m +++ b/Signal/src/view controllers/TSAttachmentAdapter.m @@ -16,8 +16,6 @@ @property UIImage *image; @property (strong, nonatomic) UIImageView *cachedImageView; -@property (assign, nonatomic, readonly) BOOL isImageAttachment; - @end @implementation TSAttachmentAdapter @@ -26,9 +24,9 @@ self = [super init]; if (self) { - _image = [UIImage imageWithCGImage:attachment.image.CGImage]; + _image = attachment.image; _cachedImageView = nil; - _isImageAttachment = YES; + _attachmentId = attachment.uniqueId; } return self; } @@ -73,7 +71,7 @@ -(BOOL)isImage { - return _isImageAttachment; + return YES; } #pragma mark - Utility @@ -100,7 +98,6 @@ return ratio > 1.0f ? [self smallPortraitSize] : [self smallLandscapeSize]; } - - (CGSize)largePortraitSize { return CGSizeMake(220.0f, 310.0f); diff --git a/Signal/src/view controllers/TSMessageAdapter.m b/Signal/src/view controllers/TSMessageAdapter.m index 8c661dd41..09ea9de6e 100644 --- a/Signal/src/view controllers/TSMessageAdapter.m +++ b/Signal/src/view controllers/TSMessageAdapter.m @@ -15,6 +15,7 @@ #import "TSattachment.h" #import "TSAttachmentStream.h" #import "TSAttachmentAdapter.h" +#import "TSAttachmentPointer.h" @interface TSMessageAdapter () @@ -92,13 +93,23 @@ for (NSString *attachmentID in message.attachments) { TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentID]; - + if ([attachment isKindOfClass:[TSAttachmentStream class]]) { TSAttachmentStream *stream = (TSAttachmentStream*)attachment; if ([stream isImage]) { adapter.mediaItem = [[TSAttachmentAdapter alloc] initWithAttachment:stream]; adapter.mediaItem.appliesMediaViewMaskAsOutgoing = [interaction isKindOfClass:[TSOutgoingMessage class]]; + break; + } else { + DDLogWarn(@"We have a TSAttachmentStream for an unsupported media type"); } + } else if ([attachment isKindOfClass:[TSAttachmentPointer class]]){ + //TSAttachmentPointer *pointer = (TSAttachmentPointer*)attachment; + //TODO: Change this status when download failed; + adapter.messageBody = @"Attachment is downloading"; + adapter.messageType = TSInfoMessageAdapter; + } else { + DDLogError(@"We retreived an attachment that doesn't have a known type : %@", NSStringFromClass([attachment class])); } } } diff --git a/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.h b/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.h new file mode 100644 index 000000000..1baf6cb26 --- /dev/null +++ b/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.h @@ -0,0 +1,13 @@ +// +// JSQMessagesCollectionViewCell+menuBarItems.h +// Signal +// +// Created by Frederic Jacobs on 26/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "JSQMessagesCollectionViewCell.h" + +@interface JSQMessagesCollectionViewCell (menuBarItems) + +@end diff --git a/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.m b/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.m new file mode 100644 index 000000000..958d02e27 --- /dev/null +++ b/Signal/src/views/JSQMessagesCollectionViewCell+menuBarItems.m @@ -0,0 +1,49 @@ +// +// JSQMessagesCollectionViewCell+menuBarItems.m +// Signal +// +// Created by Frederic Jacobs on 26/12/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "JSQMessagesCollectionViewCell+menuBarItems.h" + +@implementation JSQMessagesCollectionViewCell (menuBarItems) + +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender +{ + if (action == @selector(delete:)) { + return YES; + } + + return [super canPerformAction:action withSender:sender]; +} + +- (void)delete:(id)sender +{ + [self performSelectorOnParentCollectionView:@selector(delete:) + withSender:sender]; +} + +- (void)performSelectorOnParentCollectionView:(SEL)selector + withSender:(id)sender { + UIView *view = self; + do { + view = view.superview; + } while (![view isKindOfClass:[UICollectionView class]]); + UICollectionView *collectionView = (UICollectionView *)view; + NSIndexPath *indexPath = [collectionView indexPathForCell:self]; + + if (collectionView.delegate && + [collectionView.delegate respondsToSelector:@selector(collectionView: + performAction: + forItemAtIndexPath: + withSender:)]) + + [collectionView.delegate collectionView:collectionView + performAction:selector + forItemAtIndexPath:indexPath + withSender:sender]; +} + +@end