blob: 210946e682422931bb45d39a3bb0baac4a724ab4 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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/infobars/infobar_container_mediator.h"
#include "ios/chrome/browser/infobars/infobar_container_ios.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#import "ios/chrome/browser/tabs/tab.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#import "ios/chrome/browser/tabs/tab_model_observer.h"
#import "ios/chrome/browser/translate/language_selection_handler.h"
#import "ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h"
#import "ios/chrome/browser/ui/infobars/infobar_container_consumer.h"
#import "ios/chrome/browser/ui/settings/sync_utils/sync_util.h"
#include "ios/chrome/browser/upgrade/upgrade_center.h"
#import "ios/chrome/browser/web/tab_id_tab_helper.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface InfobarContainerMediator ()<TabModelObserver,
WebStateListObserving> {
// A single infobar container handles all infobars in all tabs. It keeps
// track of infobars for current tab (accessed via infobar helper of
// the current tab).
std::unique_ptr<InfoBarContainerIOS> _infoBarContainer;
// Bridge class to deliver webStateList notifications.
std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
}
// The mediator's BrowserState.
@property(nonatomic, assign, readonly) ios::ChromeBrowserState* browserState;
// The mediator's TabModel.
@property(nonatomic, weak, readonly) TabModel* tabModel;
// The mediator's consumer.
@property(nonatomic, weak) id<InfobarContainerConsumer> consumer;
// The WebStateList that this mediator listens for any changes on its Webstates.
@property(nonatomic, assign) WebStateList* webStateList;
@end
@implementation InfobarContainerMediator
#pragma mark - Public Interface
- (instancetype)initWithConsumer:(id<InfobarContainerConsumer>)consumer
browserState:(ios::ChromeBrowserState*)browserState
tabModel:(TabModel*)tabModel {
self = [super init];
if (self) {
_browserState = browserState;
_consumer = consumer;
_tabModel = tabModel;
_webStateList = _tabModel.webStateList;
_infoBarContainer.reset(new InfoBarContainerIOS(_consumer));
infobars::InfoBarManager* infoBarManager = nullptr;
if (_tabModel.currentTab) {
DCHECK(_tabModel.currentTab.webState);
infoBarManager =
InfoBarManagerImpl::FromWebState(_tabModel.currentTab.webState);
}
_infoBarContainer->ChangeInfoBarManager(infoBarManager);
_webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
_webStateList->AddObserver(_webStateListObserver.get());
[_tabModel addObserver:self];
}
return self;
}
- (void)dealloc {
[_tabModel removeObserver:self];
_webStateList->RemoveObserver(_webStateListObserver.get());
_webStateListObserver.reset();
}
#pragma mark - TabModelObserver
- (void)tabModel:(TabModel*)model
didChangeActiveTab:(Tab*)newTab
previousTab:(Tab*)previousTab
atIndex:(NSUInteger)index {
// Dismiss the language selector, if any; this is a no-op when there's no
// language selector presented.
[self.languageSelectionHandler dismissLanguageSelector];
}
- (void)tabModel:(TabModel*)model willStartLoadingTab:(Tab*)tab {
// Dismiss the language selector, if any; this is a no-op when there's no
// language selector presented.
[self.languageSelectionHandler dismissLanguageSelector];
}
// TODO(crbug.com/892376): Stop observing TabModel and use WebStateList instead.
- (void)tabModel:(TabModel*)model
newTabWillOpen:(Tab*)tab
inBackground:(BOOL)background {
// When adding new tabs, check what kind of reminder infobar should
// be added to the new tab. Try to add only one of them.
// This check is done when a new tab is added either through the Tools Menu
// "New Tab", through a long press on the Tab Switcher button "New Tab", and
// through creating a New Tab from the Tab Switcher. This method is called
// after a new tab has added and finished initial navigation. If this is added
// earlier, the initial navigation may end up clearing the infobar(s) that are
// just added.
web::WebState* webState = tab.webState;
DCHECK(webState);
infobars::InfoBarManager* infoBarManager =
InfoBarManagerImpl::FromWebState(webState);
[[UpgradeCenter sharedInstance] addInfoBarToManager:infoBarManager
forTabId:[tab tabId]];
if (!ReSignInInfoBarDelegate::Create(
self.browserState, tab,
self.signinPresenter /* id<SigninPresenter> */)) {
DisplaySyncErrors(self.browserState, tab,
self.syncPresenter /* id<SyncPresenter> */);
}
}
#pragma mark - WebStateListObserver
- (void)webStateList:(WebStateList*)webStateList
didChangeActiveWebState:(web::WebState*)newWebState
oldWebState:(web::WebState*)oldWebState
atIndex:(int)atIndex
reason:(int)reason {
DCHECK_EQ(_webStateList, webStateList);
if (!newWebState)
return;
infobars::InfoBarManager* infoBarManager =
InfoBarManagerImpl::FromWebState(newWebState);
_infoBarContainer->ChangeInfoBarManager(infoBarManager);
}
- (void)webStateList:(WebStateList*)webStateList
didReplaceWebState:(web::WebState*)oldWebState
withWebState:(web::WebState*)newWebState
atIndex:(int)atIndex {
DCHECK_EQ(_webStateList, webStateList);
infobars::InfoBarManager* infoBarManager = nullptr;
if (newWebState) {
infoBarManager = InfoBarManagerImpl::FromWebState(newWebState);
}
_infoBarContainer->ChangeInfoBarManager(infoBarManager);
}
#pragma mark - UpgradeCenterClient
- (void)showUpgrade:(UpgradeCenter*)center {
DCHECK(self.tabModel.webStateList);
// Add an infobar on all the open tabs.
WebStateList* webStateList = self.tabModel.webStateList;
for (int index = 0; index < webStateList->count(); ++index) {
web::WebState* webState = webStateList->GetWebStateAt(index);
NSString* tabId = TabIdTabHelper::FromWebState(webState)->tab_id();
infobars::InfoBarManager* infoBarManager =
InfoBarManagerImpl::FromWebState(webState);
DCHECK(infoBarManager);
[center addInfoBarToManager:infoBarManager forTabId:tabId];
}
}
@end