// Copyright 2023 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/ui/content_suggestions/safety_check/safety_check_view.h"
#import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager_constants.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/multi_row_container_view.h"
#import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_content_view_delegate.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/constants.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_audience.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_item_view.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/types.h"
#import "ios/chrome/browser/ui/content_suggestions/safety_check/utils.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
@interface SafetyCheckView () <SafetyCheckItemViewTapDelegate>
@end
@implementation SafetyCheckView {
id<MagicStackModuleContentViewDelegate> _contentViewDelegate;
SafetyCheckState* _state;
UIView* _contentView;
}
#pragma mark - Public methods
- (instancetype)initWithState:(SafetyCheckState*)state
contentViewDelegate:
(id<MagicStackModuleContentViewDelegate>)contentViewDelegate {
if ((self = [super init])) {
_contentViewDelegate = contentViewDelegate;
_state = state;
}
return self;
}
#pragma mark - SafetyCheckMagicStackConsumer
- (void)safetyCheckStateDidChange:(SafetyCheckState*)state {
_state = state;
if (_contentView) {
[_contentView removeFromSuperview];
}
[self createSubviews];
}
#pragma mark - UIView
- (void)willMoveToSuperview:(UIView*)newSuperview {
[super willMoveToSuperview:newSuperview];
[self createSubviews];
}
#pragma mark - SafetyCheckItemViewTapDelegate
- (void)didTapSafetyCheckItemView:(SafetyCheckItemView*)view {
[self.audience didSelectSafetyCheckItem:view.itemType];
}
#pragma mark - Private methods
// Creates all views for the Safety Check (Magic Stack) module.
- (void)createSubviews {
// Return if the subviews have already been created and added.
if (!(self.subviews.count == 0)) {
return;
}
self.translatesAutoresizingMaskIntoConstraints = NO;
self.accessibilityIdentifier = safety_check::kSafetyCheckViewID;
[_contentViewDelegate
setSubtitle:FormatElapsedTimeSinceLastSafetyCheck(_state.lastRunTime)];
// If any of the checks are running, the module should display its running
// state.
if (_state.runningState == RunningSafetyCheckState::kRunning ||
_state.updateChromeState == UpdateChromeSafetyCheckState::kRunning ||
_state.passwordState == PasswordSafetyCheckState::kRunning ||
_state.safeBrowsingState == SafeBrowsingSafetyCheckState::kRunning) {
SafetyCheckItemView* view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kRunning
layoutType:SafetyCheckItemLayoutType::kHero];
view.tapDelegate = self;
_contentView = view;
[self addSubview:_contentView];
AddSameConstraints(_contentView, self);
return;
}
// If all checks are in the default state, the module should display the
// default state.
if (_state.runningState == RunningSafetyCheckState::kDefault &&
_state.updateChromeState == UpdateChromeSafetyCheckState::kDefault &&
_state.passwordState == PasswordSafetyCheckState::kDefault &&
_state.safeBrowsingState == SafeBrowsingSafetyCheckState::kDefault) {
SafetyCheckItemView* view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kDefault
layoutType:SafetyCheckItemLayoutType::kHero];
view.tapDelegate = self;
_contentView = view;
[self addSubview:_contentView];
AddSameConstraints(_contentView, self);
return;
}
int checkIssuesCount = [_state numberOfIssues];
// Show the "All Safe" state if there are no check issues.
if (checkIssuesCount == 0) {
SafetyCheckItemView* view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kAllSafe
layoutType:SafetyCheckItemLayoutType::kHero];
view.tapDelegate = self;
_contentView = view;
[self addSubview:_contentView];
AddSameConstraints(_contentView, self);
return;
}
if (checkIssuesCount > 1) {
NSMutableArray<SafetyCheckItemView*>* safetyCheckItems =
[[NSMutableArray alloc] init];
// Update Chrome check
if (InvalidUpdateChromeState(_state.updateChromeState)) {
SafetyCheckItemView* updateChromeView = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kUpdateChrome
layoutType:SafetyCheckItemLayoutType::kCompact];
updateChromeView.tapDelegate = self;
[safetyCheckItems addObject:updateChromeView];
}
// Password check
if (InvalidPasswordState(_state.passwordState)) {
SafetyCheckItemView* passwordView = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kPassword
layoutType:SafetyCheckItemLayoutType::kCompact
weakPasswordsCount:_state.weakPasswordsCount
reusedPasswordsCount:_state.reusedPasswordsCount
compromisedPasswordsCount:_state.compromisedPasswordsCount];
passwordView.tapDelegate = self;
[safetyCheckItems addObject:passwordView];
}
// Safe Browsing check
//
// NOTE: Don't add the Safe Browsing check if two items already exist in
// `safetyCheckItems`. At most, the compact view displays two rows of items.
if ([safetyCheckItems count] < 2 &&
InvalidSafeBrowsingState(_state.safeBrowsingState)) {
SafetyCheckItemView* safeBrowsingView = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kSafeBrowsing
layoutType:SafetyCheckItemLayoutType::kCompact];
safeBrowsingView.tapDelegate = self;
[safetyCheckItems addObject:safeBrowsingView];
}
MultiRowContainerView* multiRowContainer =
[[MultiRowContainerView alloc] initWithViews:safetyCheckItems];
multiRowContainer.translatesAutoresizingMaskIntoConstraints = NO;
_contentView = multiRowContainer;
[self addSubview:_contentView];
AddSameConstraints(_contentView, self);
return;
}
// Show hero-cell view for single check issue.
SafetyCheckItemView* view;
if (InvalidUpdateChromeState(_state.updateChromeState)) {
view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kUpdateChrome
layoutType:SafetyCheckItemLayoutType::kHero];
} else if (InvalidPasswordState(_state.passwordState)) {
view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kPassword
layoutType:SafetyCheckItemLayoutType::kHero
weakPasswordsCount:_state.weakPasswordsCount
reusedPasswordsCount:_state.reusedPasswordsCount
compromisedPasswordsCount:_state.compromisedPasswordsCount];
} else if (InvalidSafeBrowsingState(_state.safeBrowsingState)) {
view = [[SafetyCheckItemView alloc]
initWithItemType:SafetyCheckItemType::kSafeBrowsing
layoutType:SafetyCheckItemLayoutType::kHero];
}
view.tapDelegate = self;
_contentView = view;
[self addSubview:_contentView];
AddSameConstraints(_contentView, self);
}
@end