Add progress & disable media views while uploading attachments.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-03-15 10:23:21 -03:00
parent 3dc7f2528f
commit 9ae047a1da
12 changed files with 418 additions and 133 deletions

View File

@ -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 */,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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