Add progress & disable media views while uploading attachments.
// FREEBIE
This commit is contained in:
parent
3dc7f2528f
commit
9ae047a1da
|
@ -12,6 +12,8 @@
|
|||
34330A5A1E7875FB00DF2FB9 /* fontawesome-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A591E7875FB00DF2FB9 /* fontawesome-webfont.ttf */; };
|
||||
34330A5C1E787A9800DF2FB9 /* dripicons-v2.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A5B1E787A9800DF2FB9 /* dripicons-v2.ttf */; };
|
||||
34330A5E1E787BD800DF2FB9 /* ElegantIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A5D1E787BD800DF2FB9 /* ElegantIcons.ttf */; };
|
||||
34330A611E788EA900DF2FB9 /* AttachmentUploadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34330A601E788EA900DF2FB9 /* AttachmentUploadView.m */; };
|
||||
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34330AA21E79686200DF2FB9 /* OWSProgressView.m */; };
|
||||
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 */; };
|
||||
348A08421E6A044E0057E290 /* MessagesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348A08411E6A044E0057E290 /* MessagesViewController.xib */; };
|
||||
|
@ -631,6 +633,10 @@
|
|||
34330A591E7875FB00DF2FB9 /* fontawesome-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "fontawesome-webfont.ttf"; sourceTree = "<group>"; };
|
||||
34330A5B1E787A9800DF2FB9 /* dripicons-v2.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "dripicons-v2.ttf"; sourceTree = "<group>"; };
|
||||
34330A5D1E787BD800DF2FB9 /* ElegantIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ElegantIcons.ttf; sourceTree = "<group>"; };
|
||||
34330A5F1E788EA900DF2FB9 /* AttachmentUploadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AttachmentUploadView.h; sourceTree = "<group>"; };
|
||||
34330A601E788EA900DF2FB9 /* AttachmentUploadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AttachmentUploadView.m; sourceTree = "<group>"; };
|
||||
34330AA11E79686200DF2FB9 /* OWSProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProgressView.h; sourceTree = "<group>"; };
|
||||
34330AA21E79686200DF2FB9 /* OWSProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProgressView.m; sourceTree = "<group>"; };
|
||||
344F2F651E57A932000D9322 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+OWS.h"; path = "util/UIViewController+OWS.h"; sourceTree = "<group>"; };
|
||||
344F2F661E57A932000D9322 /* UIViewController+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+OWS.m"; path = "util/UIViewController+OWS.m"; sourceTree = "<group>"; };
|
||||
34535D801E256BE9008A4747 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+OWS.h"; sourceTree = "<group>"; };
|
||||
|
@ -2105,38 +2111,40 @@
|
|||
76EB052B18170B33006006FC /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
45F3AEB51DFDE7900080CE33 /* AvatarImageView.swift */,
|
||||
451764291DE939FD00EDB8B9 /* ContactCell.swift */,
|
||||
451764281DE939FD00EDB8B9 /* ContactCell.xib */,
|
||||
76EB052E18170B33006006FC /* ContactTableViewCell.h */,
|
||||
76EB052F18170B33006006FC /* ContactTableViewCell.m */,
|
||||
A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */,
|
||||
A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */,
|
||||
45B201751DAECBFE00C461E0 /* HighlightableLabel.swift */,
|
||||
45C681C11D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.h */,
|
||||
45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */,
|
||||
45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */,
|
||||
FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */,
|
||||
FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */,
|
||||
4531C9C21DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.h */,
|
||||
4531C9C31DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.m */,
|
||||
45E1F3A41DEF20A100852CF1 /* NoSignalContactsView.swift */,
|
||||
45E1F3A21DEF1DF000852CF1 /* NoSignalContactsView.xib */,
|
||||
45C681B91D305C080050903A /* OWSCallCollectionViewCell.h */,
|
||||
45C681BA1D305C080050903A /* OWSCallCollectionViewCell.m */,
|
||||
45C681C01D305C9E0050903A /* OWSCallCollectionViewCell.xib */,
|
||||
459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */,
|
||||
459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */,
|
||||
45C681C11D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.h */,
|
||||
45C681C21D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m */,
|
||||
45C681C31D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.xib */,
|
||||
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */,
|
||||
450873C11D9D5149006B54F2 /* OWSExpirationTimerView.h */,
|
||||
450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */,
|
||||
450873C51D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.h */,
|
||||
450873C61D9D867B006B54F2 /* OWSIncomingMessageCollectionViewCell.m */,
|
||||
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */,
|
||||
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */,
|
||||
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */,
|
||||
45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */,
|
||||
A5509ECB1A69B1D600ABA4BC /* CountryCodeTableViewCell.h */,
|
||||
A5509ECC1A69B1D600ABA4BC /* CountryCodeTableViewCell.m */,
|
||||
FCAC963D19FEF99A0046DFC5 /* InboxTableViewCell.h */,
|
||||
FCAC963E19FEF99A0046DFC5 /* InboxTableViewCell.m */,
|
||||
76EB052E18170B33006006FC /* ContactTableViewCell.h */,
|
||||
76EB052F18170B33006006FC /* ContactTableViewCell.m */,
|
||||
451764291DE939FD00EDB8B9 /* ContactCell.swift */,
|
||||
451764281DE939FD00EDB8B9 /* ContactCell.xib */,
|
||||
34330AA11E79686200DF2FB9 /* OWSProgressView.h */,
|
||||
34330AA21E79686200DF2FB9 /* OWSProgressView.m */,
|
||||
76EB053818170B33006006FC /* xibs */,
|
||||
459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */,
|
||||
459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */,
|
||||
450873C11D9D5149006B54F2 /* OWSExpirationTimerView.h */,
|
||||
450873C21D9D5149006B54F2 /* OWSExpirationTimerView.m */,
|
||||
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */,
|
||||
4531C9C21DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.h */,
|
||||
4531C9C31DD8E6D800F08304 /* JSQMessagesCollectionViewCell+OWS.m */,
|
||||
45E1F3A21DEF1DF000852CF1 /* NoSignalContactsView.xib */,
|
||||
45E1F3A41DEF20A100852CF1 /* NoSignalContactsView.swift */,
|
||||
45F3AEB51DFDE7900080CE33 /* AvatarImageView.swift */,
|
||||
);
|
||||
name = Views;
|
||||
path = views;
|
||||
|
@ -2173,19 +2181,21 @@
|
|||
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A5E9D4BA1A65FAD800E4481C /* TSVideoAttachmentAdapter.h */,
|
||||
A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */,
|
||||
B6A3EB491A423B3800B2236B /* TSPhotoAdapter.h */,
|
||||
B6A3EB4A1A423B3800B2236B /* TSPhotoAdapter.m */,
|
||||
4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */,
|
||||
4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */,
|
||||
B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */,
|
||||
B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */,
|
||||
B6D3CBCE1C1376BE00C039DF /* TSContentAdapters.h */,
|
||||
34330A5F1E788EA900DF2FB9 /* AttachmentUploadView.h */,
|
||||
34330A601E788EA900DF2FB9 /* AttachmentUploadView.m */,
|
||||
341BB7471DB727EE001E2975 /* JSQMediaItem+OWS.h */,
|
||||
341BB7481DB727EE001E2975 /* JSQMediaItem+OWS.m */,
|
||||
4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */,
|
||||
45666ECE1D995B94008FE134 /* OWSMessageData.h */,
|
||||
4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */,
|
||||
4CE0E3751B95453C007210CF /* TSAnimatedAdapter.h */,
|
||||
4CE0E3761B954546007210CF /* TSAnimatedAdapter.m */,
|
||||
B6D3CBCE1C1376BE00C039DF /* TSContentAdapters.h */,
|
||||
B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */,
|
||||
B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */,
|
||||
B6A3EB491A423B3800B2236B /* TSPhotoAdapter.h */,
|
||||
B6A3EB4A1A423B3800B2236B /* TSPhotoAdapter.m */,
|
||||
A5E9D4BA1A65FAD800E4481C /* TSVideoAttachmentAdapter.h */,
|
||||
A5E9D4B91A65FAD800E4481C /* TSVideoAttachmentAdapter.m */,
|
||||
);
|
||||
name = TSMessageAdapters;
|
||||
path = TSMessageAdapaters;
|
||||
|
@ -3262,6 +3272,7 @@
|
|||
B63761ED19E1FBE8005735D1 /* HttpRequestOrResponse.m in Sources */,
|
||||
76EB05A018170B33006006FC /* IpAddress.m in Sources */,
|
||||
FCAC965119FF0A6E0046DFC5 /* MessagesViewController.m in Sources */,
|
||||
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
|
||||
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
|
||||
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */,
|
||||
B68EF9BB1C0B1EBD009C3DCD /* FLAnimatedImageView.m in Sources */,
|
||||
|
@ -3371,6 +3382,7 @@
|
|||
45C681BC1D305C080050903A /* OWSCallCollectionViewCell.m in Sources */,
|
||||
76EB064018170B33006006FC /* AnonymousTerminator.m in Sources */,
|
||||
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */,
|
||||
34330A611E788EA900DF2FB9 /* AttachmentUploadView.m in Sources */,
|
||||
76EB05B218170B33006006FC /* DH3KKeyAgreementProtocol.m in Sources */,
|
||||
B63761EC19E1FBE8005735D1 /* HttpRequest.m in Sources */,
|
||||
45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@class TSAttachmentStream;
|
||||
|
||||
typedef void (^AttachmentStateBlock)(BOOL isAttachmentReady);
|
||||
|
||||
// This entity is used by various attachment adapters to
|
||||
// coordinate view state with attachment uploads.
|
||||
// During attachment uploads we want to:
|
||||
//
|
||||
// * Dim the media view using a mask layer.
|
||||
// * Show and update a progress bar.
|
||||
// * Disable any media view controls using a callback.
|
||||
@interface AttachmentUploadView : NSObject
|
||||
|
||||
@property (nonatomic, readonly) TSAttachmentStream *attachment;
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment
|
||||
superview:(UIView *)superview
|
||||
attachmentStateCallback:(AttachmentStateBlock)attachmentStateCallback;
|
||||
|
||||
@end
|
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AttachmentUploadView.h"
|
||||
#import "OWSProgressView.h"
|
||||
#import "OWSUploadingService.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
|
||||
@interface AttachmentUploadView ()
|
||||
|
||||
@property (nonatomic) TSAttachmentStream *attachment;
|
||||
|
||||
@property (nonatomic) OWSProgressView *progressView;
|
||||
|
||||
@property (nonatomic) CALayer *maskLayer;
|
||||
|
||||
@property (nonatomic) AttachmentStateBlock attachmentStateCallback;
|
||||
|
||||
@property (nonatomic) BOOL isAttachmentReady;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AttachmentUploadView
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment
|
||||
superview:(UIView *)superview
|
||||
attachmentStateCallback:(AttachmentStateBlock)attachmentStateCallback
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
OWSAssert(attachment);
|
||||
OWSAssert(superview);
|
||||
|
||||
self.attachment = attachment;
|
||||
self.attachmentStateCallback = attachmentStateCallback;
|
||||
|
||||
_maskLayer = [CALayer layer];
|
||||
[_maskLayer setBackgroundColor:[UIColor blackColor].CGColor];
|
||||
[_maskLayer setOpacity:0.4f];
|
||||
[_maskLayer setFrame:superview.frame];
|
||||
[superview.layer addSublayer:_maskLayer];
|
||||
|
||||
const CGFloat progressWidth = round(superview.frame.size.width * 0.45f);
|
||||
const CGFloat progressHeight = round(progressWidth * 0.11f);
|
||||
CGRect progressFrame = CGRectMake(round((superview.frame.size.width - progressWidth) * 0.5f),
|
||||
round((superview.frame.size.height - progressHeight) * 0.5f),
|
||||
progressWidth,
|
||||
progressHeight);
|
||||
// The progress view is white. It will only be shown
|
||||
// while the mask layer is visible, so it will show up
|
||||
// even against all-white attachments.
|
||||
_progressView = [OWSProgressView new];
|
||||
_progressView.color = [UIColor whiteColor];
|
||||
_progressView.frame = progressFrame;
|
||||
[superview addSubview:_progressView];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(attachmentUploadProgress:)
|
||||
name:kAttachmentUploadProgressNotification
|
||||
object:nil];
|
||||
|
||||
_isAttachmentReady = self.attachment.isUploaded;
|
||||
|
||||
[self ensureViewState];
|
||||
|
||||
if (attachmentStateCallback) {
|
||||
self.attachmentStateCallback(_isAttachmentReady);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)setIsAttachmentReady:(BOOL)isAttachmentReady
|
||||
{
|
||||
if (_isAttachmentReady == isAttachmentReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isAttachmentReady = isAttachmentReady;
|
||||
|
||||
[self ensureViewState];
|
||||
|
||||
if (self.attachmentStateCallback) {
|
||||
self.attachmentStateCallback(isAttachmentReady);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ensureViewState
|
||||
{
|
||||
_maskLayer.hidden = self.isAttachmentReady;
|
||||
_progressView.hidden = self.isAttachmentReady;
|
||||
}
|
||||
|
||||
- (void)attachmentUploadProgress:(NSNotification *)notification
|
||||
{
|
||||
NSDictionary *userinfo = [notification userInfo];
|
||||
double progress = [[userinfo objectForKey:kAttachmentUploadProgressKey] doubleValue];
|
||||
NSString *attachmentID = [userinfo objectForKey:kAttachmentUploadAttachmentIDKey];
|
||||
if ([self.attachment.uniqueId isEqualToString:attachmentID]) {
|
||||
if (!isnan(progress)) {
|
||||
[_progressView setProgress:(float)progress];
|
||||
self.isAttachmentReady = self.attachment.isUploaded;
|
||||
} else {
|
||||
self.isAttachmentReady = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,9 +1,5 @@
|
|||
//
|
||||
// TSAnimatedAdapter.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Mike Okner (@mikeokner) on 2015-09-01.
|
||||
// Copyright (c) 2015 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSMessageEditing.h"
|
||||
|
@ -13,7 +9,7 @@
|
|||
|
||||
@interface TSAnimatedAdapter : JSQMediaItem <OWSMessageEditing>
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment;
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
|
||||
|
||||
- (BOOL)isImage;
|
||||
- (BOOL)isAudio;
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
//
|
||||
// TSAnimatedAdapter.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Mike Okner (@mikeokner) on 2015-09-01.
|
||||
// Copyright (c) 2015 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSAnimatedAdapter.h"
|
||||
#import "AttachmentUploadView.h"
|
||||
#import "FLAnimatedImage.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import "JSQMediaItem+OWS.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
|
||||
@interface TSAnimatedAdapter ()
|
||||
|
||||
@property (strong, nonatomic) UIImageView *cachedImageView;
|
||||
@property (strong, nonatomic) UIImage *image;
|
||||
@property (strong, nonatomic) TSAttachmentStream *attachment;
|
||||
@property (nonatomic) UIImageView *cachedImageView;
|
||||
@property (nonatomic) UIImage *image;
|
||||
@property (nonatomic) TSAttachmentStream *attachment;
|
||||
@property (nonatomic) AttachmentUploadView *attachmentUploadView;
|
||||
@property (nonatomic) BOOL incoming;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TSAnimatedAdapter
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment {
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
|
@ -33,6 +33,7 @@
|
|||
_attachmentId = attachment.uniqueId;
|
||||
_image = [attachment image];
|
||||
_fileData = [NSData dataWithContentsOfURL:[attachment mediaURL]];
|
||||
_incoming = incoming;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -78,6 +79,12 @@
|
|||
[JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView
|
||||
isOutgoing:self.appliesMediaViewMaskAsOutgoing];
|
||||
self.cachedImageView = imageView;
|
||||
|
||||
if (!self.incoming) {
|
||||
self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment
|
||||
superview:imageView
|
||||
attachmentStateCallback:nil];
|
||||
}
|
||||
}
|
||||
|
||||
return self.cachedImageView;
|
||||
|
|
|
@ -127,15 +127,19 @@
|
|||
for (NSString *attachmentID in message.attachmentIds) {
|
||||
TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentID];
|
||||
|
||||
BOOL isIncomingAttachment = [interaction isKindOfClass:[TSIncomingMessage class]];
|
||||
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
TSAttachmentStream *stream = (TSAttachmentStream *)attachment;
|
||||
if ([stream isAnimated]) {
|
||||
adapter.mediaItem = [[TSAnimatedAdapter alloc] initWithAttachment:stream];
|
||||
adapter.mediaItem =
|
||||
[[TSAnimatedAdapter alloc] initWithAttachment:stream incoming:isIncomingAttachment];
|
||||
adapter.mediaItem.appliesMediaViewMaskAsOutgoing =
|
||||
[interaction isKindOfClass:[TSOutgoingMessage class]];
|
||||
break;
|
||||
} else if ([stream isImage]) {
|
||||
adapter.mediaItem = [[TSPhotoAdapter alloc] initWithAttachment:stream];
|
||||
adapter.mediaItem =
|
||||
[[TSPhotoAdapter alloc] initWithAttachment:stream incoming:isIncomingAttachment];
|
||||
adapter.mediaItem.appliesMediaViewMaskAsOutgoing =
|
||||
[interaction isKindOfClass:[TSOutgoingMessage class]];
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// 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 <JSQMessagesViewController/JSQPhotoMediaItem.h>
|
||||
|
@ -8,7 +9,7 @@
|
|||
|
||||
@interface TSPhotoAdapter : JSQPhotoMediaItem <OWSMessageEditing>
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment;
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
|
||||
|
||||
- (BOOL)isImage;
|
||||
- (BOOL)isAudio;
|
||||
|
|
|
@ -3,18 +3,23 @@
|
|||
//
|
||||
|
||||
#import "TSPhotoAdapter.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import "AttachmentUploadView.h"
|
||||
#import "JSQMediaItem+OWS.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
|
||||
|
||||
@interface TSPhotoAdapter ()
|
||||
|
||||
@property (strong, nonatomic) UIImageView *cachedImageView;
|
||||
@property (nonatomic) UIImageView *cachedImageView;
|
||||
@property (nonatomic) AttachmentUploadView *attachmentUploadView;
|
||||
@property (nonatomic) BOOL incoming;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TSPhotoAdapter
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment {
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming
|
||||
{
|
||||
self = [super initWithImage:attachment.image];
|
||||
|
||||
if (!self) {
|
||||
|
@ -24,6 +29,7 @@
|
|||
_cachedImageView = nil;
|
||||
_attachment = attachment;
|
||||
_attachmentId = attachment.uniqueId;
|
||||
_incoming = incoming;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -58,6 +64,12 @@
|
|||
[JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:imageView
|
||||
isOutgoing:self.appliesMediaViewMaskAsOutgoing];
|
||||
self.cachedImageView = imageView;
|
||||
|
||||
if (!self.incoming) {
|
||||
self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment
|
||||
superview:imageView
|
||||
attachmentStateCallback:nil];
|
||||
}
|
||||
}
|
||||
|
||||
return self.cachedImageView;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
// 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 "TSVideoAttachmentAdapter.h"
|
||||
#import "AttachmentUploadView.h"
|
||||
#import "JSQMediaItem+OWS.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import "TSMessagesManager.h"
|
||||
#import "TSStorageManager+keyingMaterial.h"
|
||||
#import "JSQMediaItem+OWS.h"
|
||||
#import <FFCircularProgressView.h>
|
||||
#import <JSQMessagesViewController/JSQMessagesMediaViewBubbleImageMasker.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <SCWaveformView.h>
|
||||
|
@ -15,18 +16,17 @@
|
|||
|
||||
@interface TSVideoAttachmentAdapter ()
|
||||
|
||||
@property UIImage *image;
|
||||
@property (strong, nonatomic) UIImageView *cachedImageView;
|
||||
@property (strong, nonatomic) UIImageView *videoPlayButton;
|
||||
@property (strong, nonatomic) CALayer *maskLayer;
|
||||
@property (strong, nonatomic) FFCircularProgressView *progressView;
|
||||
@property (strong, nonatomic) TSAttachmentStream *attachment;
|
||||
@property (strong, nonatomic) UIProgressView *audioProgress;
|
||||
@property (strong, nonatomic) SCWaveformView *waveform;
|
||||
@property (strong, nonatomic) UIButton *audioPlayPauseButton;
|
||||
@property (strong, nonatomic) UILabel *durationLabel;
|
||||
@property (strong, nonatomic) UIView *audioBubble;
|
||||
@property (nonatomic) UIImage *image;
|
||||
@property (nonatomic) UIImageView *cachedImageView;
|
||||
@property (nonatomic) UIImageView *videoPlayButton;
|
||||
@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) BOOL incoming;
|
||||
@property (nonatomic) AttachmentUploadView *attachmentUploadView;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -121,23 +121,16 @@
|
|||
_videoPlayButton.frame = CGRectMake((size.width / 2) - 18, (size.height / 2) - 18, 37, 37);
|
||||
[self.cachedImageView addSubview:_videoPlayButton];
|
||||
_videoPlayButton.hidden = YES;
|
||||
_maskLayer = [CALayer layer];
|
||||
[_maskLayer setBackgroundColor:[UIColor blackColor].CGColor];
|
||||
[_maskLayer setOpacity:0.4f];
|
||||
[_maskLayer setFrame:self.cachedImageView.frame];
|
||||
[self.cachedImageView.layer addSublayer:_maskLayer];
|
||||
_progressView = [[FFCircularProgressView alloc]
|
||||
initWithFrame:CGRectMake((size.width / 2) - 18, (size.height / 2) - 18, 37, 37)];
|
||||
[_cachedImageView addSubview:_progressView];
|
||||
if (_attachment.isDownloaded) {
|
||||
_videoPlayButton.hidden = NO;
|
||||
_maskLayer.hidden = YES;
|
||||
_progressView.hidden = YES;
|
||||
|
||||
if (!_incoming) {
|
||||
__weak TSVideoAttachmentAdapter *weakSelf = self;
|
||||
self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment
|
||||
superview:imageView
|
||||
attachmentStateCallback:^(BOOL isAttachmentReady) {
|
||||
weakSelf.videoPlayButton.hidden
|
||||
= !isAttachmentReady;
|
||||
}];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(attachmentUploadProgress:)
|
||||
name:@"attachmentUploadProgress"
|
||||
object:nil];
|
||||
}
|
||||
} else if ([self isAudio]) {
|
||||
NSError *err = NULL;
|
||||
|
@ -192,7 +185,20 @@
|
|||
[_audioBubble addSubview:_audioPlayPauseButton];
|
||||
[_audioBubble addSubview:_durationLabel];
|
||||
|
||||
if (!_incoming) {
|
||||
__weak TSVideoAttachmentAdapter *weakSelf = self;
|
||||
self.attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachment
|
||||
superview:_audioBubble
|
||||
attachmentStateCallback:^(BOOL isAttachmentReady) {
|
||||
weakSelf.audioPlayPauseButton.enabled
|
||||
= isAttachmentReady;
|
||||
}];
|
||||
}
|
||||
|
||||
return _audioBubble;
|
||||
} else {
|
||||
// Unknown media type.
|
||||
OWSAssert(0);
|
||||
}
|
||||
return self.cachedImageView;
|
||||
}
|
||||
|
@ -215,35 +221,6 @@
|
|||
return [super hash];
|
||||
}
|
||||
|
||||
- (void)attachmentUploadProgress:(NSNotification *)notification {
|
||||
NSDictionary *userinfo = [notification userInfo];
|
||||
double progress = [[userinfo objectForKey:@"progress"] doubleValue];
|
||||
NSString *attachmentID = [userinfo objectForKey:@"attachmentID"];
|
||||
if ([_attachmentId isEqualToString:attachmentID]) {
|
||||
NSLog(@"is downloaded: %d", _attachment.isDownloaded);
|
||||
if (!isnan(progress)) {
|
||||
[_progressView setProgress:(float)progress];
|
||||
}
|
||||
if (progress >= 1) {
|
||||
_maskLayer.hidden = YES;
|
||||
_progressView.hidden = YES;
|
||||
_videoPlayButton.hidden = NO;
|
||||
_attachment.isDownloaded = YES; // TODO isn't this redundant with attachment processor?
|
||||
[[TSMessagesManager sharedManager]
|
||||
.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[_attachment saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
}
|
||||
// set progress on bar
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_image = nil;
|
||||
_cachedImageView = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)setAppliesMediaViewMaskAsOutgoing:(BOOL)appliesMediaViewMaskAsOutgoing {
|
||||
[super setAppliesMediaViewMaskAsOutgoing:appliesMediaViewMaskAsOutgoing];
|
||||
_cachedImageView = nil;
|
||||
|
|
|
@ -180,29 +180,29 @@ typedef enum : NSUInteger {
|
|||
NSUInteger _unreadCount;
|
||||
}
|
||||
|
||||
@property TSThread *thread;
|
||||
@property TSMessageAdapter *lastDeliveredMessage;
|
||||
@property (nonatomic, strong) YapDatabaseConnection *editingDatabaseConnection;
|
||||
@property (nonatomic, strong) YapDatabaseConnection *uiDatabaseConnection;
|
||||
@property (nonatomic, strong) YapDatabaseViewMappings *messageMappings;
|
||||
@property (nonatomic) TSThread *thread;
|
||||
@property (nonatomic) TSMessageAdapter *lastDeliveredMessage;
|
||||
@property (nonatomic) YapDatabaseConnection *editingDatabaseConnection;
|
||||
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
|
||||
@property (nonatomic) YapDatabaseViewMappings *messageMappings;
|
||||
|
||||
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData;
|
||||
@property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData;
|
||||
@property (nonatomic, retain) JSQMessagesBubbleImage *currentlyOutgoingBubbleImageData;
|
||||
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingMessageFailedImageData;
|
||||
@property (nonatomic) JSQMessagesBubbleImage *outgoingBubbleImageData;
|
||||
@property (nonatomic) JSQMessagesBubbleImage *incomingBubbleImageData;
|
||||
@property (nonatomic) JSQMessagesBubbleImage *currentlyOutgoingBubbleImageData;
|
||||
@property (nonatomic) JSQMessagesBubbleImage *outgoingMessageFailedImageData;
|
||||
|
||||
@property (nonatomic, strong) NSTimer *audioPlayerPoller;
|
||||
@property (nonatomic, strong) TSVideoAttachmentAdapter *currentMediaAdapter;
|
||||
@property (nonatomic) NSTimer *audioPlayerPoller;
|
||||
@property (nonatomic) TSVideoAttachmentAdapter *currentMediaAdapter;
|
||||
|
||||
@property (nonatomic, retain) NSTimer *readTimer;
|
||||
@property (nonatomic, strong) UIView *navigationBarTitleView;
|
||||
@property (nonatomic, strong) UILabel *navigationBarTitleLabel;
|
||||
@property (nonatomic, strong) UILabel *navigationBarSubtitleLabel;
|
||||
@property (nonatomic, retain) UIButton *attachButton;
|
||||
@property (nonatomic) NSTimer *readTimer;
|
||||
@property (nonatomic) UIView *navigationBarTitleView;
|
||||
@property (nonatomic) UILabel *navigationBarTitleLabel;
|
||||
@property (nonatomic) UILabel *navigationBarSubtitleLabel;
|
||||
@property (nonatomic) UIButton *attachButton;
|
||||
|
||||
@property (nonatomic) CGFloat previousCollectionViewFrameWidth;
|
||||
|
||||
@property NSUInteger page;
|
||||
@property (nonatomic) NSUInteger page;
|
||||
@property (nonatomic) BOOL composeOnOpen;
|
||||
@property (nonatomic) BOOL peek;
|
||||
|
||||
|
@ -215,7 +215,7 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||
@property (nonatomic, readonly) OutboundCallInitiator *outboundCallInitiator;
|
||||
|
||||
@property NSCache *messageAdapterCache;
|
||||
@property (nonatomic) NSCache *messageAdapterCache;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface OWSProgressView : UIView
|
||||
|
||||
@property (nonatomic) UIColor *color;
|
||||
@property (nonatomic) CGFloat progress;
|
||||
|
||||
@end
|
|
@ -0,0 +1,120 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSProgressView.h"
|
||||
|
||||
@interface OWSProgressView ()
|
||||
|
||||
@property (nonatomic) CAShapeLayer *borderLayer;
|
||||
@property (nonatomic) CAShapeLayer *progressLayer;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSProgressView
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self initCommon];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initCommon];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initCommon
|
||||
{
|
||||
self.opaque = NO;
|
||||
self.userInteractionEnabled = NO;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.color = [UIColor whiteColor];
|
||||
|
||||
self.borderLayer = [CAShapeLayer new];
|
||||
self.borderLayer.fillColor = self.color.CGColor;
|
||||
[self.layer addSublayer:self.borderLayer];
|
||||
|
||||
self.progressLayer = [CAShapeLayer new];
|
||||
self.progressLayer.fillColor = self.color.CGColor;
|
||||
[self.layer addSublayer:self.progressLayer];
|
||||
|
||||
[self setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
|
||||
[self setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[self update];
|
||||
}
|
||||
|
||||
- (void)setProgress:(CGFloat)progress
|
||||
{
|
||||
if (_progress != progress) {
|
||||
_progress = progress;
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setColor:(UIColor *)color
|
||||
{
|
||||
if (![_color isEqual:color]) {
|
||||
_color = color;
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)update
|
||||
{
|
||||
CGFloat kBorderThickness = self.bounds.size.height * 0.15f;
|
||||
CGFloat kOuterRadius = self.bounds.size.height * 0.3f;
|
||||
CGFloat kInnerRadius = kOuterRadius - kBorderThickness;
|
||||
// We want to slightly overlap the border with the progress
|
||||
// to achieve a clean effect.
|
||||
CGFloat kProgressInset = kBorderThickness - 0.5f;
|
||||
|
||||
UIBezierPath *borderPath = [UIBezierPath new];
|
||||
|
||||
// Add the outer border.
|
||||
[borderPath appendPath:[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:kOuterRadius]];
|
||||
[borderPath
|
||||
appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, kBorderThickness, kBorderThickness)
|
||||
cornerRadius:kInnerRadius]];
|
||||
|
||||
self.borderLayer.path = borderPath.CGPath;
|
||||
self.borderLayer.fillColor = self.color.CGColor;
|
||||
self.borderLayer.fillRule = kCAFillRuleEvenOdd;
|
||||
|
||||
UIBezierPath *progressPath = [UIBezierPath new];
|
||||
|
||||
// Add the inner progress.
|
||||
CGRect progressRect = CGRectInset(self.bounds, kProgressInset, kProgressInset);
|
||||
progressRect.size.width *= MAX(0.f, MIN(1.f, self.progress));
|
||||
[progressPath appendPath:[UIBezierPath bezierPathWithRect:progressRect]];
|
||||
|
||||
self.progressLayer.path = progressPath.CGPath;
|
||||
self.progressLayer.fillColor = self.color.CGColor;
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size
|
||||
{
|
||||
return CGSizeMake(150, 16);
|
||||
}
|
||||
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, 16);
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue