From 9bd2ff0572dab8950b85f2f314a95ed1c53774ae Mon Sep 17 00:00:00 2001
From: Michael Kirk <michael.code@endoftheworl.de>
Date: Sun, 9 Apr 2017 15:31:31 -0400
Subject: [PATCH] Don't repaint back-button unread badge

There's not much benefit to this being done async, and making it sync
avoids the repaint.

Also, simplified the code around drawing the badge.

// FREEBIE
---
 .../ViewControllers/MessagesViewController.m  | 126 ++++++++----------
 1 file changed, 54 insertions(+), 72 deletions(-)

diff --git a/Signal/src/ViewControllers/MessagesViewController.m b/Signal/src/ViewControllers/MessagesViewController.m
index f17b106f6..8e4dea704 100644
--- a/Signal/src/ViewControllers/MessagesViewController.m
+++ b/Signal/src/ViewControllers/MessagesViewController.m
@@ -173,11 +173,6 @@ typedef enum : NSUInteger {
 @interface MessagesViewController () <JSQMessagesComposerTextViewPasteDelegate, OWSTextViewPasteDelegate> {
     UIImage *tappedImage;
     BOOL isGroupConversation;
-    
-    UIView *_unreadContainer;
-    UIImageView *_unreadBackground;
-    UILabel *_unreadLabel;
-    NSUInteger _unreadCount;
 }
 
 @property (nonatomic) TSThread *thread;
@@ -201,6 +196,11 @@ typedef enum : NSUInteger {
 @property (nonatomic) UIButton *attachButton;
 @property (nonatomic) UIView *blockStateIndicator;
 
+// Back Button Unread Count
+@property (nonatomic, readonly) UIView *backButtonUnreadCountView;
+@property (nonatomic, readonly) UILabel *backButtonUnreadCountLabel;
+@property (nonatomic, readonly) NSUInteger backButtonUnreadCount;
+
 @property (nonatomic) CGFloat previousCollectionViewFrameWidth;
 
 @property (nonatomic) NSUInteger page;
@@ -681,8 +681,7 @@ typedef enum : NSUInteger {
     [self dismissKeyBoard];
     [self startReadTimer];
 
-    // TODO prep this sync one time before view loads so we don't have to repaint.
-    [self updateBackButtonAsync];
+    [self updateBackButtonUnreadCount];
 
     [self.inputToolbar.contentView.textView endEditing:YES];
 
@@ -692,17 +691,6 @@ typedef enum : NSUInteger {
     }
 }
 
-- (void)updateBackButtonAsync {
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        NSUInteger count = [self.messagesManager unreadMessagesCountExcept:self.thread];
-        dispatch_async(dispatch_get_main_queue(), ^{
-            if (self) {
-                [self setUnreadCount:count];
-            }
-        });
-    });
-}
-
 - (void)viewWillDisappear:(BOOL)animated {
     [super viewWillDisappear:animated];
     [self toggleObservers:NO];
@@ -710,9 +698,6 @@ typedef enum : NSUInteger {
     // Since we're using a custom back button, we have to do some extra work to manage the interactivePopGestureRecognizer
     self.navigationController.interactivePopGestureRecognizer.delegate = nil;
 
-    [_unreadContainer removeFromSuperview];
-    _unreadContainer = nil;
-
     [_audioPlayerPoller invalidate];
     [_audioPlayer stop];
 
@@ -776,6 +761,33 @@ typedef enum : NSUInteger {
     (OWSDisappearingMessagesConfiguration *)disappearingMessagesConfiguration
 {
     UIBarButtonItem *backItem = [self createOWSBackButton];
+    const CGFloat unreadCountViewDiameter = 16;
+    if (_backButtonUnreadCountView == nil) {
+        _backButtonUnreadCountView = [UIView new];
+        _backButtonUnreadCountView.layer.cornerRadius = unreadCountViewDiameter / 2;
+        _backButtonUnreadCountView.backgroundColor = [UIColor redColor];
+        _backButtonUnreadCountView.hidden = YES;
+        _backButtonUnreadCountView.userInteractionEnabled = NO;
+
+        _backButtonUnreadCountLabel = [UILabel new];
+        _backButtonUnreadCountLabel.backgroundColor = [UIColor clearColor];
+        _backButtonUnreadCountLabel.textColor = [UIColor whiteColor];
+        _backButtonUnreadCountLabel.font = [UIFont systemFontOfSize:11];
+    }
+    // This method gets called multiple times, so it's important we re-layout the unread badge
+    // with respect to the new backItem.
+    [backItem.customView addSubview:_backButtonUnreadCountView];
+    [_backButtonUnreadCountView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:-6];
+    [_backButtonUnreadCountView autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:0];
+    [_backButtonUnreadCountView autoSetDimension:ALDimensionWidth toSize:unreadCountViewDiameter];
+    [_backButtonUnreadCountView autoSetDimension:ALDimensionHeight toSize:unreadCountViewDiameter];
+
+    [_backButtonUnreadCountView addSubview:_backButtonUnreadCountLabel];
+    [_backButtonUnreadCountLabel autoCenterInSuperview];
+
+    // Initialize newly created unread count badge to accurately reflect the current unread count.
+    [self updateBackButtonUnreadCount];
+
 
     const CGFloat kTitleVSpacing = 0.f;
     if (!self.navigationBarTitleView) {
@@ -2324,7 +2336,7 @@ typedef enum : NSUInteger {
     // models in order to jump to the most recent commit.
     NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
 
-    [self updateBackButtonAsync];
+    [self updateBackButtonUnreadCount];
 
     if (isGroupConversation) {
         [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
@@ -2683,57 +2695,27 @@ typedef enum : NSUInteger {
 
 #pragma mark Unread Badge
 
-- (void)setUnreadCount:(NSUInteger)unreadCount {
-    if (_unreadCount != unreadCount) {
-        _unreadCount = unreadCount;
-
-        if (_unreadCount > 0) {
-            if (_unreadContainer == nil) {
-                static UIImage *backgroundImage = nil;
-                static dispatch_once_t onceToken;
-                dispatch_once(&onceToken, ^{
-                  UIGraphicsBeginImageContextWithOptions(CGSizeMake(17.0f, 17.0f), false, 0.0f);
-                  CGContextRef context = UIGraphicsGetCurrentContext();
-                  CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
-                  CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 17.0f, 17.0f));
-                  backgroundImage =
-                      [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:8 topCapHeight:8];
-                  UIGraphicsEndImageContext();
-                });
-
-                _unreadContainer = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 10.0f, 10.0f)];
-                _unreadContainer.userInteractionEnabled = NO;
-                _unreadContainer.layer.zPosition        = 2000;
-                [self.navigationController.navigationBar addSubview:_unreadContainer];
-
-                _unreadBackground = [[UIImageView alloc] initWithImage:backgroundImage];
-                [_unreadContainer addSubview:_unreadBackground];
-
-                _unreadLabel                 = [[UILabel alloc] init];
-                _unreadLabel.backgroundColor = [UIColor clearColor];
-                _unreadLabel.textColor       = [UIColor whiteColor];
-                _unreadLabel.font            = [UIFont systemFontOfSize:12];
-                [_unreadContainer addSubview:_unreadLabel];
-            }
-            _unreadContainer.hidden = false;
-
-            _unreadLabel.text = [NSString stringWithFormat:@"%lu", (unsigned long)unreadCount];
-            [_unreadLabel sizeToFit];
-
-            CGPoint offset = CGPointMake(17.0f, 2.0f);
-
-            _unreadBackground.frame =
-                CGRectMake(offset.x, offset.y, MAX(_unreadLabel.frame.size.width + 8.0f, 17.0f), 17.0f);
-            _unreadLabel.frame = CGRectMake(offset.x
-                    + (CGFloat)floor(
-                          (2.0 * (_unreadBackground.frame.size.width - _unreadLabel.frame.size.width) / 2.0f) / 2.0f),
-                offset.y + 1.0f,
-                _unreadLabel.frame.size.width,
-                _unreadLabel.frame.size.height);
-        } else if (_unreadContainer != nil) {
-            _unreadContainer.hidden = true;
-        }
+- (void)updateBackButtonUnreadCount
+{
+    AssertIsOnMainThread();
+    self.backButtonUnreadCount = [self.messagesManager unreadMessagesCountExcept:self.thread];
+}
+
+- (void)setBackButtonUnreadCount:(NSUInteger)unreadCount
+{
+    AssertIsOnMainThread();
+    if (_backButtonUnreadCount == unreadCount) {
+        // No need to re-render same count.
+        return;
     }
+    _backButtonUnreadCount = unreadCount;
+
+    OWSAssert(_backButtonUnreadCountView != nil);
+    _backButtonUnreadCountView.hidden = unreadCount <= 0;
+
+    OWSAssert(_backButtonUnreadCountLabel != nil);
+    _backButtonUnreadCountLabel.text = [NSString stringWithFormat:@"%lu", (unsigned long)unreadCount];
+    [_backButtonUnreadCountLabel sizeToFit];
 }
 
 #pragma mark 3D Touch Preview Actions