diff --git a/iphone/Maps/Bookmarks/BookmarksSection.h b/iphone/Maps/Bookmarks/BookmarksSection.h index 89a6cd5c54..8af19136a9 100644 --- a/iphone/Maps/Bookmarks/BookmarksSection.h +++ b/iphone/Maps/Bookmarks/BookmarksSection.h @@ -1,24 +1,14 @@ +#import "MWMTypes.h" #import "TableSectionDataSource.h" -#include "kml/type_utils.hpp" - -@class BookmarksSection; - -@protocol BookmarksSectionDelegate - -- (NSInteger)numberOfBookmarksInSection:(BookmarksSection *)bookmarkSection; -- (NSString *)titleOfBookmarksSection:(BookmarksSection *)bookmarkSection; -- (BOOL)canEditBookmarksSection:(BookmarksSection *)bookmarkSection; -- (kml::MarkId)bookmarkSection:(BookmarksSection *)bookmarkSection getBookmarkIdByRow:(NSInteger)row; -- (BOOL)bookmarkSection:(BookmarksSection *)bookmarkSection onDeleteBookmarkInRow:(NSInteger)row; - -@end +NS_ASSUME_NONNULL_BEGIN @interface BookmarksSection : NSObject -@property(nullable, nonatomic) NSNumber *blockIndex; - -- (instancetype)initWithDelegate:(id)delegate; -- (instancetype)initWithBlockIndex:(NSNumber *)blockIndex delegate:(id)delegate; +- (instancetype)initWithTitle:(nullable NSString *)title + markIds:(MWMMarkIDCollection)markIds + isEditable:(BOOL)isEditable; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/BookmarksSection.mm b/iphone/Maps/Bookmarks/BookmarksSection.mm index 048ea39b8e..90a4fa7504 100644 --- a/iphone/Maps/Bookmarks/BookmarksSection.mm +++ b/iphone/Maps/Bookmarks/BookmarksSection.mm @@ -8,41 +8,48 @@ #include "geometry/distance_on_sphere.hpp" +NS_ASSUME_NONNULL_BEGIN + namespace { CGFloat const kPinDiameter = 22.0f; } // namespace -@interface BookmarksSection () - -@property(weak, nonatomic) id delegate; +@interface BookmarksSection () { + NSString *m_title; + NSMutableArray *m_markIds; + BOOL m_isEditable; +} @end @implementation BookmarksSection -- (instancetype)initWithDelegate:(id)delegate { - return [self initWithBlockIndex:nil delegate:delegate]; -} - -- (instancetype)initWithBlockIndex:(NSNumber *)blockIndex delegate:(id)delegate { +- (instancetype)initWithTitle:(nullable NSString *)title + markIds:(MWMMarkIDCollection)markIds + isEditable:(BOOL)isEditable { self = [super init]; if (self) { - _blockIndex = blockIndex; - _delegate = delegate; + m_title = title; + m_markIds = markIds.mutableCopy; + m_isEditable = isEditable; } return self; } -- (NSInteger)numberOfRows { - return [self.delegate numberOfBookmarksInSection:self]; +- (kml::MarkId)getMarkIdForRow:(NSInteger)row { + return static_cast(m_markIds[row].unsignedLongLongValue); } -- (NSString *)title { - return [self.delegate titleOfBookmarksSection:self]; +- (NSInteger)numberOfRows { + return [m_markIds count]; +} + +- (nullable NSString *)title { + return m_title; } - (BOOL)canEdit { - return [self.delegate canEditBookmarksSection:self]; + return m_isEditable; } - (void)fillCell:(UITableViewCell *)cell @@ -74,9 +81,8 @@ CGFloat const kPinDiameter = 22.0f; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"BookmarksVCBookmarkItemCell"]; } - CHECK(cell, ("Invalid bookmark cell.")); - kml::MarkId const bmId = [self.delegate bookmarkSection:self getBookmarkIdByRow:row]; + auto const bmId = [self getMarkIdForRow:row]; auto const &bm = GetFramework().GetBookmarkManager(); Bookmark const *bookmark = bm.GetBookmark(bmId); cell.textLabel.text = @(bookmark->GetPreferredName().c_str()); @@ -91,7 +97,7 @@ CGFloat const kPinDiameter = 22.0f; } - (void)updateCell:(UITableViewCell *)cell forRow:(NSInteger)row withNewLocation:(location::GpsInfo const &)info { - kml::MarkId const bmId = [self.delegate bookmarkSection:self getBookmarkIdByRow:row]; + auto const bmId = [self getMarkIdForRow:row]; auto const &bm = GetFramework().GetBookmarkManager(); Bookmark const *bookmark = bm.GetBookmark(bmId); if (!bookmark) @@ -101,7 +107,7 @@ CGFloat const kPinDiameter = 22.0f; } - (BOOL)didSelectRow:(NSInteger)row { - kml::MarkId const bmId = [self.delegate bookmarkSection:self getBookmarkIdByRow:row]; + auto const bmId = [self getMarkIdForRow:row]; [Statistics logEvent:kStatEventName(kStatBookmarks, kStatShowOnMap)]; // Same as "Close". [MWMSearchManager manager].state = MWMSearchManagerStateHidden; @@ -109,10 +115,12 @@ CGFloat const kPinDiameter = 22.0f; return YES; } -- (BOOL)deleteRow:(NSInteger)row { - kml::MarkId const bmId = [self.delegate bookmarkSection:self getBookmarkIdByRow:row]; +- (void)deleteRow:(NSInteger)row { + auto const bmId = [self getMarkIdForRow:row]; [[MWMBookmarksManager sharedManager] deleteBookmark:bmId]; - return [self.delegate bookmarkSection:self onDeleteBookmarkInRow:row]; + [m_markIds removeObjectAtIndex:row]; } @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/BookmarksVC.h b/iphone/Maps/Bookmarks/BookmarksVC.h index a8286f60af..be03b77e57 100644 --- a/iphone/Maps/Bookmarks/BookmarksVC.h +++ b/iphone/Maps/Bookmarks/BookmarksVC.h @@ -1,6 +1,8 @@ #import "MWMViewController.h" #import "MWMTypes.h" +NS_ASSUME_NONNULL_BEGIN + @class BookmarksVC; @protocol BookmarksVCDelegate @@ -17,6 +19,8 @@ @property (weak, nonatomic) id delegate; -- (instancetype)initWithCategory:(MWMMarkGroupID)index; +- (instancetype)initWithCategory:(MWMMarkGroupID)categoryId; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/BookmarksVC.mm b/iphone/Maps/Bookmarks/BookmarksVC.mm index bee1472eb6..81d7eb2d0c 100644 --- a/iphone/Maps/Bookmarks/BookmarksVC.mm +++ b/iphone/Maps/Bookmarks/BookmarksVC.mm @@ -1,5 +1,6 @@ #import "BookmarksVC.h" #import "BookmarksSection.h" +#import "InfoSection.h" #import "MWMBookmarksManager.h" #import "MWMCategoryInfoCell.h" #import "MWMCommon.h" @@ -22,6 +23,8 @@ #include #include +NS_ASSUME_NONNULL_BEGIN + using namespace std; @interface BookmarksVC () { - NSMutableArray> *m_sectionsCollection; - BookmarkManager::SortedBlocksCollection m_sortedBlocks; - search::BookmarksSearchParams::Results m_searchResults; + NSMutableArray> *m_defaultSections; + NSMutableArray> *m_searchSections; } @property(nonatomic) NSUInteger lastSearchId; @@ -72,52 +72,112 @@ using namespace std; @implementation BookmarksVC -- (instancetype)initWithCategory:(MWMMarkGroupID)index -{ +- (instancetype)initWithCategory:(MWMMarkGroupID)categoryId { self = [super init]; if (self) { - m_categoryId = index; - m_sectionsCollection = [NSMutableArray array]; - [self calculateSections]; + m_categoryId = categoryId; } return self; } -- (BOOL)isSearchMode { - return !m_searchResults.empty(); +- (BOOL)isEditable { + return [[MWMBookmarksManager sharedManager] isCategoryEditable:m_categoryId]; } -- (BOOL)isSortMode { - return ![self isSearchMode] && !m_sortedBlocks.empty(); +- (NSMutableArray> *)currentSections { + if (m_searchSections != nil) + return m_searchSections; + return m_defaultSections; } -- (void)calculateSections { - [m_sectionsCollection removeAllObjects]; - - if ([self isSearchMode]) { - [m_sectionsCollection addObject:[[BookmarksSection alloc] initWithDelegate:self]]; - return; - } - - if ([self isSortMode]) { - NSInteger blockIndex = 0; - for (auto const &block : m_sortedBlocks) { - if (!block.m_markIds.empty()) - [m_sectionsCollection addObject:[[BookmarksSection alloc] initWithBlockIndex:@(blockIndex++) delegate:self]]; - } - return; - } +- (void)setCategorySections { + if (m_defaultSections == nil) + m_defaultSections = [[NSMutableArray alloc] init]; + else + [m_defaultSections removeAllObjects]; auto const &bm = GetFramework().GetBookmarkManager(); - if (bm.IsCategoryFromCatalog(m_categoryId)) - [m_sectionsCollection addObject:[[InfoSection alloc] initWithDelegate:self]]; + if (bm.IsCategoryFromCatalog(m_categoryId)) { + [m_defaultSections addObject:[[InfoSection alloc] initWithCategoryId:m_categoryId + expanded:self.infoExpanded + observer:self]]; + } - if (bm.GetTrackIds(m_categoryId).size() > 0) - [m_sectionsCollection addObject:[[TracksSection alloc] initWithDelegate:self]]; + if (bm.GetTrackIds(m_categoryId).size() > 0) { + [m_defaultSections addObject:[[TracksSection alloc] + initWithTitle:L(@"tracks_title") + trackIds:[[MWMBookmarksManager sharedManager] trackIdsForCategory:m_categoryId] + isEditable:[self isEditable]]]; + } - if (bm.GetUserMarkIds(m_categoryId).size() > 0) - [m_sectionsCollection addObject:[[BookmarksSection alloc] initWithDelegate:self]]; + if (bm.GetUserMarkIds(m_categoryId).size() > 0) { + [m_defaultSections addObject:[[BookmarksSection alloc] initWithTitle:L(@"bookmarks") + markIds:[[MWMBookmarksManager sharedManager] + bookmarkIdsForCategory:m_categoryId] + isEditable:[self isEditable]]]; + } +} + +- (void)setSortedSections:(BookmarkManager::SortedBlocksCollection const &)sortResults { + if (m_defaultSections == nil) + m_defaultSections = [[NSMutableArray alloc] init]; + else + [m_defaultSections removeAllObjects]; + + for (auto const &block : sortResults) { + if (!block.m_markIds.empty()) { + [m_defaultSections addObject:[[BookmarksSection alloc] initWithTitle:@(block.m_blockName.c_str()) + markIds:[BookmarksVC bookmarkIds:block.m_markIds] + isEditable:[self isEditable]]]; + } else if (!block.m_trackIds.empty()) { + [m_defaultSections addObject:[[TracksSection alloc] initWithTitle:@(block.m_blockName.c_str()) + trackIds:[BookmarksVC trackIds:block.m_trackIds] + isEditable:[self isEditable]]]; + } + } +} + +- (void)setSearchSections:(search::BookmarksSearchParams::Results const &)searchResults { + if (m_searchSections == nil) { + m_searchSections = [[NSMutableArray alloc] init]; + } else { + [m_searchSections removeAllObjects]; + } + + [m_searchSections addObject:[[BookmarksSection alloc] initWithTitle:nil + markIds:[BookmarksVC bookmarkIds:searchResults] + isEditable:[self isEditable]]]; +} + +- (void)refreshDefaultSections { + if (m_defaultSections != nil) + return; + + [self setCategorySections]; + [self updateControlsVisibility]; + + auto const &bm = GetFramework().GetBookmarkManager(); + BookmarkManager::SortingType lastSortingType; + if (bm.GetLastSortingType(m_categoryId, lastSortingType)) { + auto const availableSortingTypes = [self getAvailableSortingTypes]; + for (auto availableType : availableSortingTypes) { + if (availableType == lastSortingType) { + [self sort:lastSortingType]; + break; + } + } + } +} + +- (void)updateControlsVisibility { + if ([self isEditable] && [[MWMBookmarksManager sharedManager] isCategoryNotEmpty:m_categoryId]) { + self.navigationItem.rightBarButtonItem = self.editButtonItem; + self.sortItem.enabled = YES; + } else { + self.navigationItem.rightBarButtonItem = nil; + self.sortItem.enabled = NO; + } } - (void)viewDidLoad { @@ -129,12 +189,6 @@ using namespace std; self.searchBar.backgroundImage = [UIImage imageWithColor:searchBarColor]; self.searchBar.placeholder = L(@"search"); - auto const & bm = GetFramework().GetBookmarkManager(); - auto const searchAllowed = !bm.IsCategoryFromCatalog(m_categoryId); - - self.showSearchBar.priority = searchAllowed ? UILayoutPriorityRequired : UILayoutPriorityDefaultLow; - self.hideSearchBar.priority = searchAllowed ? UILayoutPriorityDefaultLow : UILayoutPriorityRequired; - [self.noResultsView setTranslatesAutoresizingMaskIntoConstraints:NO]; self.tableView.estimatedRowHeight = 44; @@ -159,47 +213,29 @@ using namespace std; self.downloadedCategoryToolbar.barTintColor = [UIColor white]; [self showSpinner:NO]; + + [self refreshDefaultSections]; } - (void)viewWillAppear:(BOOL)animated { [MWMLocationManager addObserver:self]; - auto const &bm = GetFramework().GetBookmarkManager(); - - // Display Edit button only if table is not empty - if ([[MWMBookmarksManager sharedManager] isCategoryEditable:m_categoryId]) - { + bool searchAllowed = false; + if ([self isEditable]) { + if ([[MWMBookmarksManager sharedManager] isCategoryNotEmpty:m_categoryId]) + searchAllowed = true; self.myCategoryToolbar.hidden = NO; self.downloadedCategoryToolbar.hidden = YES; - if ([[MWMBookmarksManager sharedManager] isCategoryNotEmpty:m_categoryId]) - { - self.navigationItem.rightBarButtonItem = self.editButtonItem; - self.sortItem.enabled = YES; - - BookmarkManager::SortingType type; - if (bm.GetLastSortingType(m_categoryId, type)) { - auto const availableSortingTypes = [self getAvailableSortingTypes]; - for (auto availableType : availableSortingTypes) { - if (availableType == type) { - [self sort:type]; - break; - } - } - } - } - else - { - self.sortItem.enabled = NO; - } - } - else - { + } else { self.myCategoryToolbar.hidden = YES; self.downloadedCategoryToolbar.hidden = NO; } + self.showSearchBar.priority = searchAllowed ? UILayoutPriorityRequired : UILayoutPriorityDefaultLow; + self.hideSearchBar.priority = searchAllowed ? UILayoutPriorityDefaultLow : UILayoutPriorityRequired; [super viewWillAppear:animated]; + auto const &bm = GetFramework().GetBookmarkManager(); self.title = @(bm.GetCategoryName(m_categoryId).c_str()); } @@ -348,18 +384,6 @@ using namespace std; }]; } -+ (NSString *)getLocalizedSortingType:(BookmarkManager::SortingType)type { - switch (type) { - case BookmarkManager::SortingType::ByTime: - return L(@"sort_date"); - case BookmarkManager::SortingType::ByDistance: - return L(@"sort_distance"); - case BookmarkManager::SortingType::ByType: - return L(@"sort_type"); - } - UNREACHABLE(); -} - - (std::vector)getAvailableSortingTypes { CLLocation *lastLocation = [MWMLocationManager lastLocation]; bool const hasMyPosition = lastLocation != nil; @@ -371,8 +395,7 @@ using namespace std; - (void)sortDefault { auto &bm = GetFramework().GetBookmarkManager(); bm.ResetLastSortingType(self->m_categoryId); - self->m_sortedBlocks.clear(); - [self calculateSections]; + [self setCategorySections]; [self.tableView reloadData]; } @@ -407,8 +430,7 @@ using namespace std; self.sortItem.enabled = YES; if (status == BookmarkManager::SortParams::Status::Completed) { - m_sortedBlocks = std::move(sortedBlocks); - [self calculateSections]; + [self setSortedSections:sortedBlocks]; [self.tableView reloadData]; } }; @@ -419,20 +441,6 @@ using namespace std; bm.GetSortedBookmarks(sortParams); } -- (BookmarkManager::SortedBlock &)sortedBlockForIndex:(NSNumber *)blockIndex { - CHECK(blockIndex != nil, ()); - NSInteger index = blockIndex.integerValue; - CHECK_LESS(index, m_sortedBlocks.size(), ()); - return m_sortedBlocks[index]; -} - -- (void)deleteSortedBlockForIndex:(NSNumber *)blockIndex { - CHECK(blockIndex != nil, ()); - NSInteger index = blockIndex.integerValue; - CHECK_LESS(index, m_sortedBlocks.size(), ()); - m_sortedBlocks.erase(m_sortedBlocks.begin() + index); -} - - (UIActivityIndicatorView *)sortSpinner { if (!_sortSpinner) { _sortSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; @@ -450,12 +458,12 @@ using namespace std; - (void)cancelSearch { GetFramework().CancelSearch(search::Mode::Bookmarks); - m_searchResults.clear(); [self showNoResultsView:NO]; [self showSpinner:NO]; - [self calculateSections]; + m_searchSections = nil; + [self refreshDefaultSections]; [self.tableView reloadData]; } @@ -531,6 +539,36 @@ using namespace std; [self.tableView setEditing:editing animated:animated]; } +#pragma mark - MWMBookmarkVC + ++ (MWMMarkIDCollection)bookmarkIds:(std::vector const &)markIds { + NSMutableArray *collection = [[NSMutableArray alloc] initWithCapacity:markIds.size()]; + for (auto const &markId : markIds) { + [collection addObject:@(markId)]; + } + return collection.copy; +} + ++ (MWMTrackIDCollection)trackIds:(std::vector const &)trackIds { + NSMutableArray *collection = [[NSMutableArray alloc] initWithCapacity:trackIds.size()]; + for (auto const &trackId : trackIds) { + [collection addObject:@(trackId)]; + } + return collection.copy; +} + ++ (NSString *)getLocalizedSortingType:(BookmarkManager::SortingType)type { + switch (type) { + case BookmarkManager::SortingType::ByTime: + return L(@"sort_date"); + case BookmarkManager::SortingType::ByDistance: + return L(@"sort_distance"); + case BookmarkManager::SortingType::ByType: + return L(@"sort_type"); + } + UNREACHABLE(); +} + #pragma mark - UISearchBarDelegate - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { @@ -583,7 +621,7 @@ using namespace std; auto const &bm = GetFramework().GetBookmarkManager(); auto filteredResults = results; bm.FilterInvalidBookmarks(filteredResults); - self->m_searchResults = filteredResults; + [self setSearchSections:filteredResults]; if (status == search::BookmarksSearchParams::Status::Cancelled) { [self showSpinner:NO]; @@ -592,7 +630,6 @@ using namespace std; [self showSpinner:NO]; } - [self calculateSections]; [self.tableView reloadData]; }; @@ -604,19 +641,19 @@ using namespace std; #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return [m_sectionsCollection count]; + return [[self currentSections] count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return [m_sectionsCollection[section] numberOfRows]; + return [[self currentSections][section] numberOfRows]; } -- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - return [m_sectionsCollection[section] title]; +- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + return [[self currentSections][section] title]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell *cell = [m_sectionsCollection[indexPath.section] tableView:tableView cellForRow:indexPath.row]; + UITableViewCell *cell = [[self currentSections][indexPath.section] tableView:tableView cellForRow:indexPath.row]; cell.backgroundColor = [UIColor white]; cell.textLabel.textColor = [UIColor blackPrimaryText]; @@ -628,7 +665,7 @@ using namespace std; // Remove cell selection [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; - auto const close = [m_sectionsCollection[indexPath.section] didSelectRow:indexPath.row]; + auto const close = [[self currentSections][indexPath.section] didSelectRow:indexPath.row]; [self.searchBar resignFirstResponder]; @@ -637,34 +674,38 @@ using namespace std; } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { - return [m_sectionsCollection[indexPath.section] canEdit]; + return [[self currentSections][indexPath.section] canEdit]; } - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath { self.editing = YES; } -- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath { +- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(nullable NSIndexPath *)indexPath { self.editing = NO; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - if (![m_sectionsCollection[indexPath.section] canEdit]) + if (![[self currentSections][indexPath.section] canEdit]) return; - BOOL emptySection = NO; - if (editingStyle == UITableViewCellEditingStyleDelete) - emptySection = [m_sectionsCollection[indexPath.section] deleteRow:indexPath.row]; + if (editingStyle == UITableViewCellEditingStyleDelete) { + [[self currentSections][indexPath.section] deleteRow:indexPath.row]; + // In the case of search sections editing reset cached default sections. + if (m_searchSections != nil) + m_defaultSections = nil; + [self updateControlsVisibility]; + } - [self calculateSections]; - - // We can delete the row with animation, if the sections stay the same. - if (!emptySection) + if ([[self currentSections][indexPath.section] numberOfRows] == 0) { + [[self currentSections] removeObjectAtIndex:indexPath.section]; + auto indexSet = [NSIndexSet indexSetWithIndex:indexPath.section]; + [self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade]; + } else { [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; - else - [self.tableView reloadData]; + } auto const &bm = GetFramework().GetBookmarkManager(); if (bm.GetUserMarkIds(m_categoryId).size() + bm.GetTrackIds(m_categoryId).size() == 0) { @@ -679,181 +720,11 @@ using namespace std; header.textLabel.font = [UIFont medium14]; } -#pragma mark - BookmarksSectionDelegate +#pragma mark - InfoSectionObserver -- (NSInteger)numberOfBookmarksInSection:(BookmarksSection *)bookmarkSection { - if ([self isSearchMode]) { - return m_searchResults.size(); - } - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:bookmarkSection.blockIndex]; - return sortedBlock.m_markIds.size(); - } - auto const &bm = GetFramework().GetBookmarkManager(); - return bm.GetUserMarkIds(m_categoryId).size(); -} - -- (NSString *)titleOfBookmarksSection:(BookmarksSection *)bookmarkSection { - if ([self isSearchMode]) - return nil; - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:bookmarkSection.blockIndex]; - return @(sortedBlock.m_blockName.c_str()); - } - - return L(@"bookmarks"); -} - -- (BOOL)canEditBookmarksSection:(BookmarksSection *)bookmarkSection { - return [[MWMBookmarksManager sharedManager] isCategoryEditable:m_categoryId]; -} - -- (kml::MarkId)bookmarkSection:(BookmarksSection *)bookmarkSection getBookmarkIdByRow:(NSInteger)row { - if ([self isSearchMode]) { - CHECK_LESS(row, m_searchResults.size(), ()); - return m_searchResults[row]; - } - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:bookmarkSection.blockIndex]; - CHECK_LESS(row, sortedBlock.m_markIds.size(), ()); - return sortedBlock.m_markIds[row]; - } - - auto const &bm = GetFramework().GetBookmarkManager(); - auto const &bookmarkIds = bm.GetUserMarkIds(m_categoryId); - CHECK_LESS(row, bookmarkIds.size(), ()); - auto it = bookmarkIds.begin(); - advance(it, row); - return *it; -} - -- (BOOL)bookmarkSection:(BookmarksSection *)bookmarkSection onDeleteBookmarkInRow:(NSInteger)row { - if ([self isSearchMode]) { - CHECK_LESS(row, m_searchResults.size(), ()); - m_searchResults.erase(m_searchResults.begin() + row); - m_sortedBlocks.clear(); - return m_searchResults.empty(); - } - - if ([self isSortMode]) { - auto &sortedBlock = [self sortedBlockForIndex:bookmarkSection.blockIndex]; - auto &marks = sortedBlock.m_markIds; - CHECK_LESS(row, marks.size(), ()); - - marks.erase(marks.begin() + row); - if (marks.empty()) { - [self deleteSortedBlockForIndex:bookmarkSection.blockIndex]; - return YES; - } - return NO; - } - - auto const &bm = GetFramework().GetBookmarkManager(); - auto const &bookmarkIds = bm.GetUserMarkIds(m_categoryId); - return bookmarkIds.empty(); -} - -#pragma mark - TracksSectionDelegate - -- (NSInteger)numberOfTracksInSection:(TracksSection *)tracksSection { - CHECK(![self isSearchMode], ()); - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:tracksSection.blockIndex]; - return sortedBlock.m_trackIds.size(); - } - - auto const &bm = GetFramework().GetBookmarkManager(); - return bm.GetTrackIds(m_categoryId).size(); -} - -- (NSString *)titleOfTracksSection:(TracksSection *)tracksSection { - CHECK(![self isSearchMode], ()); - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:tracksSection.blockIndex]; - return @(sortedBlock.m_blockName.c_str()); - } - - return L(@"tracks_title"); -} - -- (BOOL)canEditTracksSection:(TracksSection *)tracksSection { - CHECK(![self isSearchMode], ()); - - if ([self isSortMode]) - return false; - - return [[MWMBookmarksManager sharedManager] isCategoryEditable:m_categoryId]; -} - -- (kml::TrackId)tracksSection:(TracksSection *)tracksSection getTrackIdByRow:(NSInteger)row { - CHECK(![self isSearchMode], ()); - - if ([self isSortMode]) { - auto const &sortedBlock = [self sortedBlockForIndex:tracksSection.blockIndex]; - CHECK_LESS(row, sortedBlock.m_trackIds.size(), ()); - return sortedBlock.m_trackIds[row]; - } - - auto const &bm = GetFramework().GetBookmarkManager(); - auto const &trackIds = bm.GetTrackIds(m_categoryId); - CHECK_LESS(row, trackIds.size(), ()); - auto it = trackIds.begin(); - advance(it, row); - return *it; -} - -- (BOOL)tracksSection:(TracksSection *)tracksSection onDeleteTrackInRow:(NSInteger)row { - CHECK(![self isSearchMode], ()); - - if ([self isSortMode]) { - auto &sortedBlock = [self sortedBlockForIndex:tracksSection.blockIndex]; - CHECK_LESS(row, sortedBlock.m_trackIds.size(), ()); - - auto &tracks = sortedBlock.m_trackIds; - tracks.erase(tracks.begin() + row); - if (tracks.empty()) { - [self deleteSortedBlockForIndex:tracksSection.blockIndex]; - return YES; - } - return NO; - } - - auto const &bm = GetFramework().GetBookmarkManager(); - auto const &trackIds = bm.GetTrackIds(m_categoryId); - return trackIds.empty(); -} - -#pragma mark - InfoSectionDelegate - -- (UITableViewCell *)infoCellForTableView:(UITableView *)tableView { - UITableViewCell *cell = [tableView dequeueReusableCellWithCellClass:MWMCategoryInfoCell.class]; - CHECK(cell, ("Invalid category info cell.")); - - auto &f = GetFramework(); - auto &bm = f.GetBookmarkManager(); - bool const categoryExists = bm.HasBmCategory(m_categoryId); - CHECK(categoryExists, ("Nonexistent category")); - - auto infoCell = (MWMCategoryInfoCell *)cell; - auto const &categoryData = bm.GetCategoryData(m_categoryId); - [infoCell updateWithCategoryData:categoryData delegate:self]; - infoCell.expanded = self.infoExpanded; - - return cell; -} - -#pragma mark - MWMCategoryInfoCellDelegate - -- (void)categoryInfoCellDidPressMore:(MWMCategoryInfoCell *)cell { - [self.tableView beginUpdates]; - cell.expanded = YES; - [self.tableView endUpdates]; - self.infoExpanded = YES; +- (void)infoSectionUpdates:(void (^_Nullable)(void))updates expanded:(BOOL)expanded { + [self.tableView update:updates]; + self.infoExpanded = expanded; } #pragma mark - MWMLocationObserver @@ -861,7 +732,7 @@ using namespace std; - (void)onLocationUpdate:(location::GpsInfo const &)info { [self.tableView.visibleCells enumerateObjectsUsingBlock:^(UITableViewCell *cell, NSUInteger idx, BOOL *stop) { auto const indexPath = [self.tableView indexPathForCell:cell]; - auto const §ion = self->m_sectionsCollection[indexPath.section]; + auto const §ion = [self currentSections][indexPath.section]; if ([section respondsToSelector:@selector(updateCell:forRow:withNewLocation:)]) [section updateCell:cell forRow:indexPath.row withNewLocation:info]; }]; @@ -925,4 +796,7 @@ using namespace std; self.noResultsBottom.constant = -keyboardHeight; } + @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/Catalog/DownloadedBookmarksViewController.swift b/iphone/Maps/Bookmarks/Catalog/DownloadedBookmarksViewController.swift index b603ccb207..ea6ad889de 100644 --- a/iphone/Maps/Bookmarks/Catalog/DownloadedBookmarksViewController.swift +++ b/iphone/Maps/Bookmarks/Catalog/DownloadedBookmarksViewController.swift @@ -120,10 +120,9 @@ extension DownloadedBookmarksViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let category = dataSource.category(at: indexPath.row) - if let bmViewController = BookmarksVC(category: category.categoryId) { - MapViewController.topViewController().navigationController?.pushViewController(bmViewController, - animated: true) - } + let bmViewController = BookmarksVC(category: category.categoryId) + MapViewController.topViewController().navigationController?.pushViewController(bmViewController, + animated: true) } } diff --git a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift index 7eb7998c87..fc2241460a 100644 --- a/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift +++ b/iphone/Maps/Bookmarks/Categories/BMCView/BMCViewController.swift @@ -109,7 +109,7 @@ final class BMCViewController: MWMViewController { } private func openCategory(category: MWMCategory) { - let bmViewController = BookmarksVC(category: category.categoryId)! + let bmViewController = BookmarksVC(category: category.categoryId) bmViewController.delegate = self MapViewController.topViewController().navigationController?.pushViewController(bmViewController, animated: true) diff --git a/iphone/Maps/Bookmarks/InfoSection.h b/iphone/Maps/Bookmarks/InfoSection.h index 7d38537225..b659c1aead 100644 --- a/iphone/Maps/Bookmarks/InfoSection.h +++ b/iphone/Maps/Bookmarks/InfoSection.h @@ -1,13 +1,19 @@ #import "TableSectionDataSource.h" -@protocol InfoSectionDelegate +NS_ASSUME_NONNULL_BEGIN -- (UITableViewCell *)infoCellForTableView:(UITableView *)tableView; +@protocol InfoSectionObserver + +- (void)infoSectionUpdates:(void (^_Nullable)(void))updates expanded:(BOOL)expanded; @end @interface InfoSection : NSObject -- (instancetype)initWithDelegate:(id)delegate; +- (instancetype)initWithCategoryId:(MWMMarkGroupID)categoryId + expanded:(BOOL)expanded + observer:(id)observer; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/InfoSection.mm b/iphone/Maps/Bookmarks/InfoSection.mm index e066bf68f5..1ccf11ea1f 100644 --- a/iphone/Maps/Bookmarks/InfoSection.mm +++ b/iphone/Maps/Bookmarks/InfoSection.mm @@ -1,17 +1,27 @@ #import "InfoSection.h" +#include "Framework.h" +#import "MWMCategoryInfoCell.h" +#import "SwiftBridge.h" -@interface InfoSection () +@interface InfoSection () { + kml::MarkGroupId m_categoryId; +} -@property(weak, nonatomic) id delegate; +@property(nonatomic) BOOL infoExpanded; +@property(weak, nonatomic) id observer; @end @implementation InfoSection -- (instancetype)initWithDelegate:(id)delegate { +- (instancetype)initWithCategoryId:(MWMMarkGroupID)categoryId + expanded:(BOOL)expanded + observer:(id)observer { self = [super init]; if (self) { - _delegate = delegate; + m_categoryId = static_cast(categoryId); + _infoExpanded = expanded; + _observer = observer; } return self; } @@ -20,7 +30,7 @@ return 1; } -- (NSString *)title { +- (nullable NSString *)title { return L(@"placepage_place_description"); } @@ -29,15 +39,37 @@ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRow:(NSInteger)row { - return [self.delegate infoCellForTableView:tableView]; + UITableViewCell *cell = [tableView dequeueReusableCellWithCellClass:MWMCategoryInfoCell.class]; + CHECK(cell, ("Invalid category info cell.")); + + auto &f = GetFramework(); + auto &bm = f.GetBookmarkManager(); + bool const categoryExists = bm.HasBmCategory(m_categoryId); + CHECK(categoryExists, ("Nonexistent category")); + + auto infoCell = (MWMCategoryInfoCell *)cell; + auto const &categoryData = bm.GetCategoryData(m_categoryId); + [infoCell updateWithCategoryData:categoryData delegate:self]; + infoCell.expanded = _infoExpanded; + + return cell; } - (BOOL)didSelectRow:(NSInteger)row { return NO; } -- (BOOL)deleteRow:(NSInteger)row { - return YES; +- (void)deleteRow:(NSInteger)row { +} + +#pragma mark - InfoSectionObserver + +- (void)categoryInfoCellDidPressMore:(MWMCategoryInfoCell *)cell { + _infoExpanded = YES; + [self.observer infoSectionUpdates:^{ + cell.expanded = YES; + } + expanded:_infoExpanded]; } @end diff --git a/iphone/Maps/Bookmarks/MWMCategoryInfoCell.h b/iphone/Maps/Bookmarks/MWMCategoryInfoCell.h index ba4531a11d..402b4d7cb8 100644 --- a/iphone/Maps/Bookmarks/MWMCategoryInfoCell.h +++ b/iphone/Maps/Bookmarks/MWMCategoryInfoCell.h @@ -1,6 +1,7 @@ -#import "InfoSection.h" #import "MWMTableViewCell.h" +NS_ASSUME_NONNULL_BEGIN + namespace kml { struct CategoryData; @@ -8,7 +9,7 @@ struct CategoryData; @class MWMCategoryInfoCell; -@protocol MWMCategoryInfoCellDelegate +@protocol MWMCategoryInfoCellDelegate - (void)categoryInfoCellDidPressMore:(MWMCategoryInfoCell *)cell; @@ -22,3 +23,5 @@ struct CategoryData; delegate:(id)delegate; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/MWMCategoryInfoCell.mm b/iphone/Maps/Bookmarks/MWMCategoryInfoCell.mm index 838ee9df0a..33d97c13f6 100644 --- a/iphone/Maps/Bookmarks/MWMCategoryInfoCell.mm +++ b/iphone/Maps/Bookmarks/MWMCategoryInfoCell.mm @@ -6,6 +6,8 @@ #include "kml/types.hpp" #include "kml/type_utils.hpp" +NS_ASSUME_NONNULL_BEGIN + @interface MWMCategoryInfoCell() @property (weak, nonatomic) IBOutlet UILabel * titleLabel; @@ -15,8 +17,8 @@ @property (weak, nonatomic) IBOutlet NSLayoutConstraint * infoToBottomConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint * infoHeightConstraint; -@property (copy, nonatomic) NSAttributedString * info; -@property (copy, nonatomic) NSString * shortInfo; +@property(copy, nonatomic, nullable) NSAttributedString *info; +@property(copy, nonatomic, nullable) NSString *shortInfo; @property (weak, nonatomic) id delegate; @end @@ -97,3 +99,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/TableSectionDataSource.h b/iphone/Maps/Bookmarks/TableSectionDataSource.h index 9a0aac8f28..eb284f005c 100644 --- a/iphone/Maps/Bookmarks/TableSectionDataSource.h +++ b/iphone/Maps/Bookmarks/TableSectionDataSource.h @@ -1,18 +1,22 @@ #include "platform/location.hpp" +NS_ASSUME_NONNULL_BEGIN + @protocol TableSectionDataSource - (NSInteger)numberOfRows; -- (NSString *)title; +- (nullable NSString *)title; - (BOOL)canEdit; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRow:(NSInteger)row; - (BOOL)didSelectRow:(NSInteger)row; -- (BOOL)deleteRow:(NSInteger)row; +- (void)deleteRow:(NSInteger)row; @optional - (void)updateCell:(UITableViewCell *)cell forRow:(NSInteger)row withNewLocation:(location::GpsInfo const &)gpsInfo; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/TracksSection.h b/iphone/Maps/Bookmarks/TracksSection.h index 2ee6a63285..042b38bb6b 100644 --- a/iphone/Maps/Bookmarks/TracksSection.h +++ b/iphone/Maps/Bookmarks/TracksSection.h @@ -1,25 +1,14 @@ +#import "MWMTypes.h" #import "TableSectionDataSource.h" -#include "kml/type_utils.hpp" - -@class TracksSection; - -@protocol TracksSectionDelegate - -- (NSInteger)numberOfTracksInSection:(TracksSection *)tracksSection; -- (NSString *)titleOfTracksSection:(TracksSection *)tracksSection; -- (BOOL)canEditTracksSection:(TracksSection *)tracksSection; -- (kml::MarkId)tracksSection:(TracksSection *)tracksSection getTrackIdByRow:(NSInteger)row; -- (BOOL)tracksSection:(TracksSection *)tracksSection onDeleteTrackInRow:(NSInteger)row; - -@end +NS_ASSUME_NONNULL_BEGIN @interface TracksSection : NSObject -@property(nullable, nonatomic) NSNumber *blockIndex; - -- (instancetype)initWithDelegate:(id)delegate; - -- (instancetype)initWithBlockIndex:(NSNumber *)blockIndex delegate:(id)delegate; +- (instancetype)initWithTitle:(nullable NSString *)title + trackIds:(MWMTrackIDCollection)trackIds + isEditable:(BOOL)isEditable; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Bookmarks/TracksSection.mm b/iphone/Maps/Bookmarks/TracksSection.mm index 2d16218c5b..5b6f9e651f 100644 --- a/iphone/Maps/Bookmarks/TracksSection.mm +++ b/iphone/Maps/Bookmarks/TracksSection.mm @@ -2,41 +2,48 @@ #import "CircleView.h" #include "Framework.h" +NS_ASSUME_NONNULL_BEGIN + namespace { CGFloat const kPinDiameter = 22.0f; } // namespace -@interface TracksSection () - -@property(weak, nonatomic) id delegate; +@interface TracksSection () { + NSString *m_title; + NSMutableArray *m_trackIds; + BOOL m_isEditable; +} @end @implementation TracksSection -- (instancetype)initWithDelegate:(id)delegate { - return [self initWithBlockIndex:nil delegate:delegate]; -} - -- (instancetype)initWithBlockIndex:(NSNumber *)blockIndex delegate:(id)delegate { +- (instancetype)initWithTitle:(nullable NSString *)title + trackIds:(MWMTrackIDCollection)trackIds + isEditable:(BOOL)isEditable { self = [super init]; if (self) { - _blockIndex = blockIndex; - _delegate = delegate; + m_title = title; + m_trackIds = trackIds.mutableCopy; + m_isEditable = isEditable; } return self; } -- (NSInteger)numberOfRows { - return [self.delegate numberOfTracksInSection:self]; +- (kml::TrackId)getTrackIdForRow:(NSInteger)row { + return static_cast(m_trackIds[row].unsignedLongLongValue); } -- (NSString *)title { - return [self.delegate titleOfTracksSection:self]; +- (NSInteger)numberOfRows { + return [m_trackIds count]; +} + +- (nullable NSString *)title { + return m_title; } - (BOOL)canEdit { - return [self.delegate canEditTracksSection:self]; + return m_isEditable; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRow:(NSInteger)row { @@ -47,7 +54,7 @@ CGFloat const kPinDiameter = 22.0f; auto const &bm = GetFramework().GetBookmarkManager(); - kml::TrackId const trackId = [self.delegate tracksSection:self getTrackIdByRow:row]; + auto const trackId = [self getTrackIdForRow:row]; Track const *track = bm.GetTrack(trackId); cell.textLabel.text = @(track->GetName().c_str()); string dist; @@ -65,16 +72,18 @@ CGFloat const kPinDiameter = 22.0f; } - (BOOL)didSelectRow:(NSInteger)row { - kml::TrackId const trackId = [self.delegate tracksSection:self getTrackIdByRow:row]; + auto const trackId = [self getTrackIdForRow:row]; GetFramework().ShowTrack(trackId); return YES; } -- (BOOL)deleteRow:(NSInteger)row { - kml::TrackId const trackId = [self.delegate tracksSection:self getTrackIdByRow:row]; +- (void)deleteRow:(NSInteger)row { + auto const trackId = [self getTrackIdForRow:row]; auto &bm = GetFramework().GetBookmarkManager(); bm.GetEditSession().DeleteTrack(trackId); - return [self.delegate tracksSection:self onDeleteTrackInRow:row]; + [m_trackIds removeObjectAtIndex:row]; } @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Classes/CircleView.h b/iphone/Maps/Classes/CircleView.h index 1340fbe3a0..3c5ac4d0a1 100644 --- a/iphone/Maps/Classes/CircleView.h +++ b/iphone/Maps/Classes/CircleView.h @@ -1,11 +1,15 @@ #import +NS_ASSUME_NONNULL_BEGIN + @interface CircleView : UIView - (id)initWithFrame:(CGRect)frame andColor:(UIColor *)color; -- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)color andImageName:(NSString *)imageName; +- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)color andImageName:(nullable NSString *)imageName; + (UIImage *)createCircleImageWith:(CGFloat)diameter andColor:(UIColor *)color; + (UIImage *)createCircleImageWith:(CGFloat)diameter andColor:(UIColor *)color andImageName:(NSString *)imageName; + (UIImage *)createCircleImageWith:(CGFloat)diameter andColor:(UIColor *)color andSubview:(UIView *)view; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Classes/CircleView.mm b/iphone/Maps/Classes/CircleView.mm index 7b1fc44c9a..25dd451c53 100644 --- a/iphone/Maps/Classes/CircleView.mm +++ b/iphone/Maps/Classes/CircleView.mm @@ -2,6 +2,8 @@ #import "CircleView.h" #import +NS_ASSUME_NONNULL_BEGIN + @interface CircleView() @property(nonatomic) UIColor *circleColor; @@ -15,7 +17,7 @@ return [self initWithFrame:frame andColor:color andImageName:nil]; } -- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)color andImageName:(NSString *)imageName { +- (id)initWithFrame:(CGRect)frame andColor:(UIColor *)color andImageName:(nullable NSString *)imageName { self = [super initWithFrame:frame]; if (self) { @@ -39,7 +41,7 @@ + (UIView *)createViewWithCircleDiameter:(CGFloat)diameter andColor:(UIColor *)color - andImageName:(NSString *)imageName { + andImageName:(nullable NSString *)imageName { UIView *circleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, diameter, diameter)]; circleView.backgroundColor = UIColor.clearColor; CircleView *circle = [[self alloc] initWithFrame:CGRectMake(0.5, 0.5, diameter - 1, diameter - 1) @@ -66,15 +68,15 @@ } + (UIImage *)imageWithView:(UIView *)view { - UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0); - CGContextRef context = UIGraphicsGetCurrentContext(); - [view.layer renderInContext:context]; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:view.bounds.size]; - UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) { + [view.layer renderInContext:rendererContext.CGContext]; + }]; - UIGraphicsEndImageContext(); - - return img; + return image; } @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h index 692571d59a..94eca39424 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.h @@ -43,8 +43,11 @@ typedef void (^PingCompletionBlock)(BOOL success); - (BOOL)checkCategoryName:(NSString *)name; - (NSArray *)bookmarksForCategory:(MWMMarkGroupID)categoryId; +- (MWMMarkIDCollection)bookmarkIdsForCategory:(MWMMarkGroupID)categoryId; - (void)deleteBookmark:(MWMMarkID)bookmarkId; +- (MWMTrackIDCollection)trackIdsForCategory:(MWMMarkGroupID)categoryId; + - (void)shareCategory:(MWMMarkGroupID)groupId; - (NSURL *)shareCategoryURL; - (void)finishShareCategory; diff --git a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm index b0a00b6561..48f1d1c170 100644 --- a/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm +++ b/iphone/Maps/Core/Bookmarks/MWMBookmarksManager.mm @@ -407,6 +407,14 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result) return [result copy]; } +- (MWMMarkIDCollection)bookmarkIdsForCategory:(MWMMarkGroupID)categoryId { + auto const &bookmarkIds = self.bm.GetUserMarkIds(categoryId); + NSMutableArray *collection = [[NSMutableArray alloc] initWithCapacity:bookmarkIds.size()]; + for (auto bookmarkId : bookmarkIds) + [collection addObject:@(bookmarkId)]; + return collection.copy; +} + - (void)deleteBookmark:(MWMMarkID)bookmarkId { self.bm.GetEditSession().DeleteBookmark(bookmarkId); @@ -416,6 +424,16 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result) }]; } +#pragma mark - Tracks + +- (MWMTrackIDCollection)trackIdsForCategory:(MWMMarkGroupID)categoryId { + auto const &trackIds = self.bm.GetTrackIds(categoryId); + NSMutableArray *collection = [[NSMutableArray alloc] initWithCapacity:trackIds.size()]; + for (auto trackId : trackIds) + [collection addObject:@(trackId)]; + return collection.copy; +} + #pragma mark - Category sharing - (void)shareCategory:(MWMMarkGroupID)groupId