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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/settings/block_popups_collection_view_controller. h"
6
7 #include "base/ios/weak_nsobject.h"
8 #include "base/logging.h"
9 #import "base/mac/foundation_util.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/values.h"
13 #include "components/content_settings/core/browser/host_content_settings_map.h"
14 #include "components/content_settings/core/common/content_settings_pattern.h"
15 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
16 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory. h"
17 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item .h"
18 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h "
19 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
20 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
21 #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h"
22 #include "ios/chrome/grit/ios_strings.h"
23 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/l10n/l10n_util_mac.h"
26
27 namespace {
28
29 typedef NS_ENUM(NSInteger, SectionIdentifier) {
30 SectionIdentifierMainSwitch = kSectionIdentifierEnumZero,
31 SectionIdentifierExceptions,
32 };
33
34 typedef NS_ENUM(NSInteger, ItemType) {
35 ItemTypeMainSwitch = kItemTypeEnumZero,
36 ItemTypeHeader,
37 ItemTypeException,
38 };
39
40 } // namespace
41
42 @interface BlockPopupsCollectionViewController ()<BooleanObserver> {
43 ios::ChromeBrowserState* _browserState; // weak
44
45 // List of url patterns that are allowed to display popups.
46 base::ListValue _exceptions;
47
48 // The observable boolean that binds to the "Disable Popups" setting state.
49 base::scoped_nsobject<ContentSettingBackedBoolean> _disablePopupsSetting;
50
51 // The item related to the switch for the "Disable Popups" setting.
52 base::scoped_nsobject<CollectionViewSwitchItem> _blockPopupsItem;
53 }
54
55 // Fetch the urls that can display popups and add them to |_exceptions|.
56 - (void)populateExceptionsList;
57
58 // Returns YES if popups are currently blocked by default, NO otherwise.
59 - (BOOL)popupsCurrentlyBlocked;
60
61 @end
62
63 @implementation BlockPopupsCollectionViewController
64
65 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
66 DCHECK(browserState);
67 self = [super initWithStyle:CollectionViewControllerStyleAppBar];
68 if (self) {
69 _browserState = browserState;
70 HostContentSettingsMap* settingsMap =
71 ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState);
72 _disablePopupsSetting.reset([[ContentSettingBackedBoolean alloc]
73 initWithHostContentSettingsMap:settingsMap
74 settingID:CONTENT_SETTINGS_TYPE_POPUPS
75 inverted:YES]);
76 [_disablePopupsSetting setObserver:self];
77 self.title = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS);
78 self.collectionViewAccessibilityIdentifier =
79 @"block_popups_settings_view_controller";
80
81 [self populateExceptionsList];
82 [self updateEditButton];
83 [self loadModel];
84 }
85 return self;
86 }
87
88 - (void)dealloc {
89 [_disablePopupsSetting setObserver:nil];
90 [super dealloc];
91 }
92
93 #pragma mark - SettingsRootCollectionViewController
94
95 - (void)loadModel {
96 [super loadModel];
97
98 CollectionViewModel* model = self.collectionViewModel;
99
100 // Block popups switch.
101 [model addSectionWithIdentifier:SectionIdentifierMainSwitch];
102
103 _blockPopupsItem.reset(
104 [[CollectionViewSwitchItem alloc] initWithType:ItemTypeMainSwitch]);
105 _blockPopupsItem.get().text = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS);
106 _blockPopupsItem.get().on = [_disablePopupsSetting value];
107 _blockPopupsItem.get().accessibilityIdentifier =
108 @"blockPopupsContentView_switch";
109 [model addItem:_blockPopupsItem
110 toSectionWithIdentifier:SectionIdentifierMainSwitch];
111
112 if ([self popupsCurrentlyBlocked] && _exceptions.GetSize()) {
113 [self populateExceptionsItems];
114 }
115 }
116
117 - (BOOL)shouldShowEditButton {
118 return [self popupsCurrentlyBlocked];
119 }
120
121 - (BOOL)editButtonEnabled {
122 return _exceptions.GetSize() > 0;
123 }
124
125 #pragma mark - MDCCollectionViewEditingDelegate
126
127 - (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView {
128 return YES;
129 }
130
131 #pragma mark - UICollectionViewDataSource
132
133 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
134 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
135 UICollectionViewCell* cell =
136 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
137
138 if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
139 ItemTypeMainSwitch) {
140 CollectionViewSwitchCell* switchCell =
141 base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
142 [switchCell.switchView addTarget:self
143 action:@selector(blockPopupsSwitchChanged:)
144 forControlEvents:UIControlEventValueChanged];
145 }
146 return cell;
147 }
148
149 - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
150 viewForSupplementaryElementOfKind:(NSString*)kind
151 atIndexPath:(NSIndexPath*)indexPath {
152 UICollectionReusableView* view = [super collectionView:collectionView
153 viewForSupplementaryElementOfKind:kind
154 atIndexPath:indexPath];
155 MDCCollectionViewTextCell* textCell =
156 base::mac::ObjCCast<MDCCollectionViewTextCell>(view);
157 if (textCell) {
158 textCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
159 }
160 return view;
161 };
162
163 #pragma mark - MDCCollectionViewEditingDelegate
164
165 - (BOOL)collectionView:(UICollectionView*)collectionView
166 canEditItemAtIndexPath:(NSIndexPath*)indexPath {
167 // Any item in SectionIdentifierExceptions is editable.
168 return [self.collectionViewModel
169 sectionIdentifierForSection:indexPath.section] ==
170 SectionIdentifierExceptions;
171 }
172
173 - (void)collectionView:(UICollectionView*)collectionView
174 willDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
175 for (NSIndexPath* indexPath in indexPaths) {
176 size_t urlIndex = indexPath.item;
177 std::string urlToRemove;
178 _exceptions.GetString(urlIndex, &urlToRemove);
179
180 // Remove the exception for the site by resetting its popup setting to the
181 // default.
182 ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState)
183 ->SetContentSettingCustomScope(
184 ContentSettingsPattern::FromString(urlToRemove),
185 ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_POPUPS,
186 std::string(), CONTENT_SETTING_DEFAULT);
187
188 // Remove the site from |_exceptions|.
189 _exceptions.Remove(urlIndex, NULL);
190 }
191
192 // Must call super at the end of the child implementation.
193 [super collectionView:collectionView willDeleteItemsAtIndexPaths:indexPaths];
194 }
195
196 - (void)collectionView:(UICollectionView*)collectionView
197 didDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
198 // The only editable section is the block popups exceptions section.
199 if ([self.collectionViewModel
200 hasSectionForSectionIdentifier:SectionIdentifierExceptions]) {
201 NSInteger exceptionsSectionIndex = [self.collectionViewModel
202 sectionForSectionIdentifier:SectionIdentifierExceptions];
203 if ([collectionView numberOfItemsInSection:exceptionsSectionIndex] == 0) {
204 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
205 [self.collectionView performBatchUpdates:^{
206 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
207 [weakSelf retain]);
208 if (!strongSelf) {
209 return;
210 }
211 NSInteger section = [strongSelf.get().collectionViewModel
212 sectionForSectionIdentifier:SectionIdentifierExceptions];
213 [strongSelf.get().collectionViewModel
214 removeSectionWithIdentifier:SectionIdentifierExceptions];
215 [strongSelf.get().collectionView
216 deleteSections:[NSIndexSet indexSetWithIndex:section]];
217 }
218 completion:nil];
219 }
220 }
221 }
222
223 #pragma mark MDCCollectionViewStylingDelegate
224
225 - (BOOL)collectionView:(UICollectionView*)collectionView
226 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
227 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
228 switch (type) {
229 case ItemTypeMainSwitch:
230 return YES;
231 default:
232 return NO;
233 }
234 }
235
236 #pragma mark - BooleanObserver
237
238 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
239 DCHECK_EQ(observableBoolean, _disablePopupsSetting.get());
240
241 // Update the item.
242 _blockPopupsItem.get().on = [_disablePopupsSetting value];
243
244 // Update the cell.
245 [self reconfigureCellsForItems:@[ _blockPopupsItem ]
246 inSectionWithIdentifier:SectionIdentifierMainSwitch];
247
248 // Update the rest of the UI.
249 [self.editor setEditing:NO];
250 [self updateEditButton];
251 [self layoutSections:[_disablePopupsSetting value]];
252 }
253
254 #pragma mark - Actions
255
256 - (void)blockPopupsSwitchChanged:(UISwitch*)switchView {
257 // Update the setting.
258 [_disablePopupsSetting setValue:switchView.on];
259
260 // Update the item.
261 _blockPopupsItem.get().on = [_disablePopupsSetting value];
262
263 // Update the rest of the UI.
264 [self.editor setEditing:NO];
265 [self updateEditButton];
266 [self layoutSections:switchView.on];
267 }
268
269 #pragma mark - Private
270
271 - (BOOL)popupsCurrentlyBlocked {
272 return [_disablePopupsSetting value];
273 }
274
275 - (void)populateExceptionsList {
276 // The body of this method was mostly copied from
277 // chrome/browser/ui/webui/options/content_settings_handler.cc and simplified
278 // to only deal with urls/patterns that allow popups.
279 ContentSettingsForOneType entries;
280 ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState)
281 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, std::string(),
282 &entries);
283 for (size_t i = 0; i < entries.size(); ++i) {
284 // Skip default settings from extensions and policy, and the default content
285 // settings; all of them will affect the default setting UI.
286 if (entries[i].primary_pattern == ContentSettingsPattern::Wildcard() &&
287 entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() &&
288 entries[i].source != "preference") {
289 continue;
290 }
291 // The content settings UI does not support secondary content settings
292 // pattern yet. For content settings set through the content settings UI the
293 // secondary pattern is by default a wildcard pattern. Hence users are not
294 // able to modify content settings with a secondary pattern other than the
295 // wildcard pattern. So only show settings that the user is able to modify.
296 if (entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() &&
297 entries[i].setting == CONTENT_SETTING_ALLOW) {
298 _exceptions.Append(
299 new base::StringValue(entries[i].primary_pattern.ToString()));
300 } else {
301 LOG(ERROR) << "Secondary content settings patterns are not "
302 << "supported by the content settings UI";
303 }
304 }
305 }
306
307 - (void)populateExceptionsItems {
308 CollectionViewModel* model = self.collectionViewModel;
309 [model addSectionWithIdentifier:SectionIdentifierExceptions];
310
311 CollectionViewTextItem* header = [
312 [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease];
313 header.text = l10n_util::GetNSString(IDS_IOS_POPUPS_ALLOWED);
314 [model setHeader:header forSectionWithIdentifier:SectionIdentifierExceptions];
315
316 for (size_t i = 0; i < _exceptions.GetSize(); ++i) {
317 std::string allowed_url;
318 _exceptions.GetString(i, &allowed_url);
319 CollectionViewTextItem* item = [[[CollectionViewTextItem alloc]
320 initWithType:ItemTypeException] autorelease];
321 item.text = base::SysUTF8ToNSString(allowed_url);
322 [model addItem:item toSectionWithIdentifier:SectionIdentifierExceptions];
323 }
324 }
325
326 - (void)layoutSections:(BOOL)blockPopupsIsOn {
327 BOOL hasExceptions = _exceptions.GetSize();
328 BOOL exceptionsListShown = [self.collectionViewModel
329 hasSectionForSectionIdentifier:SectionIdentifierExceptions];
330
331 if (blockPopupsIsOn && !exceptionsListShown && hasExceptions) {
332 // Animate in the list of exceptions. Animation looks much better if the
333 // section is added at once, rather than row-by-row as each object is added.
334 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
335 [self.collectionView performBatchUpdates:^{
336 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
337 [weakSelf retain]);
338 if (!strongSelf)
339 return;
340 [strongSelf populateExceptionsItems];
341 NSUInteger index = [[strongSelf collectionViewModel]
342 sectionForSectionIdentifier:SectionIdentifierExceptions];
343 [[strongSelf collectionView]
344 insertSections:[NSIndexSet indexSetWithIndex:index]];
345 }
346 completion:nil];
347 } else if (!blockPopupsIsOn && exceptionsListShown) {
348 // Make sure the exception section is not shown.
349 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self);
350 [self.collectionView performBatchUpdates:^{
351 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf(
352 [weakSelf retain]);
353 if (!strongSelf)
354 return;
355 NSUInteger index = [[strongSelf collectionViewModel]
356 sectionForSectionIdentifier:SectionIdentifierExceptions];
357 [[strongSelf collectionViewModel]
358 removeSectionWithIdentifier:SectionIdentifierExceptions];
359 [[strongSelf collectionView]
360 deleteSections:[NSIndexSet indexSetWithIndex:index]];
361 }
362 completion:nil];
363 }
364 }
365
366 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698