mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Attachments handling
- Sends image rotated - If message is delete, delete the attachment db object and file - Delete attachment from detail view
This commit is contained in:
parent
f2217cacd7
commit
402df72306
24 changed files with 275 additions and 81 deletions
|
@ -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 = "<group>"; };
|
||||
B67ADDC31989FF8700E1A773 /* RPServerRequestsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RPServerRequestsManager.m; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
B68112E91A4D9EC400BA82FF /* UIImage+normalizeImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImage+normalizeImage.m"; path = "util/UIImage+normalizeImage.m"; sourceTree = "<group>"; };
|
||||
B68112EB1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "JSQMessagesCollectionViewCell+menuBarItems.h"; path = "views/JSQMessagesCollectionViewCell+menuBarItems.h"; sourceTree = "<group>"; };
|
||||
B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "JSQMessagesCollectionViewCell+menuBarItems.m"; path = "views/JSQMessagesCollectionViewCell+menuBarItems.m"; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 */,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
if (preference) {
|
||||
return [preference unsignedIntegerValue];
|
||||
} else {
|
||||
return TSImageQualityMedium;
|
||||
return TSImageQualityUncropped;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <YapDatabase/YapDatabaseRelationshipNode.h>
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, TSLastActionType) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#import "TSAttachment.h"
|
||||
|
||||
@interface TSAttachmentStream : TSAttachment
|
||||
@interface TSAttachmentStream : TSAttachment <YapDatabaseRelationshipNode>
|
||||
|
||||
- (instancetype)initWithIdentifier:(NSString*)identifier
|
||||
data:(NSData*)data
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -33,6 +33,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage){
|
|||
|
||||
- (void)addattachments:(NSArray*)attachments;
|
||||
- (void)addattachment:(NSString*)attachment;
|
||||
- (BOOL)hasattachments;
|
||||
- (BOOL)hasAttachments;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
15
Signal/src/util/UIImage+normalizeImage.h
Normal file
15
Signal/src/util/UIImage+normalizeImage.h
Normal file
|
@ -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 <UIKit/UIKit.h>
|
||||
|
||||
@interface UIImage (normalizeImage)
|
||||
|
||||
- (UIImage *)normalizedImage;
|
||||
|
||||
@end
|
23
Signal/src/util/UIImage+normalizeImage.m
Normal file
23
Signal/src/util/UIImage+normalizeImage.m
Normal file
|
@ -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
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIImage+normalizeImage.h"
|
||||
#import "UIImage+contentTypes.h"
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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]];
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
#import "GroupModel.h"
|
||||
@class TSThread;
|
||||
|
||||
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate,UINavigationControllerDelegate>
|
||||
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate,
|
||||
UINavigationControllerDelegate,
|
||||
UITextViewDelegate>
|
||||
|
||||
- (void)setupWithThread:(TSThread*)thread;
|
||||
- (void)setupWithTSIdentifier:(NSString*)identifier;
|
||||
- (void)setupWithTSGroup:(GroupModel*)model;
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
-(void)updateImageQualityLabel
|
||||
{
|
||||
switch ([Environment.preferences imageUploadQuality]) {
|
||||
case TSImageQualityUncropped:
|
||||
self.detailLabel.text = @"Full";
|
||||
break;
|
||||
case TSImageQualityHigh:
|
||||
self.detailLabel.text = @"High";
|
||||
break;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -16,4 +16,6 @@
|
|||
|
||||
- (BOOL)isImage;
|
||||
|
||||
@property NSString *attachmentId;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in a new issue