diff --git a/Signal/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m b/Signal/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m index a2569aa2c..9a991967f 100644 --- a/Signal/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m +++ b/Signal/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m @@ -4,7 +4,6 @@ #import "OWSBackupSettingsViewController.h" #import "OWSBackup.h" -#import "OWSProgressView.h" #import "Signal-Swift.h" #import "ThreadUtil.h" #import diff --git a/Signal/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m b/Signal/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m index 828c074e8..130554b73 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m @@ -5,6 +5,7 @@ #import "AttachmentUploadView.h" #import "OWSBezierPathView.h" #import "OWSProgressView.h" +#import #import #import #import @@ -16,10 +17,10 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) TSAttachmentStream *attachment; -@property (nonatomic) OWSBezierPathView *bezierPathView; - @property (nonatomic) OWSProgressView *progressView; +@property (nonatomic) UILabel *progressLabel; + @property (nonatomic) AttachmentStateBlock _Nullable attachmentStateCallback; @property (nonatomic) BOOL isAttachmentReady; @@ -43,20 +44,7 @@ NS_ASSUME_NONNULL_BEGIN self.attachment = attachment; self.attachmentStateCallback = attachmentStateCallback; - _bezierPathView = [OWSBezierPathView new]; - self.bezierPathView.configureShapeLayerBlock = ^(CAShapeLayer *layer, CGRect bounds) { - layer.path = [UIBezierPath bezierPathWithRect:bounds].CGPath; - layer.fillColor = [UIColor colorWithWhite:0.f alpha:0.4f].CGColor; - }; - [self addSubview:self.bezierPathView]; - [self.bezierPathView autoPinToSuperviewEdges]; - - // 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]; - self.progressView.color = [UIColor whiteColor]; - [self addSubview:self.progressView]; + [self createContents]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(attachmentUploadProgress:) @@ -79,6 +67,44 @@ NS_ASSUME_NONNULL_BEGIN [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (void)createContents +{ + // 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]; + self.progressView.color = [UIColor whiteColor]; + [self.progressView autoSetDimension:ALDimensionWidth toSize:80.f]; + [self.progressView autoSetDimension:ALDimensionHeight toSize:6.f]; + + self.progressLabel = [UILabel new]; + self.progressLabel.text = NSLocalizedString( + @"MESSAGE_METADATA_VIEW_MESSAGE_STATUS_UPLOADING", @"Status label for messages which are uploading.") + .uppercaseString; + self.progressLabel.textColor = UIColor.whiteColor; + self.progressLabel.font = [UIFont ows_dynamicTypeCaption1Font]; + self.progressLabel.textAlignment = NSTextAlignmentCenter; + + UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ + self.progressView, + self.progressLabel, + ]]; + stackView.axis = UILayoutConstraintAxisVertical; + stackView.spacing = 4; + stackView.layoutMargins = UIEdgeInsetsMake(4, 4, 4, 4); + stackView.layoutMarginsRelativeArrangement = YES; + [self addSubview:stackView]; + [stackView autoCenterInSuperview]; + [NSLayoutConstraint + autoSetPriority:UILayoutPriorityRequired + forConstraints:^{ + [stackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual]; + [stackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual]; + [stackView autoPinEdgeToSuperviewMargin:ALEdgeLeading relation:NSLayoutRelationGreaterThanOrEqual]; + [stackView autoPinEdgeToSuperviewMargin:ALEdgeTrailing relation:NSLayoutRelationGreaterThanOrEqual]; + }]; +} + - (void)setIsAttachmentReady:(BOOL)isAttachmentReady { if (_isAttachmentReady == isAttachmentReady) { @@ -103,8 +129,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)ensureViewState { - self.bezierPathView.hidden = self.isAttachmentReady || self.lastProgress == 0; - self.progressView.hidden = self.isAttachmentReady || self.lastProgress == 0; + BOOL isUploading = !self.isAttachmentReady && self.lastProgress != 0; + self.backgroundColor = (isUploading ? [UIColor colorWithWhite:0.f alpha:0.2f] : nil); + self.progressView.hidden = !isUploading; + self.progressLabel.hidden = !isUploading; } - (void)attachmentUploadProgress:(NSNotification *)notification @@ -124,45 +152,6 @@ NS_ASSUME_NONNULL_BEGIN } } -- (void)setBounds:(CGRect)bounds -{ - BOOL sizeDidChange = !CGSizeEqualToSize(bounds.size, self.bounds.size); - [super setBounds:bounds]; - if (sizeDidChange) { - [self updateLayout]; - } -} - -- (void)setFrame:(CGRect)frame -{ - BOOL sizeDidChange = !CGSizeEqualToSize(frame.size, self.frame.size); - [super setFrame:frame]; - if (sizeDidChange) { - [self updateLayout]; - } -} - -- (void)updateLayout -{ - // Center the progress bar within the bubble mask. - // - // TODO: Verify that this layout works in RTL. - const CGFloat kBubbleTailWidth = 6.f; - CGRect bounds = self.bounds; - bounds.size.width -= kBubbleTailWidth; - if (CurrentAppContext().isRTL) { - bounds.origin.x += kBubbleTailWidth; - } - - const CGFloat progressWidth = round(bounds.size.width * 0.45f); - const CGFloat progressHeight = round(MIN(bounds.size.height * 0.5f, progressWidth * 0.09f)); - CGRect progressFrame = CGRectMake(round(bounds.origin.x + (bounds.size.width - progressWidth) * 0.5f), - round(bounds.origin.y + (bounds.size.height - progressHeight) * 0.5f), - progressWidth, - progressHeight); - self.progressView.frame = progressFrame; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index daf958e8b..79bafd92e 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -328,11 +328,6 @@ NS_ASSUME_NONNULL_BEGIN self.bodyMediaView = bodyMediaView; bodyMediaView.userInteractionEnabled = NO; - if (self.isMediaBeingSent) { - // TODO: - bodyMediaView.layer.opacity = 0.75f; - } - if (self.hasFullWidthMediaView) { // Flush any pending "text" subviews. [self insertAnyTextViewsIntoStackView:textViews]; @@ -855,7 +850,7 @@ NS_ASSUME_NONNULL_BEGIN stillImageView.layer.minificationFilter = kCAFilterTrilinear; stillImageView.layer.magnificationFilter = kCAFilterTrilinear; stillImageView.backgroundColor = [UIColor whiteColor]; - [self addAttachmentUploadViewIfNecessary:stillImageView]; + [self addAttachmentUploadViewIfNecessary]; __weak OWSMessageBubbleView *weakSelf = self; self.loadCellContentBlock = ^{ @@ -903,7 +898,7 @@ NS_ASSUME_NONNULL_BEGIN // might not match the aspect ratio of the view. animatedImageView.contentMode = UIViewContentModeScaleAspectFill; animatedImageView.backgroundColor = [UIColor whiteColor]; - [self addAttachmentUploadViewIfNecessary:animatedImageView]; + [self addAttachmentUploadViewIfNecessary]; __weak OWSMessageBubbleView *weakSelf = self; self.loadCellContentBlock = ^{ @@ -952,7 +947,7 @@ NS_ASSUME_NONNULL_BEGIN conversationStyle:self.conversationStyle]; self.viewItem.lastAudioMessageView = audioMessageView; [audioMessageView createContents]; - [self addAttachmentUploadViewIfNecessary:audioMessageView]; + [self addAttachmentUploadViewIfNecessary]; self.loadCellContentBlock = ^{ // Do nothing. @@ -982,10 +977,9 @@ NS_ASSUME_NONNULL_BEGIN UIImageView *videoPlayButton = [[UIImageView alloc] initWithImage:videoPlayIcon]; [stillImageView addSubview:videoPlayButton]; [videoPlayButton autoCenterInSuperview]; - [self addAttachmentUploadViewIfNecessary:stillImageView - attachmentStateCallback:^(BOOL isAttachmentReady) { - videoPlayButton.hidden = !isAttachmentReady; - }]; + [self addAttachmentUploadViewIfNecessary:^(BOOL isAttachmentReady) { + videoPlayButton.hidden = !isAttachmentReady; + }]; __weak OWSMessageBubbleView *weakSelf = self; self.loadCellContentBlock = ^{ @@ -1024,7 +1018,7 @@ NS_ASSUME_NONNULL_BEGIN OWSGenericAttachmentView *attachmentView = [[OWSGenericAttachmentView alloc] initWithAttachment:self.attachmentStream isIncoming:self.isIncoming]; [attachmentView createContentsWithConversationStyle:self.conversationStyle]; - [self addAttachmentUploadViewIfNecessary:attachmentView]; + [self addAttachmentUploadViewIfNecessary]; self.loadCellContentBlock = ^{ // Do nothing. @@ -1082,26 +1076,26 @@ NS_ASSUME_NONNULL_BEGIN return contactShareView; } -- (void)addAttachmentUploadViewIfNecessary:(UIView *)attachmentView +- (void)addAttachmentUploadViewIfNecessary { - [self addAttachmentUploadViewIfNecessary:attachmentView - attachmentStateCallback:^(BOOL isAttachmentReady){ - }]; + [self addAttachmentUploadViewIfNecessary:nil]; } -- (void)addAttachmentUploadViewIfNecessary:(UIView *)attachmentView - attachmentStateCallback:(AttachmentStateBlock)attachmentStateCallback +- (void)addAttachmentUploadViewIfNecessary:(nullable AttachmentStateBlock)attachmentStateCallback { - OWSAssert(attachmentView); - OWSAssert(attachmentStateCallback); OWSAssert(self.attachmentStream); + if (!attachmentStateCallback) { + attachmentStateCallback = ^(BOOL isAttachmentReady) { + }; + } + if (self.isOutgoing) { if (!self.attachmentStream.isUploaded) { AttachmentUploadView *attachmentUploadView = [[AttachmentUploadView alloc] initWithAttachment:self.attachmentStream attachmentStateCallback:attachmentStateCallback]; - [attachmentView addSubview:attachmentUploadView]; + [self.bubbleView addSubview:attachmentUploadView]; [attachmentUploadView autoPinToSuperviewEdges]; } } diff --git a/Signal/src/views/OWSProgressView.m b/Signal/src/views/OWSProgressView.m index 91bafe456..881638399 100644 --- a/Signal/src/views/OWSProgressView.m +++ b/Signal/src/views/OWSProgressView.m @@ -3,6 +3,8 @@ // #import "OWSProgressView.h" +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -40,7 +42,6 @@ NS_ASSUME_NONNULL_BEGIN { self.opaque = NO; self.userInteractionEnabled = NO; - self.backgroundColor = [UIColor clearColor]; self.color = [UIColor whiteColor]; // Prevent the shape layer from animating changes. @@ -48,11 +49,9 @@ NS_ASSUME_NONNULL_BEGIN [CATransaction setDisableActions:YES]; 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]; [CATransaction commit]; @@ -89,32 +88,24 @@ NS_ASSUME_NONNULL_BEGIN [CATransaction begin]; [CATransaction setDisableActions:YES]; - CGFloat kBorderThickness = self.bounds.size.height * 0.1f; - CGFloat kOuterRadius = self.bounds.size.height * 0.25f; - 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]; + CGFloat borderThickness = MAX(CGHairlineWidth(), self.bounds.size.height * 0.1f); + CGFloat cornerRadius = MIN(self.bounds.size.width, self.bounds.size.height) * 0.5f; // Add the outer border. - [borderPath appendPath:[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:kOuterRadius]]; - [borderPath - appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, kBorderThickness, kBorderThickness) - cornerRadius:kInnerRadius]]; - + UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:cornerRadius]; self.borderLayer.path = borderPath.CGPath; - self.borderLayer.fillColor = self.color.CGColor; - self.borderLayer.fillRule = kCAFillRuleEvenOdd; - - UIBezierPath *progressPath = [UIBezierPath new]; + self.borderLayer.strokeColor = self.color.CGColor; + self.borderLayer.lineWidth = borderThickness; + self.borderLayer.fillColor = [UIColor clearColor].CGColor; // 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]]; - + CGRect progressRect = self.bounds; + progressRect.size.width = cornerRadius * 2; + CGFloat baseProgress = borderThickness * 2; + CGFloat minProgress = baseProgress; + CGFloat maxProgress = MAX(0, self.bounds.size.width - baseProgress); + progressRect.size.width = CGFloatLerp(minProgress, maxProgress, self.progress); + UIBezierPath *progressPath = [UIBezierPath bezierPathWithRoundedRect:progressRect cornerRadius:cornerRadius]; self.progressLayer.path = progressPath.CGPath; self.progressLayer.fillColor = self.color.CGColor;