From c70d33b9e408a00e26d10baf4ba9d4eebc7b2f30 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Mon, 9 Jul 2018 16:15:46 -0400
Subject: [PATCH] Tweak attachment upload view.

---
 .../OWSBackupSettingsViewController.m         |   1 -
 .../Cells/AttachmentUploadView.m              | 103 ++++++++----------
 .../Cells/OWSMessageBubbleView.m              |  38 +++----
 Signal/src/views/OWSProgressView.m            |  39 +++----
 4 files changed, 77 insertions(+), 104 deletions(-)

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 <SignalMessaging/AttachmentSharing.h>
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 <SignalMessaging/UIFont+OWS.h>
 #import <SignalMessaging/UIView+OWS.h>
 #import <SignalServiceKit/AppContext.h>
 #import <SignalServiceKit/OWSUploadOperation.h>
@@ -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 <SignalMessaging/OWSMath.h>
+#import <SignalMessaging/UIView+OWS.h>
 
 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;