diff --git a/Sources/Controllers/Base/OABaseNavbarViewController.h b/Sources/Controllers/Base/OABaseNavbarViewController.h index 0cc0d377f9..99cf500ef0 100644 --- a/Sources/Controllers/Base/OABaseNavbarViewController.h +++ b/Sources/Controllers/Base/OABaseNavbarViewController.h @@ -36,7 +36,8 @@ typedef NS_ENUM(NSInteger, EOABaseNavbarStyle) - (void)updateAppearance; - (void)updateNavbar; - (void)updateUI:(BOOL)animated; -- (void)updateUIWithoutData; +- (void)updateUI:(BOOL)animated completion:(void (^)(void))completion; +- (void)updateUIWithoutData:(void (^)(void))completion; - (void)refreshUI; - (UIBarButtonItem *)createRightNavbarButton:(NSString *)title diff --git a/Sources/Controllers/Base/OABaseNavbarViewController.m b/Sources/Controllers/Base/OABaseNavbarViewController.m index 9fd2d27e6b..c542023f15 100644 --- a/Sources/Controllers/Base/OABaseNavbarViewController.m +++ b/Sources/Controllers/Base/OABaseNavbarViewController.m @@ -255,13 +255,22 @@ - (void)updateNavbar - (void)updateUI:(BOOL)animated { - [self reloadData:animated]; + [self updateUI:animated completion:nil]; +} + +- (void)updateUI:(BOOL)animated completion:(void (^)(void))completion +{ + [self reloadData:animated completion:completion]; [self refreshUI]; } -- (void)updateUIWithoutData +- (void)updateUIWithoutData:(void (^)(void))completion { - [self.tableView reconfigureRowsAtIndexPaths:self.tableView.indexPathsForVisibleRows]; + [self.tableView performBatchUpdates:^{ + [self.tableView reconfigureRowsAtIndexPaths:self.tableView.indexPathsForVisibleRows]; + if (completion) + completion(); + } completion:nil]; [self refreshUI]; } @@ -271,7 +280,7 @@ - (void)refreshUI [self updateNavbar]; } -- (void) reloadData:(BOOL)animated +- (void) reloadData:(BOOL)animated completion:(void (^ __nullable)(void))completion { [self generateData]; if (animated) @@ -283,7 +292,12 @@ - (void) reloadData:(BOOL)animated { [self.tableView reloadData]; } - completion:nil]; + completion:^(BOOL finished) + { + if (completion) + completion(); + } + ]; } else { diff --git a/Sources/Controllers/Destinations/DestinationsListViewController.swift b/Sources/Controllers/Destinations/DestinationsListViewController.swift index 061bd8ae0b..ec0df135ce 100644 --- a/Sources/Controllers/Destinations/DestinationsListViewController.swift +++ b/Sources/Controllers/Destinations/DestinationsListViewController.swift @@ -24,7 +24,7 @@ class DestinationsListViewController: OABaseButtonsViewController { if tableData.hasChanged || tableData.sectionCount() == 0 { updateUI(true) } else { - updateUIWithoutData() + updateUIWithoutData(nil) } } } diff --git a/Sources/Controllers/QuickAction/OAQuickActionListViewController.m b/Sources/Controllers/QuickAction/OAQuickActionListViewController.m index 4d5b8ae4e5..867ed593bb 100644 --- a/Sources/Controllers/QuickAction/OAQuickActionListViewController.m +++ b/Sources/Controllers/QuickAction/OAQuickActionListViewController.m @@ -21,20 +21,17 @@ #import "OASwitchTableViewCell.h" #import "OsmAnd_Maps-Swift.h" -#import +@interface OAQuickActionListViewController () -#define kEnableSection 0 - -@interface OAQuickActionListViewController () +@property(nonatomic) BOOL editMode; @end @implementation OAQuickActionListViewController { OAQuickActionRegistry *_registry; - NSMutableArray *_data; - OAAppSettings *_settings; + OATableSectionData *_switchSection; } #pragma mark - Initialization @@ -42,7 +39,32 @@ @implementation OAQuickActionListViewController - (void)commonInit { _registry = [OAQuickActionRegistry sharedInstance]; - _settings = OAAppSettings.sharedManager; + _settings = [OAAppSettings sharedManager]; + + _switchSection = [OATableSectionData sectionData]; + OATableRowData *switchRow = [_switchSection createNewRow]; + switchRow.key = @"pref"; + switchRow.title = OALocalizedString(@"shared_string_enabled"); + switchRow.cellType = [OASwitchTableViewCell getCellIdentifier]; + [switchRow setObj:_settings.quickActionIsOn forKey:@"pref"]; +} + +- (void)setEditMode:(BOOL)editMode +{ + _editMode = editMode; + [self.tableView setEditing:editMode animated:YES]; + if ([self.tableData hasChanged]) + { + [self updateUI:YES completion:^{ + [self updateSwitchSection]; + }]; + } + else + { + [self updateUIWithoutData:^{ + [self updateSwitchSection]; + }]; + } } #pragma mark - UIViewController @@ -52,33 +74,28 @@ - (void)viewDidLoad [super viewDidLoad]; [self.tableView registerClass:OAMultiselectableHeaderView.class forHeaderFooterViewReuseIdentifier:[OATableViewCustomHeaderView getCellIdentifier]]; -} - -- (void) onSwitchPressed:(UISwitch *)sender -{ - [_settings.quickActionIsOn set:sender.isOn]; - [self.delegate onWidgetStateChanged]; + self.tableView.allowsMultipleSelectionDuringEditing = YES; } #pragma mark - Base UI - (NSString *)getTitle { - return self.tableView.editing ? OALocalizedString(@"quick_action_edit_list") : OALocalizedString(@"configure_screen_quick_action"); + return _editMode ? OALocalizedString(@"quick_action_edit_list") : OALocalizedString(@"configure_screen_quick_action"); } - (NSString *)getLeftNavbarButtonTitle { - return self.tableView.editing ? OALocalizedString(@"shared_string_cancel") : nil; + return _editMode ? OALocalizedString(@"shared_string_cancel") : nil; } - (NSArray *)getRightNavbarButtons { - if (self.tableView.editing) + if (_editMode) { return @[[self createRightNavbarButton:OALocalizedString(@"shared_string_done") iconName:nil - action:@selector(donePressed) + action:@selector(onRightNavbarButtonPressed) menu:nil]]; } else @@ -87,15 +104,12 @@ - (NSString *)getLeftNavbarButtonTitle iconName:@"ic_navbar_add" action:@selector(addActionPressed) menu:nil]; - UIBarButtonItem *aditButton = [self createRightNavbarButton:nil iconName:@"ic_navbar_pencil" - action:@selector(editPressed) + action:@selector(onRightNavbarButtonPressed) menu:nil]; - addButton.accessibilityLabel = OALocalizedString(@"shared_string_add"); aditButton.accessibilityLabel = OALocalizedString(@"shared_string_edit"); - return @[addButton, aditButton]; } } @@ -107,7 +121,7 @@ - (EOABaseNavbarColorScheme)getNavbarColorScheme - (NSString *)getTableHeaderDescription { - return OALocalizedString(@"quick_action_add_actions_descr"); + return _editMode ? nil : OALocalizedString(@"quick_action_add_actions_descr"); } - (UILayoutConstraintAxis)getBottomAxisMode @@ -117,12 +131,14 @@ - (UILayoutConstraintAxis)getBottomAxisMode - (NSString *)getTopButtonTitle { - return self.tableView.editing ? OALocalizedString(@"shared_string_select_all") : @""; + return _editMode + ? self.tableView.indexPathsForSelectedRows.count ? OALocalizedString(@"shared_string_deselect_all") : OALocalizedString(@"shared_string_select_all") + : @""; } - (NSString *)getBottomButtonTitle { - return self.tableView.editing ? OALocalizedString(@"shared_string_delete") : @""; + return _editMode ? OALocalizedString(@"shared_string_delete") : @""; } - (EOABaseButtonColorScheme)getTopButtonColorScheme @@ -139,46 +155,34 @@ - (EOABaseButtonColorScheme)getBottomButtonColorScheme - (void)generateData { - _data = [NSMutableArray arrayWithArray:_registry.getQuickActions]; -} - -- (NSInteger)sectionsCount -{ - // Add enable section - return [self getScreensCount] + 1; -} + [self.tableData clearAllData]; -- (UIView *)getCustomViewForHeader:(NSInteger)section -{ - if (section == kEnableSection) - return nil; - OAMultiselectableHeaderView *vw = (OAMultiselectableHeaderView *)[self.tableView dequeueReusableHeaderFooterViewWithIdentifier:[OATableViewCustomHeaderView getCellIdentifier]]; - [vw setTitleText:[NSString stringWithFormat:OALocalizedString(@"quick_action_screen_header"), section]]; - vw.section = section; - vw.delegate = self; - return vw; -} + if (!_editMode) + [self.tableData addSection:_switchSection]; -- (CGFloat)getCustomHeightForHeader:(NSInteger)section -{ - if (section == kEnableSection) - return 0.; - return 46.0; + OATableSectionData *actionsSection = [self.tableData createNewSection]; + for (NSInteger i = 0; i < _registry.getQuickActions.count; i++) + { + OAQuickAction *action = _registry.getQuickActions[i]; + if ([actionsSection rowCount] == 6) + actionsSection = [self.tableData createNewSection]; + OATableRowData *actionRow = [actionsSection createNewRow]; + actionRow.key = @"action"; + actionRow.cellType = [OASimpleTableViewCell getCellIdentifier]; + [actionRow setObj:action forKey:@"action"]; + } + [self.tableData resetChanges]; } -- (NSInteger)rowsCount:(NSInteger)section +- (BOOL)hideFirstHeader { - if (section == kEnableSection) - return 1; - - BOOL oneSection = _data.count / 6 < 1; - BOOL lastSection = section == _data.count / 6; - return oneSection || lastSection ? _data.count % 6 : 6; + return !_editMode; } - (UITableViewCell *)getRow:(NSIndexPath *)indexPath { - if (indexPath.section == kEnableSection) + OATableRowData *item = [self.tableData itemForIndexPath:indexPath]; + if ([item.cellType isEqualToString:[OASwitchTableViewCell getCellIdentifier]]) { OASwitchTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[OASwitchTableViewCell getCellIdentifier]]; if (!cell) @@ -190,8 +194,9 @@ - (UITableViewCell *)getRow:(NSIndexPath *)indexPath } if (cell) { - cell.switchView.on = _settings.quickActionIsOn.get; - cell.titleLabel.text = OALocalizedString(@"shared_string_enabled"); + OACommonBoolean *pref = [item objForKey:@"pref"]; + cell.switchView.on = [pref get]; + cell.titleLabel.text = item.title; cell.switchView.tag = indexPath.section << 10 | indexPath.row; [cell.switchView removeTarget:self action:NULL forControlEvents:UIControlEventValueChanged]; @@ -199,256 +204,375 @@ - (UITableViewCell *)getRow:(NSIndexPath *)indexPath } return cell; } - OAQuickAction *action = [self getAction:indexPath]; - OATitleDescrDraggableCell* cell = (OATitleDescrDraggableCell *)[self.tableView dequeueReusableCellWithIdentifier:[OATitleDescrDraggableCell getCellIdentifier]]; - if (cell == nil) - { - NSArray *nib = [[NSBundle mainBundle] loadNibNamed:[OATitleDescrDraggableCell getCellIdentifier] owner:self options:nil]; - cell = (OATitleDescrDraggableCell *)[nib objectAtIndex:0]; - cell.descView.hidden = YES; - } - - if (cell) + else if ([item.cellType isEqualToString:[OASimpleTableViewCell getCellIdentifier]]) { - [cell.textView setText:action.getName]; - [cell.iconView setImage:[UIImage templateImageNamed:action.getIconResName]]; - [cell.iconView setTintColor:UIColorFromRGB(color_poi_orange)]; - if (cell.iconView.subviews.count > 0) - [[cell.iconView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; - - if (action.hasSecondaryIcon) + OASimpleTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[OASimpleTableViewCell getCellIdentifier]]; + if (!cell) { - CGRect frame = CGRectMake(0., 0., cell.iconView.frame.size.width, cell.iconView.frame.size.height); - UIImage *imgBackground = [UIImage templateImageNamed:@"ic_custom_compound_action_background"]; - UIImageView *background = [[UIImageView alloc] initWithImage:imgBackground]; - [background setTintColor:UIColor.whiteColor]; - [cell.iconView addSubview:background]; - UIImage *img = [UIImage imageNamed:action.getSecondaryIconName]; - UIImageView *view = [[UIImageView alloc] initWithImage:img]; - view.frame = frame; - [cell.iconView addSubview:view]; + NSArray *nib = [[NSBundle mainBundle] loadNibNamed:[OASimpleTableViewCell getCellIdentifier] owner:self options:nil]; + cell = (OASimpleTableViewCell *) nib[0]; + [cell descriptionVisibility:NO]; + cell.leftIconView.tintColor = UIColorFromRGB(color_poi_orange); + cell.tintColor = UIColorFromRGB(color_primary_purple); + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } - cell.delegate = self; - cell.allowsSwipeWhenEditing = NO; - [cell.overflowButton setImage:[UIImage templateImageNamed:@"menu_cell_pointer"] forState:UIControlStateNormal]; - [cell.overflowButton setTintColor:UIColorFromRGB(color_tint_gray)]; - [cell.overflowButton.imageView setContentMode:UIViewContentModeCenter]; - cell.separatorInset = UIEdgeInsetsMake(0.0, 62.0, 0.0, 0.0); - cell.tintColor = UIColorFromRGB(color_primary_purple); - - [cell updateConstraintsIfNeeded]; + if (cell) + { + OAQuickAction *action = [item objForKey:@"action"]; + if (action) + { + cell.titleLabel.text = [action getName]; + cell.leftIconView.image = [UIImage templateImageNamed:[action getIconResName]]; + if ([action hasSecondaryIcon]) + { + CGRect frame = CGRectMake(0., 0., cell.leftIconView.frame.size.width, cell.leftIconView.frame.size.height); + UIImage *imgBackground = [UIImage templateImageNamed:@"ic_custom_compound_action_background"]; + UIImageView *background = [[UIImageView alloc] initWithImage:imgBackground]; + [background setTintColor:UIColor.whiteColor]; + [cell.leftIconView addSubview:background]; + UIImage *img = [UIImage imageNamed:action.getSecondaryIconName]; + UIImageView *view = [[UIImageView alloc] initWithImage:img]; + view.frame = frame; + [cell.leftIconView addSubview:view]; + } + } + } + return cell; } - return cell; + return nil; +} + +- (CGFloat)getCustomHeightForHeader:(NSInteger)section +{ + if (section == 0 && !_editMode) + return [super getCustomHeightForHeader:section]; + + return [OATableViewCustomHeaderView getHeight:[[NSString stringWithFormat:OALocalizedString(@"quick_action_screen_header"), section] upperCase] width:self.tableView.bounds.size.width xOffset:16. yOffset:12. font:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]]; +} + +- (UIView *)getCustomViewForHeader:(NSInteger)section +{ + if (section == 0 && !_editMode) + return nil; + + OAMultiselectableHeaderView *vw = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:[OATableViewCustomHeaderView getCellIdentifier]]; + vw.delegate = self; + [self configureHeader:vw forSection:section]; + + return vw; } - (void)onRowSelected:(NSIndexPath *)indexPath { if (self.tableView.isEditing) + { + [self updateBottomButtons]; return; - - [self openQuickActionSetupFor:indexPath]; -} + } -#pragma mark - UITableViewDataSource + OATableRowData *item = [self.tableData itemForIndexPath:indexPath]; + if ([item.key isEqualToString:@"action"]) + { + OAQuickAction *action = [item objForKey:@"action"]; + if (action) + { + OAActionConfigurationViewController *actionScreen = + [[OAActionConfigurationViewController alloc] initWithAction:action isNew:NO]; + actionScreen.delegate = self; + [self showViewController:actionScreen]; + } + } +} -- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath +- (void)onRowDeselected:(NSIndexPath *)indexPath { - if (_data.count == 1) - return; - - AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); - - OAQuickAction *sourceAction = [self getAction:sourceIndexPath]; - OAQuickAction *destAction = [self getAction:destinationIndexPath]; - destinationIndexPath = [NSIndexPath indexPathForRow:destinationIndexPath.row inSection:destinationIndexPath.section - 1]; - sourceIndexPath = [NSIndexPath indexPathForRow:sourceIndexPath.row inSection:sourceIndexPath.section - 1]; - [_data setObject:sourceAction atIndexedSubscript:destinationIndexPath.section * 6 + destinationIndexPath.row]; - [_data setObject:destAction atIndexedSubscript:sourceIndexPath.section * 6 + sourceIndexPath.row]; - [self.tableView reloadData]; + if (self.tableView.isEditing) + [self updateBottomButtons]; } +#pragma mark - UITableViewDataSource + - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { - return indexPath.section != kEnableSection; + return _editMode; } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { - return indexPath.section != kEnableSection; + return _editMode; } -- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath +- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { - if(proposedDestinationIndexPath.section == kEnableSection) + OATableRowData *sourceItem = [self.tableData itemForIndexPath:sourceIndexPath]; + [self.tableData removeRowAt:sourceIndexPath]; + if (destinationIndexPath.section == sourceIndexPath.section) { - return sourceIndexPath; + [self.tableData addRowAtIndexPath:destinationIndexPath row:sourceItem]; + return; } - else if (proposedDestinationIndexPath.section >= self.sectionsCount) + + OATableSectionData *destinationSectionData = [self.tableData sectionDataForIndex:destinationIndexPath.section]; + if ([destinationSectionData rowCount] < 6) { - NSInteger prevSection = proposedDestinationIndexPath.section - 1; - return [NSIndexPath indexPathForRow:[self rowsCount:prevSection] - 1 inSection:prevSection]; + [destinationSectionData addRow:sourceItem position:destinationIndexPath.row]; + } + else + { + NSMutableArray *rowsToNextSection = [NSMutableArray array]; + for (NSInteger section = destinationIndexPath.section; section < [self.tableData sectionCount]; section++) + { + OATableSectionData *sectionData = [self.tableData sectionDataForIndex:section]; + if (section == destinationIndexPath.section) + [sectionData addRow:sourceItem position:destinationIndexPath.row]; + + if ([sectionData rowCount] > 6) + { + NSMutableArray *indexPathsToDelete = [NSMutableArray array]; + for (NSInteger row = 6; row < [sectionData rowCount]; row++) + { + NSIndexPath *indexPathToDelete = [NSIndexPath indexPathForRow:row inSection:section]; + [indexPathsToDelete addObject:indexPathToDelete]; + [rowsToNextSection addObject:[self.tableData itemForIndexPath:indexPathToDelete]]; + } + for (NSIndexPath *indexPathForDelete in indexPathsToDelete) + { + [sectionData removeRowAtIndex:indexPathForDelete.row]; + } + + if (section == [self.tableData sectionCount] - 1) + { + NSInteger newSectionCount = ceil(rowsToNextSection.count / 6.); + for (NSInteger newSection = 0; newSection < newSectionCount; newSection++) + { + sectionData = [self.tableData createNewSection]; + NSRange range = NSMakeRange(0, MIN(6, rowsToNextSection.count)); + [sectionData addRows:[rowsToNextSection subarrayWithRange:range] position:0]; + [rowsToNextSection removeObjectsInRange:range]; + } + } + else + { + sectionData = [self.tableData sectionDataForIndex:section + 1]; + } + + if (rowsToNextSection.count > 0) + { + [sectionData addRows:rowsToNextSection position:0]; + [rowsToNextSection removeAllObjects]; + } + } + } } - return proposedDestinationIndexPath; + [self.tableView reloadData]; } #pragma mark - Additions -- (void)saveChanges +- (void)configureHeader:(OAMultiselectableHeaderView *)headerView forSection:(NSInteger)section { - [_registry updateQuickActions:[NSArray arrayWithArray:_data]]; - [_registry.quickActionListChangedObservable notifyEvent]; + headerView.section = section; + [headerView setTitleText:[NSString stringWithFormat:OALocalizedString(@"quick_action_screen_header"), !_editMode ? section : (section + 1)]]; } -- (NSInteger)getScreensCount +- (void)reloadHeaders { - NSInteger numOfItems = _data.count; - BOOL oneSection = numOfItems / 6 < 1; - BOOL hasRemainder = numOfItems % 6 != 0; - if (oneSection) - return 1; - else - return (numOfItems / 6) + (hasRemainder ? 1 : 0); + for (NSInteger i = 0; i < [self.tableView numberOfSections]; i++) + { + UITableViewHeaderFooterView *headerView = [self.tableView headerViewForSection:i]; + if ([headerView isKindOfClass:OAMultiselectableHeaderView.class]) + [self configureHeader:(OAMultiselectableHeaderView *) headerView forSection:i]; + } } -- (void)disableEditing +- (void)updateSwitchSection { - [self.tableView beginUpdates]; - [self.tableView setEditing:NO animated:YES]; - [self updateUI:YES]; - [self.tableView endUpdates]; + if (_editMode) + { + [self.tableData removeSection:_switchSection]; + [self.tableData resetChanges]; + [self.tableView performBatchUpdates:^{ + [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; + } completion:^(BOOL finished) { + [self reloadHeaders]; + }]; + } + else if (self.tableData.sectionCount > 0 && [self.tableData sectionDataForIndex:0] != _switchSection) + { + [self.tableData addSection:_switchSection atIndex:0]; + [self.tableData resetChanges]; + [self.tableView performBatchUpdates:^{ + [self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; + } completion:^(BOOL finished) { + [self reloadHeaders]; + }]; + } } -- (OAQuickAction *)getAction:(NSIndexPath *)indexPath +- (void)saveChanges { - NSIndexPath *correctedPath = indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1]; - if (_data.count == 1) - return _data.firstObject; - return _data[6 * correctedPath.section + correctedPath.row]; + if ([self.tableData hasChanged]) + { + NSMutableArray *actions = [NSMutableArray array]; + for (NSInteger section = 0; section < [self.tableData sectionCount]; section++) + { + for (NSInteger row = 0; row < [self.tableData rowCount:section]; row++) + { + OATableRowData *item = [self.tableData itemForIndexPath:[NSIndexPath indexPathForRow:row inSection:section]]; + OAQuickAction *action = [item objForKey:@"action"]; + if (action) + [actions addObject:action]; + } + } + [_registry updateQuickActions:actions]; + [_registry.quickActionListChangedObservable notifyEvent]; + } } -- (void)openQuickActionSetupFor:(NSIndexPath *)indexPath +- (void)showUnsavedChangesAlert:(BOOL)shouldDismiss { - OAQuickAction *item = [self getAction:indexPath]; - OAActionConfigurationViewController *actionScreen = [[OAActionConfigurationViewController alloc] initWithAction:item isNew:NO]; - actionScreen.delegate = self; - [self.navigationController pushViewController:actionScreen animated:YES]; + UIAlertController *alert = [UIAlertController alertControllerWithTitle: OALocalizedString(@"unsaved_changes") + message: OALocalizedString(@"unsaved_changes_will_be_lost_discard") + preferredStyle:UIAlertControllerStyleActionSheet]; + [alert addAction:[UIAlertAction actionWithTitle:OALocalizedString(@"shared_string_discard") + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * _Nonnull action) { + self.editMode = NO; + if (shouldDismiss) + [self dismissViewController]; + }]]; + [alert addAction:[UIAlertAction actionWithTitle:OALocalizedString(@"shared_string_cancel") + style:UIAlertActionStyleCancel + handler:nil]]; + UIPopoverPresentationController *popPresenter = alert.popoverPresentationController; + popPresenter.barButtonItem = [self getLeftNavbarButton]; + popPresenter.permittedArrowDirections = UIPopoverArrowDirectionAny; + [self presentViewController:alert animated:YES completion:nil]; } #pragma mark - Selectors -- (void)editPressed -{ - [self.tableView beginUpdates]; - [self.tableView setEditing:YES animated:YES]; - self.tableView.allowsMultipleSelectionDuringEditing = YES; - [self updateUI:YES]; - [self.tableView endUpdates]; -} - - (void)onLeftNavbarButtonPressed { - [self disableEditing]; - _data = [NSMutableArray arrayWithArray:_registry.getQuickActions]; - [self.tableView reloadData]; -} - -- (void)donePressed -{ - [self disableEditing]; - [self saveChanges]; + if (_editMode) + { + if ([self.tableData hasChanged]) + [self showUnsavedChangesAlert:NO]; + else + self.editMode = NO; + return; + } + [super onLeftNavbarButtonPressed]; } -- (void)addActionPressed +- (void)onRightNavbarButtonPressed { - OAAddQuickActionViewController *vc = [[OAAddQuickActionViewController alloc] init]; - vc.delegate = self; - [self.navigationController pushViewController:vc animated:YES]; + if (_editMode) + [self saveChanges]; + self.editMode = !_editMode; } - (void)onTopButtonPressed { - NSInteger sections = self.tableView.numberOfSections; - - [self.tableView beginUpdates]; - for (NSInteger section = 0; section < sections; section++) + if ([self.tableView indexPathsForSelectedRows].count > 0) { - NSInteger rowsCount = [self.tableView numberOfRowsInSection:section]; - for (NSInteger row = 0; row < rowsCount; row++) + for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) { - [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:YES scrollPosition:UITableViewScrollPositionNone]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; } } - [self.tableView endUpdates]; + else + { + for (NSInteger section = 0; section < [self.tableData sectionCount]; section++) + { + for (NSInteger row = 0; row < [self.tableData rowCount:section]; row++) + { + [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] + animated:YES + scrollPosition:UITableViewScrollPositionNone]; + } + } + } + [self updateBottomButtons]; } - (void)onBottomButtonPressed { - NSArray *indexes = [self.tableView indexPathsForSelectedRows]; + NSArray *indexes = [self.tableView indexPathsForSelectedRows]; + if (indexes.count > 0) { + NSMutableArray *sectionsToRemove = [NSMutableArray array]; + for (NSInteger section = 0; section < [self.tableData sectionCount]; section++) + { + if ([NSIndexPath getRowsCount:section at:indexes] == [self.tableData rowCount:section]) + [sectionsToRemove addObject:[NSIndexSet indexSetWithIndex:section]]; + } + UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message: [NSString stringWithFormat:OALocalizedString(@"confirm_bulk_delete"), indexes.count] preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:OALocalizedString(@"shared_string_cancel") style:UIAlertActionStyleDefault handler:nil]]; - [alert addAction:[UIAlertAction actionWithTitle:OALocalizedString(@"shared_string_ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - NSMutableArray *dataCopy = [NSMutableArray arrayWithArray:_data]; - for (NSIndexPath *path in indexes) - { - OAQuickAction *item = [self getAction:path]; - [dataCopy removeObject:item]; - } - _data = dataCopy; - [self saveChanges]; - [self.tableView reloadData]; - [self editPressed]; + [alert addAction:[UIAlertAction actionWithTitle:OALocalizedString(@"shared_string_ok") style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { + [self.tableData removeItemsAtIndexPaths:indexes]; + [self.tableView performBatchUpdates:^{ + [self.tableView deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationAutomatic]; + if (sectionsToRemove.count > 0) + { + for (NSIndexSet *section in sectionsToRemove) + { + [self.tableView deleteSections:section withRowAnimation:UITableViewRowAnimationAutomatic]; + } + } + } completion:^(BOOL finished) { + [self updateBottomButtons]; + }]; }]]; [self presentViewController:alert animated:YES completion:nil]; } } -#pragma mark - Swipe Delegate - -- (BOOL)swipeTableCell:(MGSwipeTableCell *)cell canSwipe:(MGSwipeDirection)direction; +- (void)onSwitchPressed:(UISwitch *)sender { - return self.tableView.isEditing; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag & 0x3FF inSection:sender.tag >> 10]; + OATableRowData *item = [self.tableData itemForIndexPath:indexPath]; + if ([item.key isEqual:@"pref"]) + { + OACommonBoolean *pref = [item objForKey:@"pref"]; + [pref set:sender.isOn]; + [self.delegate onWidgetStateChanged]; + } } -- (void)swipeTableCell:(MGSwipeTableCell *)cell didChangeSwipeState:(MGSwipeState)state gestureIsActive:(BOOL)gestureIsActive +- (void)addActionPressed { - if (state != MGSwipeStateNone) - cell.showsReorderControl = NO; - else - cell.showsReorderControl = YES; + OAAddQuickActionViewController *vc = [[OAAddQuickActionViewController alloc] init]; + vc.delegate = self; + [self showViewController:vc]; } #pragma mark - OAMultiselectableHeaderDelegate - (void)headerCheckboxChanged:(id)sender value:(BOOL)value { - OAMultiselectableHeaderView *headerView = (OAMultiselectableHeaderView *)sender; + OAMultiselectableHeaderView *headerView = (OAMultiselectableHeaderView *) sender; NSInteger section = headerView.section; - NSInteger rowsCount = [self.tableView numberOfRowsInSection:section]; - - [self.tableView beginUpdates]; - if (value) - { - for (int i = 0; i < rowsCount; i++) - [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:section] animated:YES scrollPosition:UITableViewScrollPositionNone]; - } - else + for (int i = 0; i < [self.tableData rowCount:section]; i++) { - for (int i = 0; i < rowsCount; i++) - [self.tableView deselectRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:section] animated:YES]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:section]; + if (value) + [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; + else + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; } - [self.tableView endUpdates]; } #pragma mark - OAQuickActionListDelegate - (void)updateData { - _data = [NSMutableArray arrayWithArray:_registry.getQuickActions]; - [self.tableView reloadData]; + [self updateUI:YES]; } @end diff --git a/Sources/Controllers/Settings/WidgetSettings/WidgetsListViewController.swift b/Sources/Controllers/Settings/WidgetSettings/WidgetsListViewController.swift index c32b50ba9f..5693e46f7f 100644 --- a/Sources/Controllers/Settings/WidgetSettings/WidgetsListViewController.swift +++ b/Sources/Controllers/Settings/WidgetSettings/WidgetsListViewController.swift @@ -35,8 +35,9 @@ class WidgetsListViewController: BaseSegmentedControlViewController { if tableData.hasChanged || tableData.sectionCount() == 0 { updateUI(true) } else { - updateUIWithoutData() + updateUIWithoutData(nil) } + updateAppearance() } } @@ -359,7 +360,7 @@ extension WidgetsListViewController { tableData.addRow(at: movedIndexPath, row: movableItem) tableView.moveRow(at: movableIndexPath, to: movedIndexPath) } - tableData.removeSection(UInt(indexPath.section)) + tableData.removeSection(at: UInt(indexPath.section)) tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic) if editMode { tableView.reloadData() diff --git a/Sources/Helpers/Extensions.swift b/Sources/Helpers/Extensions.swift index bae0b1299d..c58fd82e73 100644 --- a/Sources/Helpers/Extensions.swift +++ b/Sources/Helpers/Extensions.swift @@ -56,3 +56,11 @@ extension NSMutableAttributedString { } } + +@objc extension NSIndexPath { + + @objc static func getRowsCount(_ section: UInt, at indexPaths: [NSIndexPath]) -> Int { + return indexPaths.filter { $0.section == section }.count + } + +} diff --git a/Sources/Models/OATableDataModel.h b/Sources/Models/OATableDataModel.h index 746a9c4f30..3b1a82f234 100644 --- a/Sources/Models/OATableDataModel.h +++ b/Sources/Models/OATableDataModel.h @@ -23,7 +23,8 @@ - (void) addSection:(OATableSectionData *_Nonnull)sectionData atIndex:(NSInteger)index; - (void) addRowAtIndexPath:(NSIndexPath *_Nonnull)indexPath row:(OATableRowData *_Nonnull)row; - (void) removeRowAt:(NSIndexPath *_Nonnull)indexPath; -- (void) removeSection:(NSUInteger)section; +- (void) removeSectionAt:(NSUInteger)index; +- (void) removeSection:(OATableSectionData *_Nonnull)sectionData; - (void) removeItemsAtIndexPaths:(NSArray *_Nonnull)indexPaths; - (OATableSectionData *_Nonnull)sectionDataForIndex:(NSUInteger)index; diff --git a/Sources/Models/OATableDataModel.m b/Sources/Models/OATableDataModel.m index a73c7af369..44a76fc079 100644 --- a/Sources/Models/OATableDataModel.m +++ b/Sources/Models/OATableDataModel.m @@ -50,9 +50,15 @@ - (void)addSection:(OATableSectionData *)sectionData atIndex:(NSInteger)index [_sectionData insertObject:sectionData atIndex:index]; } -- (void)removeSection:(NSUInteger)section +- (void)removeSectionAt:(NSUInteger)index { - [_sectionData removeObjectAtIndex:section]; + [_sectionData removeObjectAtIndex:index]; + _hasChanged = YES; +} + +- (void)removeSection:(OATableSectionData *)section +{ + [_sectionData removeObject:section]; _hasChanged = YES; } @@ -63,6 +69,9 @@ - (void)removeRowAt:(NSIndexPath *)indexPath - (void)removeItemsAtIndexPaths:(NSArray *)indexPaths { + indexPaths = [indexPaths sortedArrayUsingComparator:^NSComparisonResult(NSIndexPath * _Nonnull indexPath1, NSIndexPath * _Nonnull indexPath2) { + return [self compareDescendingNSIndexPath:indexPath1 indexPath2:indexPath2]; + }]; for (NSIndexPath *indexPath in indexPaths) { [_sectionData[indexPath.section] removeRowAtIndex:indexPath.row]; @@ -79,7 +88,7 @@ - (void)removeItemsAtIndexPaths:(NSArray *)indexPaths { for (NSNumber *section in [emptySections sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:nil ascending:NO]]]) { - [self removeSection:section.intValue]; + [self removeSectionAt:section.intValue]; } } } @@ -134,4 +143,25 @@ - (void) resetChanges [data resetChanges]; } +- (NSComparisonResult)compareDescendingNSIndexPath:(NSIndexPath *)indexPath1 indexPath2:(NSIndexPath *)indexPath2 +{ + if (indexPath1.section > indexPath2.section) + { + return NSOrderedAscending; + } + else if (indexPath1.section < indexPath2.section) + { + return NSOrderedDescending; + } + else + { + if (indexPath1.row > indexPath2.row) + return NSOrderedAscending; + else if (indexPath1.row < indexPath2.row) + return NSOrderedDescending; + else + return NSOrderedSame; + } +} + @end diff --git a/Sources/Models/OATableSectionData.h b/Sources/Models/OATableSectionData.h index 5a789c2f36..5025c6f821 100644 --- a/Sources/Models/OATableSectionData.h +++ b/Sources/Models/OATableSectionData.h @@ -23,9 +23,10 @@ NS_ASSUME_NONNULL_BEGIN - (OATableRowData *) createNewRow; - (OATableRowData *) getRow:(NSUInteger)index; +- (void)addRow:(OATableRowData *)rowData position:(NSUInteger)position; - (void)addRow:(OATableRowData *)rowData; - (void)addRows:(NSArray *)rows; -- (void)addRow:(OATableRowData *)rowData position:(NSUInteger)position; +- (void)addRows:(NSArray *)rows position:(NSUInteger)position; - (OATableRowData *) addRowFromDictionary:(NSDictionary *)dictionary; - (void)removeRowAtIndex:(NSInteger)index; - (void)removeAllRows; diff --git a/Sources/Models/OATableSectionData.m b/Sources/Models/OATableSectionData.m index ade64068dd..5b9daf9383 100644 --- a/Sources/Models/OATableSectionData.m +++ b/Sources/Models/OATableSectionData.m @@ -80,6 +80,12 @@ - (void)addRows:(NSArray *)rows _hasChanged = YES; } +- (void)addRows:(NSArray *)rows position:(NSUInteger)position +{ + [_rowData insertObjects:rows atIndexes:[NSIndexSet indexSetWithIndex:position]]; + _hasChanged = YES; +} + - (OATableRowData *) addRowFromDictionary:(NSDictionary *)dictionary { OATableRowData *row = [[OATableRowData alloc] initWithData:dictionary];