chromium/ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_view_controller.mm

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_view_controller.h"

#import <MaterialComponents/MaterialProgressView.h>

#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/context_menu/ui_bundled/link_preview/link_preview_constants.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ui/gfx/ios/uikit_util.h"

namespace {
const CGFloat kURLBarMarginVertical = 13.0;
const CGFloat kURLBarMarginHorizontal = 16.0;
const CGFloat kSeparatorHeight = 0.1f;
const CGFloat kProgressBarHeight = 2.0f;
}  // namespace

@interface LinkPreviewViewController ()

// The view of the loaded webState.
@property(nonatomic, strong) UIView* webStateView;

// The NSString that indicates the origin of the preview url.
@property(nonatomic, copy) NSString* origin;

// The URL bar label.
@property(nonatomic, strong) UILabel* URLBarLabel;

// Progress bar displayed below the URL bar.
@property(nonatomic, strong) MDCProgressView* progressBar;

// YES if the page is loading.
@property(nonatomic, assign, getter=isLoading) BOOL loading;

@end

@implementation LinkPreviewViewController

- (instancetype)initWithView:(UIView*)webStateView origin:(NSString*)origin {
  self = [super initWithNibName:nil bundle:nil];
  if (self) {
    _webStateView = webStateView;
    _origin = origin;
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  self.URLBarLabel = [[UILabel alloc] init];
  self.URLBarLabel.text = self.origin;
  self.URLBarLabel.font =
      [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
  self.URLBarLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
  self.URLBarLabel.translatesAutoresizingMaskIntoConstraints = NO;
  self.URLBarLabel.accessibilityIdentifier = kPreviewOriginIdentifier;

  UIView* URLBarView = [[UIView alloc] init];
  URLBarView.backgroundColor = [UIColor colorNamed:kBackgroundColor];
  URLBarView.translatesAutoresizingMaskIntoConstraints = NO;
  URLBarView.accessibilityIdentifier = kPreviewURLBarIdentifier;

  [URLBarView addSubview:self.URLBarLabel];
  [NSLayoutConstraint activateConstraints:@[
    [self.URLBarLabel.topAnchor constraintEqualToAnchor:URLBarView.topAnchor
                                               constant:kURLBarMarginVertical],
    [self.URLBarLabel.bottomAnchor
        constraintEqualToAnchor:URLBarView.bottomAnchor
                       constant:-kURLBarMarginVertical],
    [self.URLBarLabel.leadingAnchor
        constraintEqualToAnchor:URLBarView.leadingAnchor
                       constant:kURLBarMarginHorizontal],
    [self.URLBarLabel.trailingAnchor
        constraintEqualToAnchor:URLBarView.trailingAnchor
                       constant:-kURLBarMarginHorizontal],

  ]];

  UIView* separator = [[UIView alloc] init];
  separator.backgroundColor = [UIColor colorNamed:kSeparatorColor];
  separator.translatesAutoresizingMaskIntoConstraints = NO;

  self.progressBar = [[MDCProgressView alloc] init];
  self.progressBar.translatesAutoresizingMaskIntoConstraints = NO;
  self.progressBar.hidden = YES;
  self.progressBar.accessibilityIdentifier = kPreviewProgressBarIdentifier;

  self.webStateView.translatesAutoresizingMaskIntoConstraints = NO;
  self.webStateView.accessibilityIdentifier = kPreviewWebStateViewIdentifier;

  [self.view addSubview:URLBarView];
  [self.view addSubview:separator];
  [self.view addSubview:self.progressBar];
  [self.view addSubview:self.webStateView];

  [NSLayoutConstraint activateConstraints:@[
    [URLBarView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
    [URLBarView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
    [URLBarView.trailingAnchor
        constraintEqualToAnchor:self.view.trailingAnchor],
    [URLBarView.bottomAnchor constraintEqualToAnchor:separator.topAnchor],
    [separator.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
    [separator.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
    [separator.heightAnchor
        constraintEqualToConstant:ui::AlignValueToUpperPixel(kSeparatorHeight)],
    [separator.bottomAnchor
        constraintEqualToAnchor:self.webStateView.topAnchor],
    [self.progressBar.leadingAnchor
        constraintEqualToAnchor:self.view.leadingAnchor],
    [self.progressBar.trailingAnchor
        constraintEqualToAnchor:self.view.trailingAnchor],
    [self.progressBar.heightAnchor
        constraintEqualToConstant:ui::AlignValueToUpperPixel(
                                      kProgressBarHeight)],
    [self.progressBar.bottomAnchor
        constraintEqualToAnchor:self.webStateView.topAnchor],
    [self.webStateView.leadingAnchor
        constraintEqualToAnchor:self.view.leadingAnchor],
    [self.webStateView.trailingAnchor
        constraintEqualToAnchor:self.view.trailingAnchor],
    [self.webStateView.bottomAnchor
        constraintEqualToAnchor:self.view.bottomAnchor],
  ]];
}

#pragma mark - LinkPreviewConsumer

- (void)setLoadingState:(BOOL)loading {
  if (self.loading == loading)
    return;

  self.loading = loading;

  if (!loading) {
    [self finishProgressBar];
  } else if (self.progressBar.hidden) {
    [self.progressBar setProgress:0];
    [self updateProgressBarVisibility];
  }
}

- (void)setLoadingProgressFraction:(double)progress {
  [self.progressBar setProgress:progress animated:YES completion:nil];
}

- (void)setPreviewOrigin:(NSString*)origin {
  self.origin = origin;
  self.URLBarLabel.text = origin;
}

#pragma mark - Private

// Reset auto layout of the webStateView to YES, otherwise it can't be
// expanded to a tab.
- (void)resetAutoLayoutForPreview {
  self.webStateView.translatesAutoresizingMaskIntoConstraints = YES;
}

// Finish the progress bar when the page stops loading.
- (void)finishProgressBar {
  __weak __typeof(self) weakSelf = self;
  [self.progressBar setProgress:1
                       animated:YES
                     completion:^(BOOL finished) {
                       [weakSelf updateProgressBarVisibility];
                     }];
}

// Makes sure that the visibility of the progress bar is matching the one which
// is expected.
- (void)updateProgressBarVisibility {
  __weak __typeof(self) weakSelf = self;
  if (self.loading && self.progressBar.hidden) {
    [self.progressBar setHidden:NO
                       animated:YES
                     completion:^(BOOL finished) {
                       [weakSelf updateProgressBarVisibility];
                     }];
  } else if (!self.loading && !self.progressBar.hidden) {
    [self.progressBar setHidden:YES
                       animated:YES
                     completion:^(BOOL finished) {
                       [weakSelf updateProgressBarVisibility];
                     }];
  }
}

@end