Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Unified Diff: ios/chrome/browser/ui/settings/block_popups_collection_view_controller.mm

Issue 2589583003: Upstream Chrome on iOS source code [7/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/settings/block_popups_collection_view_controller.mm
diff --git a/ios/chrome/browser/ui/settings/block_popups_collection_view_controller.mm b/ios/chrome/browser/ui/settings/block_popups_collection_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..3041f481473c411df014a693c1995f72a46e97b5
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/block_popups_collection_view_controller.mm
@@ -0,0 +1,366 @@
+// Copyright 2015 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/settings/block_popups_collection_view_controller.h"
+
+#include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#import "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/values.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
+#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
+#import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+ SectionIdentifierMainSwitch = kSectionIdentifierEnumZero,
+ SectionIdentifierExceptions,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+ ItemTypeMainSwitch = kItemTypeEnumZero,
+ ItemTypeHeader,
+ ItemTypeException,
+};
+
+} // namespace
+
+@interface BlockPopupsCollectionViewController ()<BooleanObserver> {
+ ios::ChromeBrowserState* _browserState; // weak
+
+ // List of url patterns that are allowed to display popups.
+ base::ListValue _exceptions;
+
+ // The observable boolean that binds to the "Disable Popups" setting state.
+ base::scoped_nsobject<ContentSettingBackedBoolean> _disablePopupsSetting;
+
+ // The item related to the switch for the "Disable Popups" setting.
+ base::scoped_nsobject<CollectionViewSwitchItem> _blockPopupsItem;
+}
+
+// Fetch the urls that can display popups and add them to |_exceptions|.
+- (void)populateExceptionsList;
+
+// Returns YES if popups are currently blocked by default, NO otherwise.
+- (BOOL)popupsCurrentlyBlocked;
+
+@end
+
+@implementation BlockPopupsCollectionViewController
+
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
+ DCHECK(browserState);
+ self = [super initWithStyle:CollectionViewControllerStyleAppBar];
+ if (self) {
+ _browserState = browserState;
+ HostContentSettingsMap* settingsMap =
+ ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState);
+ _disablePopupsSetting.reset([[ContentSettingBackedBoolean alloc]
+ initWithHostContentSettingsMap:settingsMap
+ settingID:CONTENT_SETTINGS_TYPE_POPUPS
+ inverted:YES]);
+ [_disablePopupsSetting setObserver:self];
+ self.title = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS);
+ self.collectionViewAccessibilityIdentifier =
+ @"block_popups_settings_view_controller";
+
+ [self populateExceptionsList];
+ [self updateEditButton];
+ [self loadModel];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [_disablePopupsSetting setObserver:nil];
+ [super dealloc];
+}
+
+#pragma mark - SettingsRootCollectionViewController
+
+- (void)loadModel {
+ [super loadModel];
+
+ CollectionViewModel* model = self.collectionViewModel;
+
+ // Block popups switch.
+ [model addSectionWithIdentifier:SectionIdentifierMainSwitch];
+
+ _blockPopupsItem.reset(
+ [[CollectionViewSwitchItem alloc] initWithType:ItemTypeMainSwitch]);
+ _blockPopupsItem.get().text = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS);
+ _blockPopupsItem.get().on = [_disablePopupsSetting value];
+ _blockPopupsItem.get().accessibilityIdentifier =
+ @"blockPopupsContentView_switch";
+ [model addItem:_blockPopupsItem
+ toSectionWithIdentifier:SectionIdentifierMainSwitch];
+
+ if ([self popupsCurrentlyBlocked] && _exceptions.GetSize()) {
+ [self populateExceptionsItems];
+ }
+}
+
+- (BOOL)shouldShowEditButton {
+ return [self popupsCurrentlyBlocked];
+}
+
+- (BOOL)editButtonEnabled {
+ return _exceptions.GetSize() > 0;
+}
+
+#pragma mark - MDCCollectionViewEditingDelegate
+
+- (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView {
+ return YES;
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
+ cellForItemAtIndexPath:(NSIndexPath*)indexPath {
+ UICollectionViewCell* cell =
+ [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
+
+ if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
+ ItemTypeMainSwitch) {
+ CollectionViewSwitchCell* switchCell =
+ base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
+ [switchCell.switchView addTarget:self
+ action:@selector(blockPopupsSwitchChanged:)
+ forControlEvents:UIControlEventValueChanged];
+ }
+ return cell;
+}
+
+- (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
+ viewForSupplementaryElementOfKind:(NSString*)kind
+ atIndexPath:(NSIndexPath*)indexPath {
+ UICollectionReusableView* view = [super collectionView:collectionView
+ viewForSupplementaryElementOfKind:kind
+ atIndexPath:indexPath];
+ MDCCollectionViewTextCell* textCell =
+ base::mac::ObjCCast<MDCCollectionViewTextCell>(view);
+ if (textCell) {
+ textCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
+ }
+ return view;
+};
+
+#pragma mark - MDCCollectionViewEditingDelegate
+
+- (BOOL)collectionView:(UICollectionView*)collectionView
+ canEditItemAtIndexPath:(NSIndexPath*)indexPath {
+ // Any item in SectionIdentifierExceptions is editable.
+ return [self.collectionViewModel
+ sectionIdentifierForSection:indexPath.section] ==
+ SectionIdentifierExceptions;
+}
+
+- (void)collectionView:(UICollectionView*)collectionView
+ willDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
+ for (NSIndexPath* indexPath in indexPaths) {
+ size_t urlIndex = indexPath.item;
+ std::string urlToRemove;
+ _exceptions.GetString(urlIndex, &urlToRemove);
+
+ // Remove the exception for the site by resetting its popup setting to the
+ // default.
+ ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState)
+ ->SetContentSettingCustomScope(
+ ContentSettingsPattern::FromString(urlToRemove),
+ ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_POPUPS,
+ std::string(), CONTENT_SETTING_DEFAULT);
+
+ // Remove the site from |_exceptions|.
+ _exceptions.Remove(urlIndex, NULL);
+ }
+
+ // Must call super at the end of the child implementation.
+ [super collectionView:collectionView willDeleteItemsAtIndexPaths:indexPaths];
+}
+
+- (void)collectionView:(UICollectionView*)collectionView
+ didDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
+ // The only editable section is the block popups exceptions section.
+ if ([self.collectionViewModel
+ hasSectionForSectionIdentifier:SectionIdentifierExceptions]) {
+ NSInteger exceptionsSectionIndex = [self.collectionViewModel
+ sectionForSectionIdentifier:SectionIdentifierExceptions];
+ if ([collectionView numberOfItemsInSection:exceptionsSectionIndex] == 0) {
+ base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
+ [self.collectionView performBatchUpdates:^{
+ base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf) {
+ return;
+ }
+ NSInteger section = [strongSelf.get().collectionViewModel
+ sectionForSectionIdentifier:SectionIdentifierExceptions];
+ [strongSelf.get().collectionViewModel
+ removeSectionWithIdentifier:SectionIdentifierExceptions];
+ [strongSelf.get().collectionView
+ deleteSections:[NSIndexSet indexSetWithIndex:section]];
+ }
+ completion:nil];
+ }
+ }
+}
+
+#pragma mark MDCCollectionViewStylingDelegate
+
+- (BOOL)collectionView:(UICollectionView*)collectionView
+ hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
+ NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
+ switch (type) {
+ case ItemTypeMainSwitch:
+ return YES;
+ default:
+ return NO;
+ }
+}
+
+#pragma mark - BooleanObserver
+
+- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
+ DCHECK_EQ(observableBoolean, _disablePopupsSetting.get());
+
+ // Update the item.
+ _blockPopupsItem.get().on = [_disablePopupsSetting value];
+
+ // Update the cell.
+ [self reconfigureCellsForItems:@[ _blockPopupsItem ]
+ inSectionWithIdentifier:SectionIdentifierMainSwitch];
+
+ // Update the rest of the UI.
+ [self.editor setEditing:NO];
+ [self updateEditButton];
+ [self layoutSections:[_disablePopupsSetting value]];
+}
+
+#pragma mark - Actions
+
+- (void)blockPopupsSwitchChanged:(UISwitch*)switchView {
+ // Update the setting.
+ [_disablePopupsSetting setValue:switchView.on];
+
+ // Update the item.
+ _blockPopupsItem.get().on = [_disablePopupsSetting value];
+
+ // Update the rest of the UI.
+ [self.editor setEditing:NO];
+ [self updateEditButton];
+ [self layoutSections:switchView.on];
+}
+
+#pragma mark - Private
+
+- (BOOL)popupsCurrentlyBlocked {
+ return [_disablePopupsSetting value];
+}
+
+- (void)populateExceptionsList {
+ // The body of this method was mostly copied from
+ // chrome/browser/ui/webui/options/content_settings_handler.cc and simplified
+ // to only deal with urls/patterns that allow popups.
+ ContentSettingsForOneType entries;
+ ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState)
+ ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
+ &entries);
+ for (size_t i = 0; i < entries.size(); ++i) {
+ // Skip default settings from extensions and policy, and the default content
+ // settings; all of them will affect the default setting UI.
+ if (entries[i].primary_pattern == ContentSettingsPattern::Wildcard() &&
+ entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() &&
+ entries[i].source != "preference") {
+ continue;
+ }
+ // The content settings UI does not support secondary content settings
+ // pattern yet. For content settings set through the content settings UI the
+ // secondary pattern is by default a wildcard pattern. Hence users are not
+ // able to modify content settings with a secondary pattern other than the
+ // wildcard pattern. So only show settings that the user is able to modify.
+ if (entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() &&
+ entries[i].setting == CONTENT_SETTING_ALLOW) {
+ _exceptions.Append(
+ new base::StringValue(entries[i].primary_pattern.ToString()));
+ } else {
+ LOG(ERROR) << "Secondary content settings patterns are not "
+ << "supported by the content settings UI";
+ }
+ }
+}
+
+- (void)populateExceptionsItems {
+ CollectionViewModel* model = self.collectionViewModel;
+ [model addSectionWithIdentifier:SectionIdentifierExceptions];
+
+ CollectionViewTextItem* header = [
+ [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease];
+ header.text = l10n_util::GetNSString(IDS_IOS_POPUPS_ALLOWED);
+ [model setHeader:header forSectionWithIdentifier:SectionIdentifierExceptions];
+
+ for (size_t i = 0; i < _exceptions.GetSize(); ++i) {
+ std::string allowed_url;
+ _exceptions.GetString(i, &allowed_url);
+ CollectionViewTextItem* item = [[[CollectionViewTextItem alloc]
+ initWithType:ItemTypeException] autorelease];
+ item.text = base::SysUTF8ToNSString(allowed_url);
+ [model addItem:item toSectionWithIdentifier:SectionIdentifierExceptions];
+ }
+}
+
+- (void)layoutSections:(BOOL)blockPopupsIsOn {
+ BOOL hasExceptions = _exceptions.GetSize();
+ BOOL exceptionsListShown = [self.collectionViewModel
+ hasSectionForSectionIdentifier:SectionIdentifierExceptions];
+
+ if (blockPopupsIsOn && !exceptionsListShown && hasExceptions) {
+ // Animate in the list of exceptions. Animation looks much better if the
+ // section is added at once, rather than row-by-row as each object is added.
+ base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
+ [self.collectionView performBatchUpdates:^{
+ base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ [strongSelf populateExceptionsItems];
+ NSUInteger index = [[strongSelf collectionViewModel]
+ sectionForSectionIdentifier:SectionIdentifierExceptions];
+ [[strongSelf collectionView]
+ insertSections:[NSIndexSet indexSetWithIndex:index]];
+ }
+ completion:nil];
+ } else if (!blockPopupsIsOn && exceptionsListShown) {
+ // Make sure the exception section is not shown.
+ base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
+ [self.collectionView performBatchUpdates:^{
+ base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
+ [weakSelf retain]);
+ if (!strongSelf)
+ return;
+ NSUInteger index = [[strongSelf collectionViewModel]
+ sectionForSectionIdentifier:SectionIdentifierExceptions];
+ [[strongSelf collectionViewModel]
+ removeSectionWithIdentifier:SectionIdentifierExceptions];
+ [[strongSelf collectionView]
+ deleteSections:[NSIndexSet indexSetWithIndex:index]];
+ }
+ completion:nil];
+ }
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698