| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/ui/settings/block_popups_collection_view_controller.
h" | 5 #import "ios/chrome/browser/ui/settings/block_popups_collection_view_controller.
h" |
| 6 | 6 |
| 7 #import "base/ios/weak_nsobject.h" | |
| 8 #include "base/logging.h" | 7 #include "base/logging.h" |
| 9 #import "base/mac/foundation_util.h" | 8 #import "base/mac/foundation_util.h" |
| 10 #import "base/mac/scoped_nsobject.h" | |
| 11 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 12 #include "base/values.h" | 10 #include "base/values.h" |
| 13 #include "components/content_settings/core/browser/host_content_settings_map.h" | 11 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 14 #include "components/content_settings/core/common/content_settings_pattern.h" | 12 #include "components/content_settings/core/common/content_settings_pattern.h" |
| 15 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 13 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 16 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.
h" | 14 #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" | 15 #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
" | 16 #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" | 17 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
| 20 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" | 18 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" |
| 21 #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" | 19 #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" |
| 22 #include "ios/chrome/grit/ios_strings.h" | 20 #include "ios/chrome/grit/ios_strings.h" |
| 23 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat
erialPalettes.h" | 21 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat
erialPalettes.h" |
| 24 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
| 25 #include "ui/base/l10n/l10n_util_mac.h" | 23 #include "ui/base/l10n/l10n_util_mac.h" |
| 26 | 24 |
| 25 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 26 #error "This file requires ARC support." |
| 27 #endif |
| 28 |
| 27 namespace { | 29 namespace { |
| 28 | 30 |
| 29 typedef NS_ENUM(NSInteger, SectionIdentifier) { | 31 typedef NS_ENUM(NSInteger, SectionIdentifier) { |
| 30 SectionIdentifierMainSwitch = kSectionIdentifierEnumZero, | 32 SectionIdentifierMainSwitch = kSectionIdentifierEnumZero, |
| 31 SectionIdentifierExceptions, | 33 SectionIdentifierExceptions, |
| 32 }; | 34 }; |
| 33 | 35 |
| 34 typedef NS_ENUM(NSInteger, ItemType) { | 36 typedef NS_ENUM(NSInteger, ItemType) { |
| 35 ItemTypeMainSwitch = kItemTypeEnumZero, | 37 ItemTypeMainSwitch = kItemTypeEnumZero, |
| 36 ItemTypeHeader, | 38 ItemTypeHeader, |
| 37 ItemTypeException, | 39 ItemTypeException, |
| 38 }; | 40 }; |
| 39 | 41 |
| 40 } // namespace | 42 } // namespace |
| 41 | 43 |
| 42 @interface BlockPopupsCollectionViewController ()<BooleanObserver> { | 44 @interface BlockPopupsCollectionViewController ()<BooleanObserver> { |
| 43 ios::ChromeBrowserState* _browserState; // weak | 45 ios::ChromeBrowserState* _browserState; // weak |
| 44 | 46 |
| 45 // List of url patterns that are allowed to display popups. | 47 // List of url patterns that are allowed to display popups. |
| 46 base::ListValue _exceptions; | 48 base::ListValue _exceptions; |
| 47 | 49 |
| 48 // The observable boolean that binds to the "Disable Popups" setting state. | 50 // The observable boolean that binds to the "Disable Popups" setting state. |
| 49 base::scoped_nsobject<ContentSettingBackedBoolean> _disablePopupsSetting; | 51 ContentSettingBackedBoolean* _disablePopupsSetting; |
| 50 | 52 |
| 51 // The item related to the switch for the "Disable Popups" setting. | 53 // The item related to the switch for the "Disable Popups" setting. |
| 52 base::scoped_nsobject<CollectionViewSwitchItem> _blockPopupsItem; | 54 CollectionViewSwitchItem* _blockPopupsItem; |
| 53 } | 55 } |
| 54 | 56 |
| 55 // Fetch the urls that can display popups and add them to |_exceptions|. | 57 // Fetch the urls that can display popups and add them to |_exceptions|. |
| 56 - (void)populateExceptionsList; | 58 - (void)populateExceptionsList; |
| 57 | 59 |
| 58 // Returns YES if popups are currently blocked by default, NO otherwise. | 60 // Returns YES if popups are currently blocked by default, NO otherwise. |
| 59 - (BOOL)popupsCurrentlyBlocked; | 61 - (BOOL)popupsCurrentlyBlocked; |
| 60 | 62 |
| 61 @end | 63 @end |
| 62 | 64 |
| 63 @implementation BlockPopupsCollectionViewController | 65 @implementation BlockPopupsCollectionViewController |
| 64 | 66 |
| 65 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState { | 67 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState { |
| 66 DCHECK(browserState); | 68 DCHECK(browserState); |
| 67 self = [super initWithStyle:CollectionViewControllerStyleAppBar]; | 69 self = [super initWithStyle:CollectionViewControllerStyleAppBar]; |
| 68 if (self) { | 70 if (self) { |
| 69 _browserState = browserState; | 71 _browserState = browserState; |
| 70 HostContentSettingsMap* settingsMap = | 72 HostContentSettingsMap* settingsMap = |
| 71 ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState); | 73 ios::HostContentSettingsMapFactory::GetForBrowserState(_browserState); |
| 72 _disablePopupsSetting.reset([[ContentSettingBackedBoolean alloc] | 74 _disablePopupsSetting = [[ContentSettingBackedBoolean alloc] |
| 73 initWithHostContentSettingsMap:settingsMap | 75 initWithHostContentSettingsMap:settingsMap |
| 74 settingID:CONTENT_SETTINGS_TYPE_POPUPS | 76 settingID:CONTENT_SETTINGS_TYPE_POPUPS |
| 75 inverted:YES]); | 77 inverted:YES]; |
| 76 [_disablePopupsSetting setObserver:self]; | 78 [_disablePopupsSetting setObserver:self]; |
| 77 self.title = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS); | 79 self.title = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS); |
| 78 self.collectionViewAccessibilityIdentifier = | 80 self.collectionViewAccessibilityIdentifier = |
| 79 @"block_popups_settings_view_controller"; | 81 @"block_popups_settings_view_controller"; |
| 80 | 82 |
| 81 [self populateExceptionsList]; | 83 [self populateExceptionsList]; |
| 82 [self updateEditButton]; | 84 [self updateEditButton]; |
| 83 [self loadModel]; | 85 [self loadModel]; |
| 84 } | 86 } |
| 85 return self; | 87 return self; |
| 86 } | 88 } |
| 87 | 89 |
| 88 - (void)dealloc { | 90 - (void)dealloc { |
| 89 [_disablePopupsSetting setObserver:nil]; | 91 [_disablePopupsSetting setObserver:nil]; |
| 90 [super dealloc]; | |
| 91 } | 92 } |
| 92 | 93 |
| 93 #pragma mark - SettingsRootCollectionViewController | 94 #pragma mark - SettingsRootCollectionViewController |
| 94 | 95 |
| 95 - (void)loadModel { | 96 - (void)loadModel { |
| 96 [super loadModel]; | 97 [super loadModel]; |
| 97 | 98 |
| 98 CollectionViewModel* model = self.collectionViewModel; | 99 CollectionViewModel* model = self.collectionViewModel; |
| 99 | 100 |
| 100 // Block popups switch. | 101 // Block popups switch. |
| 101 [model addSectionWithIdentifier:SectionIdentifierMainSwitch]; | 102 [model addSectionWithIdentifier:SectionIdentifierMainSwitch]; |
| 102 | 103 |
| 103 _blockPopupsItem.reset( | 104 _blockPopupsItem = |
| 104 [[CollectionViewSwitchItem alloc] initWithType:ItemTypeMainSwitch]); | 105 [[CollectionViewSwitchItem alloc] initWithType:ItemTypeMainSwitch]; |
| 105 _blockPopupsItem.get().text = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS); | 106 _blockPopupsItem.text = l10n_util::GetNSString(IDS_IOS_BLOCK_POPUPS); |
| 106 _blockPopupsItem.get().on = [_disablePopupsSetting value]; | 107 _blockPopupsItem.on = [_disablePopupsSetting value]; |
| 107 _blockPopupsItem.get().accessibilityIdentifier = | 108 _blockPopupsItem.accessibilityIdentifier = @"blockPopupsContentView_switch"; |
| 108 @"blockPopupsContentView_switch"; | |
| 109 [model addItem:_blockPopupsItem | 109 [model addItem:_blockPopupsItem |
| 110 toSectionWithIdentifier:SectionIdentifierMainSwitch]; | 110 toSectionWithIdentifier:SectionIdentifierMainSwitch]; |
| 111 | 111 |
| 112 if ([self popupsCurrentlyBlocked] && _exceptions.GetSize()) { | 112 if ([self popupsCurrentlyBlocked] && _exceptions.GetSize()) { |
| 113 [self populateExceptionsItems]; | 113 [self populateExceptionsItems]; |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 | 116 |
| 117 - (BOOL)shouldShowEditButton { | 117 - (BOOL)shouldShowEditButton { |
| 118 return [self popupsCurrentlyBlocked]; | 118 return [self popupsCurrentlyBlocked]; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 } | 180 } |
| 181 | 181 |
| 182 - (void)collectionView:(UICollectionView*)collectionView | 182 - (void)collectionView:(UICollectionView*)collectionView |
| 183 didDeleteItemsAtIndexPaths:(NSArray*)indexPaths { | 183 didDeleteItemsAtIndexPaths:(NSArray*)indexPaths { |
| 184 // The only editable section is the block popups exceptions section. | 184 // The only editable section is the block popups exceptions section. |
| 185 if ([self.collectionViewModel | 185 if ([self.collectionViewModel |
| 186 hasSectionForSectionIdentifier:SectionIdentifierExceptions]) { | 186 hasSectionForSectionIdentifier:SectionIdentifierExceptions]) { |
| 187 NSInteger exceptionsSectionIndex = [self.collectionViewModel | 187 NSInteger exceptionsSectionIndex = [self.collectionViewModel |
| 188 sectionForSectionIdentifier:SectionIdentifierExceptions]; | 188 sectionForSectionIdentifier:SectionIdentifierExceptions]; |
| 189 if ([collectionView numberOfItemsInSection:exceptionsSectionIndex] == 0) { | 189 if ([collectionView numberOfItemsInSection:exceptionsSectionIndex] == 0) { |
| 190 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self); | 190 __weak BlockPopupsCollectionViewController* weakSelf = self; |
| 191 [self.collectionView performBatchUpdates:^{ | 191 [self.collectionView performBatchUpdates:^{ |
| 192 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf( | 192 BlockPopupsCollectionViewController* strongSelf = weakSelf; |
| 193 [weakSelf retain]); | |
| 194 if (!strongSelf) { | 193 if (!strongSelf) { |
| 195 return; | 194 return; |
| 196 } | 195 } |
| 197 NSInteger section = [strongSelf.get().collectionViewModel | 196 NSInteger section = [strongSelf.collectionViewModel |
| 198 sectionForSectionIdentifier:SectionIdentifierExceptions]; | 197 sectionForSectionIdentifier:SectionIdentifierExceptions]; |
| 199 [strongSelf.get().collectionViewModel | 198 [strongSelf.collectionViewModel |
| 200 removeSectionWithIdentifier:SectionIdentifierExceptions]; | 199 removeSectionWithIdentifier:SectionIdentifierExceptions]; |
| 201 [strongSelf.get().collectionView | 200 [strongSelf.collectionView |
| 202 deleteSections:[NSIndexSet indexSetWithIndex:section]]; | 201 deleteSections:[NSIndexSet indexSetWithIndex:section]]; |
| 203 } | 202 } |
| 204 completion:nil]; | 203 completion:nil]; |
| 205 } | 204 } |
| 206 } | 205 } |
| 207 } | 206 } |
| 208 | 207 |
| 209 #pragma mark MDCCollectionViewStylingDelegate | 208 #pragma mark MDCCollectionViewStylingDelegate |
| 210 | 209 |
| 211 - (BOOL)collectionView:(UICollectionView*)collectionView | 210 - (BOOL)collectionView:(UICollectionView*)collectionView |
| 212 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { | 211 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { |
| 213 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; | 212 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| 214 switch (type) { | 213 switch (type) { |
| 215 case ItemTypeMainSwitch: | 214 case ItemTypeMainSwitch: |
| 216 return YES; | 215 return YES; |
| 217 default: | 216 default: |
| 218 return NO; | 217 return NO; |
| 219 } | 218 } |
| 220 } | 219 } |
| 221 | 220 |
| 222 #pragma mark - BooleanObserver | 221 #pragma mark - BooleanObserver |
| 223 | 222 |
| 224 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean { | 223 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean { |
| 225 DCHECK_EQ(observableBoolean, _disablePopupsSetting.get()); | 224 DCHECK_EQ(observableBoolean, _disablePopupsSetting); |
| 226 | 225 |
| 227 // Update the item. | 226 // Update the item. |
| 228 _blockPopupsItem.get().on = [_disablePopupsSetting value]; | 227 _blockPopupsItem.on = [_disablePopupsSetting value]; |
| 229 | 228 |
| 230 // Update the cell. | 229 // Update the cell. |
| 231 [self reconfigureCellsForItems:@[ _blockPopupsItem ] | 230 [self reconfigureCellsForItems:@[ _blockPopupsItem ] |
| 232 inSectionWithIdentifier:SectionIdentifierMainSwitch]; | 231 inSectionWithIdentifier:SectionIdentifierMainSwitch]; |
| 233 | 232 |
| 234 // Update the rest of the UI. | 233 // Update the rest of the UI. |
| 235 [self.editor setEditing:NO]; | 234 [self.editor setEditing:NO]; |
| 236 [self updateEditButton]; | 235 [self updateEditButton]; |
| 237 [self layoutSections:[_disablePopupsSetting value]]; | 236 [self layoutSections:[_disablePopupsSetting value]]; |
| 238 } | 237 } |
| 239 | 238 |
| 240 #pragma mark - Actions | 239 #pragma mark - Actions |
| 241 | 240 |
| 242 - (void)blockPopupsSwitchChanged:(UISwitch*)switchView { | 241 - (void)blockPopupsSwitchChanged:(UISwitch*)switchView { |
| 243 // Update the setting. | 242 // Update the setting. |
| 244 [_disablePopupsSetting setValue:switchView.on]; | 243 [_disablePopupsSetting setValue:switchView.on]; |
| 245 | 244 |
| 246 // Update the item. | 245 // Update the item. |
| 247 _blockPopupsItem.get().on = [_disablePopupsSetting value]; | 246 _blockPopupsItem.on = [_disablePopupsSetting value]; |
| 248 | 247 |
| 249 // Update the rest of the UI. | 248 // Update the rest of the UI. |
| 250 [self.editor setEditing:NO]; | 249 [self.editor setEditing:NO]; |
| 251 [self updateEditButton]; | 250 [self updateEditButton]; |
| 252 [self layoutSections:switchView.on]; | 251 [self layoutSections:switchView.on]; |
| 253 } | 252 } |
| 254 | 253 |
| 255 #pragma mark - Private | 254 #pragma mark - Private |
| 256 | 255 |
| 257 - (BOOL)popupsCurrentlyBlocked { | 256 - (BOOL)popupsCurrentlyBlocked { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 287 LOG(ERROR) << "Secondary content settings patterns are not " | 286 LOG(ERROR) << "Secondary content settings patterns are not " |
| 288 << "supported by the content settings UI"; | 287 << "supported by the content settings UI"; |
| 289 } | 288 } |
| 290 } | 289 } |
| 291 } | 290 } |
| 292 | 291 |
| 293 - (void)populateExceptionsItems { | 292 - (void)populateExceptionsItems { |
| 294 CollectionViewModel* model = self.collectionViewModel; | 293 CollectionViewModel* model = self.collectionViewModel; |
| 295 [model addSectionWithIdentifier:SectionIdentifierExceptions]; | 294 [model addSectionWithIdentifier:SectionIdentifierExceptions]; |
| 296 | 295 |
| 297 CollectionViewTextItem* header = [ | 296 CollectionViewTextItem* header = |
| 298 [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease]; | 297 [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader]; |
| 299 header.text = l10n_util::GetNSString(IDS_IOS_POPUPS_ALLOWED); | 298 header.text = l10n_util::GetNSString(IDS_IOS_POPUPS_ALLOWED); |
| 300 header.textColor = [[MDCPalette greyPalette] tint500]; | 299 header.textColor = [[MDCPalette greyPalette] tint500]; |
| 301 [model setHeader:header forSectionWithIdentifier:SectionIdentifierExceptions]; | 300 [model setHeader:header forSectionWithIdentifier:SectionIdentifierExceptions]; |
| 302 | 301 |
| 303 for (size_t i = 0; i < _exceptions.GetSize(); ++i) { | 302 for (size_t i = 0; i < _exceptions.GetSize(); ++i) { |
| 304 std::string allowed_url; | 303 std::string allowed_url; |
| 305 _exceptions.GetString(i, &allowed_url); | 304 _exceptions.GetString(i, &allowed_url); |
| 306 CollectionViewTextItem* item = [[[CollectionViewTextItem alloc] | 305 CollectionViewTextItem* item = |
| 307 initWithType:ItemTypeException] autorelease]; | 306 [[CollectionViewTextItem alloc] initWithType:ItemTypeException]; |
| 308 item.text = base::SysUTF8ToNSString(allowed_url); | 307 item.text = base::SysUTF8ToNSString(allowed_url); |
| 309 [model addItem:item toSectionWithIdentifier:SectionIdentifierExceptions]; | 308 [model addItem:item toSectionWithIdentifier:SectionIdentifierExceptions]; |
| 310 } | 309 } |
| 311 } | 310 } |
| 312 | 311 |
| 313 - (void)layoutSections:(BOOL)blockPopupsIsOn { | 312 - (void)layoutSections:(BOOL)blockPopupsIsOn { |
| 314 BOOL hasExceptions = _exceptions.GetSize(); | 313 BOOL hasExceptions = _exceptions.GetSize(); |
| 315 BOOL exceptionsListShown = [self.collectionViewModel | 314 BOOL exceptionsListShown = [self.collectionViewModel |
| 316 hasSectionForSectionIdentifier:SectionIdentifierExceptions]; | 315 hasSectionForSectionIdentifier:SectionIdentifierExceptions]; |
| 317 | 316 |
| 318 if (blockPopupsIsOn && !exceptionsListShown && hasExceptions) { | 317 if (blockPopupsIsOn && !exceptionsListShown && hasExceptions) { |
| 319 // Animate in the list of exceptions. Animation looks much better if the | 318 // Animate in the list of exceptions. Animation looks much better if the |
| 320 // section is added at once, rather than row-by-row as each object is added. | 319 // section is added at once, rather than row-by-row as each object is added. |
| 321 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self); | 320 __weak BlockPopupsCollectionViewController* weakSelf = self; |
| 322 [self.collectionView performBatchUpdates:^{ | 321 [self.collectionView performBatchUpdates:^{ |
| 323 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf( | 322 BlockPopupsCollectionViewController* strongSelf = weakSelf; |
| 324 [weakSelf retain]); | |
| 325 if (!strongSelf) | 323 if (!strongSelf) |
| 326 return; | 324 return; |
| 327 [strongSelf populateExceptionsItems]; | 325 [strongSelf populateExceptionsItems]; |
| 328 NSUInteger index = [[strongSelf collectionViewModel] | 326 NSUInteger index = [[strongSelf collectionViewModel] |
| 329 sectionForSectionIdentifier:SectionIdentifierExceptions]; | 327 sectionForSectionIdentifier:SectionIdentifierExceptions]; |
| 330 [[strongSelf collectionView] | 328 [[strongSelf collectionView] |
| 331 insertSections:[NSIndexSet indexSetWithIndex:index]]; | 329 insertSections:[NSIndexSet indexSetWithIndex:index]]; |
| 332 } | 330 } |
| 333 completion:nil]; | 331 completion:nil]; |
| 334 } else if (!blockPopupsIsOn && exceptionsListShown) { | 332 } else if (!blockPopupsIsOn && exceptionsListShown) { |
| 335 // Make sure the exception section is not shown. | 333 // Make sure the exception section is not shown. |
| 336 base::WeakNSObject<BlockPopupsCollectionViewController> weakSelf(self); | 334 __weak BlockPopupsCollectionViewController* weakSelf = self; |
| 337 [self.collectionView performBatchUpdates:^{ | 335 [self.collectionView performBatchUpdates:^{ |
| 338 base::scoped_nsobject<BlockPopupsCollectionViewController> strongSelf( | 336 BlockPopupsCollectionViewController* strongSelf = weakSelf; |
| 339 [weakSelf retain]); | |
| 340 if (!strongSelf) | 337 if (!strongSelf) |
| 341 return; | 338 return; |
| 342 NSUInteger index = [[strongSelf collectionViewModel] | 339 NSUInteger index = [[strongSelf collectionViewModel] |
| 343 sectionForSectionIdentifier:SectionIdentifierExceptions]; | 340 sectionForSectionIdentifier:SectionIdentifierExceptions]; |
| 344 [[strongSelf collectionViewModel] | 341 [[strongSelf collectionViewModel] |
| 345 removeSectionWithIdentifier:SectionIdentifierExceptions]; | 342 removeSectionWithIdentifier:SectionIdentifierExceptions]; |
| 346 [[strongSelf collectionView] | 343 [[strongSelf collectionView] |
| 347 deleteSections:[NSIndexSet indexSetWithIndex:index]]; | 344 deleteSections:[NSIndexSet indexSetWithIndex:index]]; |
| 348 } | 345 } |
| 349 completion:nil]; | 346 completion:nil]; |
| 350 } | 347 } |
| 351 } | 348 } |
| 352 | 349 |
| 353 @end | 350 @end |
| OLD | NEW |