[ios] Format all Obj C code via clang-format

Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
This commit is contained in:
Konstantin Pastbin
2025-08-17 16:37:15 +07:00
parent 52e9ddc038
commit aea784ddd7
109 changed files with 5113 additions and 4270 deletions

View File

@@ -7,19 +7,19 @@
@implementation MWMBookmark (Core) @implementation MWMBookmark (Core)
- (instancetype)initWithMarkId:(MWMMarkID)markId bookmarkData:(Bookmark const *)bookmark { - (instancetype)initWithMarkId:(MWMMarkID)markId bookmarkData:(Bookmark const *)bookmark
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_bookmarkId = markId; _bookmarkId = markId;
_bookmarkName = @(bookmark->GetPreferredName().c_str()); _bookmarkName = @(bookmark->GetPreferredName().c_str());
_bookmarkColor = convertKmlColor(bookmark->GetColor()); _bookmarkColor = convertKmlColor(bookmark->GetColor());
_bookmarkIconName = [NSString stringWithFormat:@"%@%@", _bookmarkIconName = [NSString
@"ic_bm_", stringWithFormat:@"%@%@", @"ic_bm_", [@(kml::ToString(bookmark->GetData().m_icon).c_str()) lowercaseString]];
[@(kml::ToString(bookmark->GetData().m_icon).c_str()) lowercaseString]]; auto const & types = bookmark->GetData().m_featureTypes;
auto const &types = bookmark->GetData().m_featureTypes; if (!types.empty())
if (!types.empty()) {
_bookmarkType = @(kml::GetLocalizedFeatureType(types).c_str()); _bookmarkType = @(kml::GetLocalizedFeatureType(types).c_str());
}
auto latlon = bookmark->GetLatLon(); auto latlon = bookmark->GetLatLon();
_locationCoordinate = CLLocationCoordinate2DMake(latlon.m_lat, latlon.m_lon); _locationCoordinate = CLLocationCoordinate2DMake(latlon.m_lat, latlon.m_lon);
} }

View File

@@ -1,42 +1,26 @@
#import "MWMBookmarkColor+Core.h" #import "MWMBookmarkColor+Core.h"
MWMBookmarkColor convertKmlColor(kml::PredefinedColor kmlColor) { MWMBookmarkColor convertKmlColor(kml::PredefinedColor kmlColor)
switch (kmlColor) { {
case kml::PredefinedColor::None: switch (kmlColor)
return MWMBookmarkColorNone; {
case kml::PredefinedColor::Red: case kml::PredefinedColor::None: return MWMBookmarkColorNone;
return MWMBookmarkColorRed; case kml::PredefinedColor::Red: return MWMBookmarkColorRed;
case kml::PredefinedColor::Blue: case kml::PredefinedColor::Blue: return MWMBookmarkColorBlue;
return MWMBookmarkColorBlue; case kml::PredefinedColor::Purple: return MWMBookmarkColorPurple;
case kml::PredefinedColor::Purple: case kml::PredefinedColor::Yellow: return MWMBookmarkColorYellow;
return MWMBookmarkColorPurple; case kml::PredefinedColor::Pink: return MWMBookmarkColorPink;
case kml::PredefinedColor::Yellow: case kml::PredefinedColor::Brown: return MWMBookmarkColorBrown;
return MWMBookmarkColorYellow; case kml::PredefinedColor::Green: return MWMBookmarkColorGreen;
case kml::PredefinedColor::Pink: case kml::PredefinedColor::Orange: return MWMBookmarkColorOrange;
return MWMBookmarkColorPink; case kml::PredefinedColor::DeepPurple: return MWMBookmarkColorDeepPurple;
case kml::PredefinedColor::Brown: case kml::PredefinedColor::LightBlue: return MWMBookmarkColorLightBlue;
return MWMBookmarkColorBrown; case kml::PredefinedColor::Cyan: return MWMBookmarkColorCyan;
case kml::PredefinedColor::Green: case kml::PredefinedColor::Teal: return MWMBookmarkColorTeal;
return MWMBookmarkColorGreen; case kml::PredefinedColor::Lime: return MWMBookmarkColorLime;
case kml::PredefinedColor::Orange: case kml::PredefinedColor::DeepOrange: return MWMBookmarkColorDeepOrange;
return MWMBookmarkColorOrange; case kml::PredefinedColor::Gray: return MWMBookmarkColorGray;
case kml::PredefinedColor::DeepPurple: case kml::PredefinedColor::BlueGray: return MWMBookmarkColorBlueGray;
return MWMBookmarkColorDeepPurple; case kml::PredefinedColor::Count: return MWMBookmarkColorCount;
case kml::PredefinedColor::LightBlue:
return MWMBookmarkColorLightBlue;
case kml::PredefinedColor::Cyan:
return MWMBookmarkColorCyan;
case kml::PredefinedColor::Teal:
return MWMBookmarkColorTeal;
case kml::PredefinedColor::Lime:
return MWMBookmarkColorLime;
case kml::PredefinedColor::DeepOrange:
return MWMBookmarkColorDeepOrange;
case kml::PredefinedColor::Gray:
return MWMBookmarkColorGray;
case kml::PredefinedColor::BlueGray:
return MWMBookmarkColorBlueGray;
case kml::PredefinedColor::Count:
return MWMBookmarkColorCount;
} }
} }

View File

@@ -1,8 +1,8 @@
#import "MWMBookmarksManager.h" #import "MWMBookmarksManager.h"
#import "MWMBookmark+Core.h" #import "MWMBookmark+Core.h"
#import "MWMBookmarksSection.h"
#import "MWMBookmarkGroup.h" #import "MWMBookmarkGroup.h"
#import "MWMBookmarksSection.h"
#import "MWMCarPlayBookmarkObject.h" #import "MWMCarPlayBookmarkObject.h"
#import "MWMTrack+Core.h" #import "MWMTrack+Core.h"
#import "RecentlyDeletedCategory+Core.h" #import "RecentlyDeletedCategory+Core.h"
@@ -18,81 +18,60 @@
#include <utility> #include <utility>
static kml::PredefinedColor kmlColorFromBookmarkColor(MWMBookmarkColor bookmarkColor) { static kml::PredefinedColor kmlColorFromBookmarkColor(MWMBookmarkColor bookmarkColor)
switch (bookmarkColor) { {
case MWMBookmarkColorNone: switch (bookmarkColor)
return kml::PredefinedColor::None; {
case MWMBookmarkColorRed: case MWMBookmarkColorNone: return kml::PredefinedColor::None;
return kml::PredefinedColor::Red; case MWMBookmarkColorRed: return kml::PredefinedColor::Red;
case MWMBookmarkColorBlue: case MWMBookmarkColorBlue: return kml::PredefinedColor::Blue;
return kml::PredefinedColor::Blue; case MWMBookmarkColorPurple: return kml::PredefinedColor::Purple;
case MWMBookmarkColorPurple: case MWMBookmarkColorYellow: return kml::PredefinedColor::Yellow;
return kml::PredefinedColor::Purple; case MWMBookmarkColorPink: return kml::PredefinedColor::Pink;
case MWMBookmarkColorYellow: case MWMBookmarkColorBrown: return kml::PredefinedColor::Brown;
return kml::PredefinedColor::Yellow; case MWMBookmarkColorGreen: return kml::PredefinedColor::Green;
case MWMBookmarkColorPink: case MWMBookmarkColorOrange: return kml::PredefinedColor::Orange;
return kml::PredefinedColor::Pink; case MWMBookmarkColorDeepPurple: return kml::PredefinedColor::DeepPurple;
case MWMBookmarkColorBrown: case MWMBookmarkColorLightBlue: return kml::PredefinedColor::LightBlue;
return kml::PredefinedColor::Brown; case MWMBookmarkColorCyan: return kml::PredefinedColor::Cyan;
case MWMBookmarkColorGreen: case MWMBookmarkColorTeal: return kml::PredefinedColor::Teal;
return kml::PredefinedColor::Green; case MWMBookmarkColorLime: return kml::PredefinedColor::Lime;
case MWMBookmarkColorOrange: case MWMBookmarkColorDeepOrange: return kml::PredefinedColor::DeepOrange;
return kml::PredefinedColor::Orange; case MWMBookmarkColorGray: return kml::PredefinedColor::Gray;
case MWMBookmarkColorDeepPurple: case MWMBookmarkColorBlueGray: return kml::PredefinedColor::BlueGray;
return kml::PredefinedColor::DeepPurple; case MWMBookmarkColorCount: return kml::PredefinedColor::Count;
case MWMBookmarkColorLightBlue:
return kml::PredefinedColor::LightBlue;
case MWMBookmarkColorCyan:
return kml::PredefinedColor::Cyan;
case MWMBookmarkColorTeal:
return kml::PredefinedColor::Teal;
case MWMBookmarkColorLime:
return kml::PredefinedColor::Lime;
case MWMBookmarkColorDeepOrange:
return kml::PredefinedColor::DeepOrange;
case MWMBookmarkColorGray:
return kml::PredefinedColor::Gray;
case MWMBookmarkColorBlueGray:
return kml::PredefinedColor::BlueGray;
case MWMBookmarkColorCount:
return kml::PredefinedColor::Count;
} }
} }
static MWMBookmarksSortingType convertSortingType(BookmarkManager::SortingType const &sortingType) { static MWMBookmarksSortingType convertSortingType(BookmarkManager::SortingType const & sortingType)
switch (sortingType) { {
case BookmarkManager::SortingType::ByType: switch (sortingType)
return MWMBookmarksSortingTypeByType; {
case BookmarkManager::SortingType::ByDistance: case BookmarkManager::SortingType::ByType: return MWMBookmarksSortingTypeByType;
return MWMBookmarksSortingTypeByDistance; case BookmarkManager::SortingType::ByDistance: return MWMBookmarksSortingTypeByDistance;
case BookmarkManager::SortingType::ByTime: case BookmarkManager::SortingType::ByTime: return MWMBookmarksSortingTypeByTime;
return MWMBookmarksSortingTypeByTime; case BookmarkManager::SortingType::ByName: return MWMBookmarksSortingTypeByName;
case BookmarkManager::SortingType::ByName:
return MWMBookmarksSortingTypeByName;
} }
} }
static BookmarkManager::SortingType convertSortingTypeToCore(MWMBookmarksSortingType sortingType) { static BookmarkManager::SortingType convertSortingTypeToCore(MWMBookmarksSortingType sortingType)
switch (sortingType) { {
case MWMBookmarksSortingTypeByType: switch (sortingType)
return BookmarkManager::SortingType::ByType; {
case MWMBookmarksSortingTypeByDistance: case MWMBookmarksSortingTypeByType: return BookmarkManager::SortingType::ByType;
return BookmarkManager::SortingType::ByDistance; case MWMBookmarksSortingTypeByDistance: return BookmarkManager::SortingType::ByDistance;
case MWMBookmarksSortingTypeByTime: case MWMBookmarksSortingTypeByTime: return BookmarkManager::SortingType::ByTime;
return BookmarkManager::SortingType::ByTime; case MWMBookmarksSortingTypeByName: return BookmarkManager::SortingType::ByName;
case MWMBookmarksSortingTypeByName:
return BookmarkManager::SortingType::ByName;
} }
} }
static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) { static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType)
switch (fileType) { {
case MWMKmlFileTypeText: switch (fileType)
return KmlFileType::Text; {
case MWMKmlFileTypeBinary: case MWMKmlFileTypeText: return KmlFileType::Text;
return KmlFileType::Binary; case MWMKmlFileTypeBinary: return KmlFileType::Binary;
case MWMKmlFileTypeGpx: case MWMKmlFileTypeGpx: return KmlFileType::Gpx;
return KmlFileType::Gpx;
} }
} }
@@ -114,9 +93,7 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
{ {
static MWMBookmarksManager * manager; static MWMBookmarksManager * manager;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ manager = [[self alloc] initManager]; });
manager = [[self alloc] initManager];
});
return manager; return manager;
} }
@@ -151,13 +128,12 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
BookmarkManager::AsyncLoadingCallbacks bookmarkCallbacks; BookmarkManager::AsyncLoadingCallbacks bookmarkCallbacks;
{ {
__weak auto wSelf = self; __weak auto wSelf = self;
bookmarkCallbacks.m_onStarted = [wSelf]() { bookmarkCallbacks.m_onStarted = [wSelf]() { wSelf.areBookmarksLoaded = NO; };
wSelf.areBookmarksLoaded = NO;
};
} }
{ {
__weak auto wSelf = self; __weak auto wSelf = self;
bookmarkCallbacks.m_onFinished = [wSelf]() { bookmarkCallbacks.m_onFinished = [wSelf]()
{
__strong auto self = wSelf; __strong auto self = wSelf;
if (!self) if (!self)
return; return;
@@ -170,8 +146,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
} }
{ {
__weak auto wSelf = self; __weak auto wSelf = self;
bookmarkCallbacks.m_onFileSuccess = [wSelf](std::string const & filePath, bookmarkCallbacks.m_onFileSuccess = [wSelf](std::string const & filePath, bool isTemporaryFile)
bool isTemporaryFile) { {
__strong __typeof(self) self = wSelf; __strong __typeof(self) self = wSelf;
[self loopObservers:^(id<MWMBookmarksObserver> observer) { [self loopObservers:^(id<MWMBookmarksObserver> observer) {
if ([observer respondsToSelector:@selector(onBookmarksFileLoadSuccess)]) if ([observer respondsToSelector:@selector(onBookmarksFileLoadSuccess)])
@@ -181,7 +157,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
} }
{ {
__weak auto wSelf = self; __weak auto wSelf = self;
bookmarkCallbacks.m_onFileError = [wSelf](std::string const & filePath, bool isTemporaryFile) { bookmarkCallbacks.m_onFileError = [wSelf](std::string const & filePath, bool isTemporaryFile)
{
__strong __typeof(self) self = wSelf; __strong __typeof(self) self = wSelf;
[self loopObservers:^(id<MWMBookmarksObserver> observer) { [self loopObservers:^(id<MWMBookmarksObserver> observer) {
if ([observer respondsToSelector:@selector(onBookmarksFileLoadError)]) if ([observer respondsToSelector:@selector(onBookmarksFileLoadError)])
@@ -228,11 +205,13 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return self.bm.AreAllCategoriesEmpty(); return self.bm.AreAllCategoriesEmpty();
} }
- (BOOL)isCategoryEmpty:(MWMMarkGroupID)groupId { - (BOOL)isCategoryEmpty:(MWMMarkGroupID)groupId
{
return self.bm.HasBmCategory(groupId) && self.bm.IsCategoryEmpty(groupId); return self.bm.HasBmCategory(groupId) && self.bm.IsCategoryEmpty(groupId);
} }
- (void)prepareForSearch:(MWMMarkGroupID)groupId { - (void)prepareForSearch:(MWMMarkGroupID)groupId
{
self.bm.PrepareForSearch(groupId); self.bm.PrepareForSearch(groupId);
} }
@@ -255,22 +234,18 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
{ {
switch (self.bm.GetCategoryData(groupId).m_accessRules) switch (self.bm.GetCategoryData(groupId).m_accessRules)
{ {
case kml::AccessRules::Local: case kml::AccessRules::Local: return MWMBookmarkGroupAccessStatusLocal;
return MWMBookmarkGroupAccessStatusLocal; case kml::AccessRules::Public: return MWMBookmarkGroupAccessStatusPublic;
case kml::AccessRules::Public: case kml::AccessRules::DirectLink: return MWMBookmarkGroupAccessStatusPrivate;
return MWMBookmarkGroupAccessStatusPublic; case kml::AccessRules::AuthorOnly: return MWMBookmarkGroupAccessStatusAuthorOnly;
case kml::AccessRules::DirectLink: case kml::AccessRules::P2P:
return MWMBookmarkGroupAccessStatusPrivate; case kml::AccessRules::Paid:
case kml::AccessRules::AuthorOnly: case kml::AccessRules::Count: return MWMBookmarkGroupAccessStatusOther;
return MWMBookmarkGroupAccessStatusAuthorOnly;
case kml::AccessRules::P2P:
case kml::AccessRules::Paid:
case kml::AccessRules::Count:
return MWMBookmarkGroupAccessStatusOther;
} }
} }
- (NSString *)getCategoryAnnotation:(MWMMarkGroupID)groupId { - (NSString *)getCategoryAnnotation:(MWMMarkGroupID)groupId
{
return @(GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_annotation).c_str()); return @(GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_annotation).c_str());
} }
@@ -289,32 +264,33 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return @(self.bm.GetCategoryData(groupId).m_authorId.c_str()); return @(self.bm.GetCategoryData(groupId).m_authorId.c_str());
} }
- (MWMBookmarkGroupType)getCategoryGroupType:(MWMMarkGroupID)groupId { - (MWMBookmarkGroupType)getCategoryGroupType:(MWMMarkGroupID)groupId
if (self.bm.IsCompilation(groupId) == false) { {
if (self.bm.IsCompilation(groupId) == false)
return MWMBookmarkGroupTypeRoot; return MWMBookmarkGroupTypeRoot;
} switch (self.bm.GetCompilationType(groupId))
switch (self.bm.GetCompilationType(groupId)) { {
case kml::CompilationType::Category: case kml::CompilationType::Category: return MWMBookmarkGroupTypeCategory;
return MWMBookmarkGroupTypeCategory; case kml::CompilationType::Collection: return MWMBookmarkGroupTypeCollection;
case kml::CompilationType::Collection: case kml::CompilationType::Day: return MWMBookmarkGroupTypeDay;
return MWMBookmarkGroupTypeCollection;
case kml::CompilationType::Day:
return MWMBookmarkGroupTypeDay;
} }
return MWMBookmarkGroupTypeRoot; return MWMBookmarkGroupTypeRoot;
} }
- (nullable NSURL *)getCategoryImageUrl:(MWMMarkGroupID)groupId { - (nullable NSURL *)getCategoryImageUrl:(MWMMarkGroupID)groupId
NSString *urlString = @(self.bm.GetCategoryData(groupId).m_imageUrl.c_str()); {
NSString * urlString = @(self.bm.GetCategoryData(groupId).m_imageUrl.c_str());
return [NSURL URLWithString:urlString]; return [NSURL URLWithString:urlString];
} }
- (BOOL)hasExtraInfo:(MWMMarkGroupID)groupId { - (BOOL)hasExtraInfo:(MWMMarkGroupID)groupId
{
auto data = self.bm.GetCategoryData(groupId); auto data = self.bm.GetCategoryData(groupId);
return !data.m_description.empty() || !data.m_annotation.empty(); return !data.m_description.empty() || !data.m_annotation.empty();
} }
- (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId { - (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId
{
auto const description = GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_description); auto const description = GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_description);
return strings::IsHTML(description); return strings::IsHTML(description);
} }
@@ -346,11 +322,13 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
self.bm.GetEditSession().SetIsVisible(groupId, isVisible); self.bm.GetEditSession().SetIsVisible(groupId, isVisible);
} }
- (void)setUserCategoriesVisible:(BOOL)isVisible { - (void)setUserCategoriesVisible:(BOOL)isVisible
{
self.bm.SetAllCategoriesVisibility(isVisible); self.bm.SetAllCategoriesVisibility(isVisible);
} }
- (void)setCatalogCategoriesVisible:(BOOL)isVisible { - (void)setCatalogCategoriesVisible:(BOOL)isVisible
{
self.bm.SetAllCategoriesVisibility(isVisible); self.bm.SetAllCategoriesVisibility(isVisible);
} }
@@ -383,24 +361,27 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return self.bm.HasTrack(trackId); return self.bm.HasTrack(trackId);
} }
- (NSArray<NSNumber *> *)availableSortingTypes:(MWMMarkGroupID)groupId hasMyPosition:(BOOL)hasMyPosition{ - (NSArray<NSNumber *> *)availableSortingTypes:(MWMMarkGroupID)groupId hasMyPosition:(BOOL)hasMyPosition
{
auto const availableTypes = self.bm.GetAvailableSortingTypes(groupId, hasMyPosition); auto const availableTypes = self.bm.GetAvailableSortingTypes(groupId, hasMyPosition);
NSMutableArray *result = [NSMutableArray array]; NSMutableArray * result = [NSMutableArray array];
for (auto const &sortingType : availableTypes) { for (auto const & sortingType : availableTypes)
[result addObject:[NSNumber numberWithInteger:convertSortingType(sortingType)]]; [result addObject:[NSNumber numberWithInteger:convertSortingType(sortingType)]];
}
return [result copy]; return [result copy];
} }
- (void)sortBookmarks:(MWMMarkGroupID)groupId - (void)sortBookmarks:(MWMMarkGroupID)groupId
sortingType:(MWMBookmarksSortingType)sortingType sortingType:(MWMBookmarksSortingType)sortingType
location:(CLLocation *)location location:(CLLocation *)location
completion:(SortBookmarksCompletionBlock)completion { completion:(SortBookmarksCompletionBlock)completion
{
self.bm.SetLastSortingType(groupId, convertSortingTypeToCore(sortingType)); self.bm.SetLastSortingType(groupId, convertSortingTypeToCore(sortingType));
m2::PointD myPosition = m2::PointD::Zero(); m2::PointD myPosition = m2::PointD::Zero();
if (sortingType == MWMBookmarksSortingTypeByDistance) { if (sortingType == MWMBookmarksSortingTypeByDistance)
if (!location) { {
if (!location)
{
completion(nil); completion(nil);
return; return;
} }
@@ -415,59 +396,63 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
sortParams.m_sortingType = convertSortingTypeToCore(sortingType); sortParams.m_sortingType = convertSortingTypeToCore(sortingType);
sortParams.m_hasMyPosition = location != nil; sortParams.m_hasMyPosition = location != nil;
sortParams.m_myPosition = myPosition; sortParams.m_myPosition = myPosition;
sortParams.m_onResults = [weakSelf, sortId, completion] (BookmarkManager::SortedBlocksCollection &&sortedBlocks, sortParams.m_onResults = [weakSelf, sortId, completion](BookmarkManager::SortedBlocksCollection && sortedBlocks,
BookmarkManager::SortParams::Status status) { BookmarkManager::SortParams::Status status)
{
__strong auto self = weakSelf; __strong auto self = weakSelf;
if (!self || sortId != self.lastSortId) if (!self || sortId != self.lastSortId)
return; return;
switch (status) { switch (status)
case BookmarkManager::SortParams::Status::Completed: { {
NSMutableArray *result = [NSMutableArray array]; case BookmarkManager::SortParams::Status::Completed:
for (auto const &sortedBlock : sortedBlocks) { {
NSMutableArray *bookmarks = nil; NSMutableArray * result = [NSMutableArray array];
if (sortedBlock.m_markIds.size() > 0) { for (auto const & sortedBlock : sortedBlocks)
bookmarks = [NSMutableArray array]; {
for (auto const &markId : sortedBlock.m_markIds) { NSMutableArray * bookmarks = nil;
[bookmarks addObject:[[MWMBookmark alloc] initWithMarkId:markId if (sortedBlock.m_markIds.size() > 0)
bookmarkData:self.bm.GetBookmark(markId)]]; {
} bookmarks = [NSMutableArray array];
} for (auto const & markId : sortedBlock.m_markIds)
NSMutableArray *tracks = nil; [bookmarks addObject:[[MWMBookmark alloc] initWithMarkId:markId bookmarkData:self.bm.GetBookmark(markId)]];
if (sortedBlock.m_trackIds.size() > 0) {
tracks = [NSMutableArray array];
for (auto const &trackId : sortedBlock.m_trackIds) {
[tracks addObject:[[MWMTrack alloc] initWithTrackId:trackId trackData:self.bm.GetTrack(trackId)]];
}
}
[result addObject:[[MWMBookmarksSection alloc] initWithTitle:@(sortedBlock.m_blockName.c_str())
bookmarks:bookmarks
tracks:tracks]];
} }
completion([result copy]); NSMutableArray * tracks = nil;
break; if (sortedBlock.m_trackIds.size() > 0)
{
tracks = [NSMutableArray array];
for (auto const & trackId : sortedBlock.m_trackIds)
[tracks addObject:[[MWMTrack alloc] initWithTrackId:trackId trackData:self.bm.GetTrack(trackId)]];
}
[result addObject:[[MWMBookmarksSection alloc] initWithTitle:@(sortedBlock.m_blockName.c_str())
bookmarks:bookmarks
tracks:tracks]];
} }
case BookmarkManager::SortParams::Status::Cancelled: completion([result copy]);
completion(nil); break;
break; }
case BookmarkManager::SortParams::Status::Cancelled: completion(nil); break;
} }
}; };
self.bm.GetSortedCategory(sortParams); self.bm.GetSortedCategory(sortParams);
} }
- (BOOL)hasLastSortingType:(MWMMarkGroupID)groupId { - (BOOL)hasLastSortingType:(MWMMarkGroupID)groupId
{
BookmarkManager::SortingType st; BookmarkManager::SortingType st;
return self.bm.GetLastSortingType(groupId, st); return self.bm.GetLastSortingType(groupId, st);
} }
- (MWMBookmarksSortingType)lastSortingType:(MWMMarkGroupID)groupId { - (MWMBookmarksSortingType)lastSortingType:(MWMMarkGroupID)groupId
{
BookmarkManager::SortingType st; BookmarkManager::SortingType st;
self.bm.GetLastSortingType(groupId, st); self.bm.GetLastSortingType(groupId, st);
return convertSortingType(st); return convertSortingType(st);
} }
- (void)resetLastSortingType:(MWMMarkGroupID)groupId { - (void)resetLastSortingType:(MWMMarkGroupID)groupId
{
self.bm.ResetLastSortingType(groupId); self.bm.ResetLastSortingType(groupId);
} }
@@ -479,15 +464,16 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
auto const & bookmarkIds = self.bm.GetUserMarkIds(categoryId); auto const & bookmarkIds = self.bm.GetUserMarkIds(categoryId);
for (auto bookmarkId : bookmarkIds) for (auto bookmarkId : bookmarkIds)
{ {
MWMCarPlayBookmarkObject *bookmark = [[MWMCarPlayBookmarkObject alloc] initWithBookmarkId:bookmarkId]; MWMCarPlayBookmarkObject * bookmark = [[MWMCarPlayBookmarkObject alloc] initWithBookmarkId:bookmarkId];
[result addObject:bookmark]; [result addObject:bookmark];
} }
return [result copy]; return [result copy];
} }
- (MWMMarkIDCollection)bookmarkIdsForCategory:(MWMMarkGroupID)categoryId { - (MWMMarkIDCollection)bookmarkIdsForCategory:(MWMMarkGroupID)categoryId
auto const &bookmarkIds = self.bm.GetUserMarkIds(categoryId); {
NSMutableArray<NSNumber *> *collection = [[NSMutableArray alloc] initWithCapacity:bookmarkIds.size()]; auto const & bookmarkIds = self.bm.GetUserMarkIds(categoryId);
NSMutableArray<NSNumber *> * collection = [[NSMutableArray alloc] initWithCapacity:bookmarkIds.size()];
for (auto bookmarkId : bookmarkIds) for (auto bookmarkId : bookmarkIds)
[collection addObject:@(bookmarkId)]; [collection addObject:@(bookmarkId)];
return [collection copy]; return [collection copy];
@@ -502,39 +488,45 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
}]; }];
} }
- (void)deleteTrack:(MWMTrackID)trackId { - (void)deleteTrack:(MWMTrackID)trackId
{
self.bm.GetEditSession().DeleteTrack(trackId); self.bm.GetEditSession().DeleteTrack(trackId);
} }
- (MWMBookmark *)bookmarkWithId:(MWMMarkID)bookmarkId { - (MWMBookmark *)bookmarkWithId:(MWMMarkID)bookmarkId
{
return [[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)]; return [[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)];
} }
- (MWMTrack *)trackWithId:(MWMTrackID)trackId { - (MWMTrack *)trackWithId:(MWMTrackID)trackId
{
return [[MWMTrack alloc] initWithTrackId:trackId trackData:self.bm.GetTrack(trackId)]; return [[MWMTrack alloc] initWithTrackId:trackId trackData:self.bm.GetTrack(trackId)];
} }
- (MWMBookmarkGroup *)categoryForBookmarkId:(MWMMarkID)bookmarkId { - (MWMBookmarkGroup *)categoryForBookmarkId:(MWMMarkID)bookmarkId
{
auto const groupId = self.bm.GetBookmark(bookmarkId)->GetGroupId(); auto const groupId = self.bm.GetBookmark(bookmarkId)->GetGroupId();
return [self categoryWithId:groupId]; return [self categoryWithId:groupId];
} }
- (MWMBookmarkGroup *)categoryForTrackId:(MWMTrackID)trackId { - (MWMBookmarkGroup *)categoryForTrackId:(MWMTrackID)trackId
{
auto const groupId = self.bm.GetTrack(trackId)->GetGroupId(); auto const groupId = self.bm.GetTrack(trackId)->GetGroupId();
return [self categoryWithId:groupId]; return [self categoryWithId:groupId];
} }
- (NSString *)descriptionForBookmarkId:(MWMMarkID)bookmarkId { - (NSString *)descriptionForBookmarkId:(MWMMarkID)bookmarkId
{
auto const description = self.bm.GetBookmark(bookmarkId)->GetDescription(); auto const description = self.bm.GetBookmark(bookmarkId)->GetDescription();
return [NSString stringWithUTF8String:description.c_str()]; return [NSString stringWithUTF8String:description.c_str()];
} }
- (NSArray<MWMBookmark *> *)bookmarksForGroup:(MWMMarkGroupID)groupId { - (NSArray<MWMBookmark *> *)bookmarksForGroup:(MWMMarkGroupID)groupId
auto const &bookmarkIds = self.bm.GetUserMarkIds(groupId); {
NSMutableArray *result = [NSMutableArray array]; auto const & bookmarkIds = self.bm.GetUserMarkIds(groupId);
for (auto bookmarkId : bookmarkIds) { NSMutableArray * result = [NSMutableArray array];
for (auto bookmarkId : bookmarkIds)
[result addObject:[[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)]]; [result addObject:[[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)]];
}
return [result copy]; return [result copy];
} }
@@ -547,32 +539,30 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
using search::BookmarksSearchParams; using search::BookmarksSearchParams;
BookmarksSearchParams params{ BookmarksSearchParams params{
text.UTF8String, text.UTF8String, groupId,
groupId, // m_onResults
// m_onResults [weakSelf, searchId, completion](BookmarksSearchParams::Results results, BookmarksSearchParams::Status status)
[weakSelf, searchId, completion](BookmarksSearchParams::Results results, BookmarksSearchParams::Status status) {
{ __strong auto self = weakSelf;
__strong auto self = weakSelf; if (!self || searchId != self.lastSearchId)
if (!self || searchId != self.lastSearchId) return;
return;
self.bm.FilterInvalidBookmarks(results); self.bm.FilterInvalidBookmarks(results);
NSMutableArray *result = [NSMutableArray array]; NSMutableArray * result = [NSMutableArray array];
for (auto bookmarkId : results) for (auto bookmarkId : results)
[result addObject:[[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)]]; [result addObject:[[MWMBookmark alloc] initWithMarkId:bookmarkId bookmarkData:self.bm.GetBookmark(bookmarkId)]];
completion(result); completion(result);
} }};
};
GetFramework().GetSearchAPI().SearchInBookmarks(std::move(params)); GetFramework().GetSearchAPI().SearchInBookmarks(std::move(params));
} }
#pragma mark - Tracks #pragma mark - Tracks
- (MWMTrackIDCollection)trackIdsForCategory:(MWMMarkGroupID)categoryId { - (MWMTrackIDCollection)trackIdsForCategory:(MWMMarkGroupID)categoryId
{
auto const & trackIds = self.bm.GetTrackIds(categoryId); auto const & trackIds = self.bm.GetTrackIds(categoryId);
NSMutableArray<NSNumber *> * collection = [[NSMutableArray alloc] initWithCapacity:trackIds.size()]; NSMutableArray<NSNumber *> * collection = [[NSMutableArray alloc] initWithCapacity:trackIds.size()];
@@ -581,7 +571,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return collection; return collection;
} }
- (NSArray<MWMTrack *> *)tracksForGroup:(MWMMarkGroupID)groupId { - (NSArray<MWMTrack *> *)tracksForGroup:(MWMMarkGroupID)groupId
{
auto const & trackIds = self.bm.GetTrackIds(groupId); auto const & trackIds = self.bm.GetTrackIds(groupId);
NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:trackIds.size()]; NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:trackIds.size()];
@@ -590,7 +581,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return result; return result;
} }
- (NSArray<MWMBookmarkGroup *> *)collectionsForGroup:(MWMMarkGroupID)groupId { - (NSArray<MWMBookmarkGroup *> *)collectionsForGroup:(MWMMarkGroupID)groupId
{
auto const & collectionIds = self.bm.GetChildrenCollections(groupId); auto const & collectionIds = self.bm.GetChildrenCollections(groupId);
NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:collectionIds.size()]; NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:collectionIds.size()];
@@ -599,7 +591,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return result; return result;
} }
- (NSArray<MWMBookmarkGroup *> *)categoriesForGroup:(MWMMarkGroupID)groupId { - (NSArray<MWMBookmarkGroup *> *)categoriesForGroup:(MWMMarkGroupID)groupId
{
auto const & categoryIds = self.bm.GetChildrenCategories(groupId); auto const & categoryIds = self.bm.GetChildrenCategories(groupId);
NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:categoryIds.size()]; NSMutableArray * result = [[NSMutableArray alloc] initWithCapacity:categoryIds.size()];
@@ -610,48 +603,50 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
#pragma mark - Category sharing #pragma mark - Category sharing
- (void)shareCategory:(MWMMarkGroupID)groupId fileType:(MWMKmlFileType)fileType completion:(SharingResultCompletionHandler)completion { - (void)shareCategory:(MWMMarkGroupID)groupId
self.bm.PrepareFileForSharing({groupId}, [self, completion](auto sharingResult) { fileType:(MWMKmlFileType)fileType
[self handleSharingResult:sharingResult completion:completion]; completion:(SharingResultCompletionHandler)completion
}, convertFileTypeToCore(fileType)); {
self.bm.PrepareFileForSharing({groupId}, [self, completion](auto sharingResult)
{ [self handleSharingResult:sharingResult completion:completion]; }, convertFileTypeToCore(fileType));
} }
- (void)shareAllCategoriesWithCompletion:(SharingResultCompletionHandler)completion { - (void)shareAllCategoriesWithCompletion:(SharingResultCompletionHandler)completion
self.bm.PrepareAllFilesForSharing([self, completion](auto sharingResult) { {
[self handleSharingResult:sharingResult completion:completion]; self.bm.PrepareAllFilesForSharing([self, completion](auto sharingResult)
}); { [self handleSharingResult:sharingResult completion:completion]; });
} }
- (void)shareTrack:(MWMTrackID)trackId fileType:(MWMKmlFileType)fileType completion:(SharingResultCompletionHandler)completion { - (void)shareTrack:(MWMTrackID)trackId
self.bm.PrepareTrackFileForSharing(trackId, [self, completion](auto sharingResult) { fileType:(MWMKmlFileType)fileType
[self handleSharingResult:sharingResult completion:completion]; completion:(SharingResultCompletionHandler)completion
}, convertFileTypeToCore(fileType)); {
self.bm.PrepareTrackFileForSharing(trackId, [self, completion](auto sharingResult)
{ [self handleSharingResult:sharingResult completion:completion]; }, convertFileTypeToCore(fileType));
} }
- (void)handleSharingResult:(BookmarkManager::SharingResult)sharingResult completion:(SharingResultCompletionHandler)completion { - (void)handleSharingResult:(BookmarkManager::SharingResult)sharingResult
NSURL *urlToALocalFile = nil; completion:(SharingResultCompletionHandler)completion
{
NSURL * urlToALocalFile = nil;
MWMBookmarksShareStatus status; MWMBookmarksShareStatus status;
switch (sharingResult.m_code) { switch (sharingResult.m_code)
case BookmarkManager::SharingResult::Code::Success: {
urlToALocalFile = [NSURL fileURLWithPath:@(sharingResult.m_sharingPath.c_str()) isDirectory:NO]; case BookmarkManager::SharingResult::Code::Success:
ASSERT(urlToALocalFile, ("Invalid share category URL")); urlToALocalFile = [NSURL fileURLWithPath:@(sharingResult.m_sharingPath.c_str()) isDirectory:NO];
self.shareCategoryURL = urlToALocalFile; ASSERT(urlToALocalFile, ("Invalid share category URL"));
status = MWMBookmarksShareStatusSuccess; self.shareCategoryURL = urlToALocalFile;
break; status = MWMBookmarksShareStatusSuccess;
case BookmarkManager::SharingResult::Code::EmptyCategory: break;
status = MWMBookmarksShareStatusEmptyCategory; case BookmarkManager::SharingResult::Code::EmptyCategory: status = MWMBookmarksShareStatusEmptyCategory; break;
break; case BookmarkManager::SharingResult::Code::ArchiveError: status = MWMBookmarksShareStatusArchiveError; break;
case BookmarkManager::SharingResult::Code::ArchiveError: case BookmarkManager::SharingResult::Code::FileError: status = MWMBookmarksShareStatusFileError; break;
status = MWMBookmarksShareStatusArchiveError;
break;
case BookmarkManager::SharingResult::Code::FileError:
status = MWMBookmarksShareStatusFileError;
break;
} }
completion(status, urlToALocalFile); completion(status, urlToALocalFile);
} }
- (void)finishSharing { - (void)finishSharing
{
if (!self.shareCategoryURL) if (!self.shareCategoryURL)
return; return;
@@ -661,17 +656,20 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
#pragma mark - Notifications #pragma mark - Notifications
- (void)setNotificationsEnabled:(BOOL)enabled { - (void)setNotificationsEnabled:(BOOL)enabled
{
self.bm.SetNotificationsEnabled(enabled); self.bm.SetNotificationsEnabled(enabled);
} }
- (BOOL)areNotificationsEnabled { - (BOOL)areNotificationsEnabled
{
return self.bm.AreNotificationsEnabled(); return self.bm.AreNotificationsEnabled();
} }
#pragma mark - Catalog #pragma mark - Catalog
- (NSArray<MWMBookmarkGroup *> *)sortedUserCategories { - (NSArray<MWMBookmarkGroup *> *)sortedUserCategories
{
auto const & list = self.bm.GetSortedBmGroupIdList(); auto const & list = self.bm.GetSortedBmGroupIdList();
NSMutableArray<MWMBookmarkGroup *> * result = [[NSMutableArray alloc] initWithCapacity:list.size()]; NSMutableArray<MWMBookmarkGroup *> * result = [[NSMutableArray alloc] initWithCapacity:list.size()];
@@ -680,11 +678,13 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
return result; return result;
} }
- (MWMBookmarkGroup *)categoryWithId:(MWMMarkGroupID)groupId { - (MWMBookmarkGroup *)categoryWithId:(MWMMarkGroupID)groupId
{
return [[MWMBookmarkGroup alloc] initWithCategoryId:groupId bookmarksManager:self]; return [[MWMBookmarkGroup alloc] initWithCategoryId:groupId bookmarksManager:self];
} }
- (size_t)userCategoriesCount { - (size_t)userCategoriesCount
{
return self.bm.GetBmGroupsCount(); return self.bm.GetBmGroupsCount();
} }
@@ -692,7 +692,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
setGroupId:(MWMMarkGroupID)groupId setGroupId:(MWMMarkGroupID)groupId
title:(NSString *)title title:(NSString *)title
color:(MWMBookmarkColor)color color:(MWMBookmarkColor)color
description:(NSString *)description { description:(NSString *)description
{
ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ()); ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ());
auto const currentGroupId = self.bm.GetBookmark(bookmarkId)->GetGroupId(); auto const currentGroupId = self.bm.GetBookmark(bookmarkId)->GetGroupId();
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
@@ -712,7 +713,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
bookmark->SetCustomName(title.UTF8String); bookmark->SetCustomName(title.UTF8String);
} }
- (void)updateBookmark:(MWMMarkID)bookmarkId setColor:(MWMBookmarkColor)color { - (void)updateBookmark:(MWMMarkID)bookmarkId setColor:(MWMBookmarkColor)color
{
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
auto bookmark = editSession.GetBookmarkForEdit(bookmarkId); auto bookmark = editSession.GetBookmarkForEdit(bookmarkId);
@@ -725,10 +727,12 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
bookmark->SetColor(kmlColor); bookmark->SetColor(kmlColor);
} }
- (void)moveBookmark:(MWMMarkID)bookmarkId toGroupId:(MWMMarkGroupID)groupId { - (void)moveBookmark:(MWMMarkID)bookmarkId toGroupId:(MWMMarkGroupID)groupId
{
ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ()); ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ());
auto const currentGroupId = self.bm.GetBookmark(bookmarkId)->GetGroupId(); auto const currentGroupId = self.bm.GetBookmark(bookmarkId)->GetGroupId();
if (currentGroupId != groupId) { if (currentGroupId != groupId)
{
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
editSession.MoveBookmark(bookmarkId, currentGroupId, groupId); editSession.MoveBookmark(bookmarkId, currentGroupId, groupId);
} }
@@ -737,7 +741,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
- (void)updateTrack:(MWMTrackID)trackId - (void)updateTrack:(MWMTrackID)trackId
setGroupId:(MWMMarkGroupID)groupId setGroupId:(MWMMarkGroupID)groupId
color:(UIColor *)color color:(UIColor *)color
title:(NSString *)title { title:(NSString *)title
{
ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ()); ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ());
auto const currentGroupId = self.bm.GetTrack(trackId)->GetGroupId(); auto const currentGroupId = self.bm.GetTrack(trackId)->GetGroupId();
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
@@ -756,7 +761,8 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
track->SetName(title.UTF8String); track->SetName(title.UTF8String);
} }
- (void)updateTrack:(MWMTrackID)trackId setColor:(UIColor *)color { - (void)updateTrack:(MWMTrackID)trackId setColor:(UIColor *)color
{
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
auto track = editSession.GetTrackForEdit(trackId); auto track = editSession.GetTrackForEdit(trackId);
@@ -769,16 +775,19 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
track->SetColor(newColor); track->SetColor(newColor);
} }
- (void)moveTrack:(MWMTrackID)trackId toGroupId:(MWMMarkGroupID)groupId { - (void)moveTrack:(MWMTrackID)trackId toGroupId:(MWMMarkGroupID)groupId
{
ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ()); ASSERT_NOT_EQUAL(groupId, kml::kInvalidMarkGroupId, ());
auto const currentGroupId = self.bm.GetTrack(trackId)->GetGroupId(); auto const currentGroupId = self.bm.GetTrack(trackId)->GetGroupId();
if (currentGroupId != groupId) { if (currentGroupId != groupId)
{
auto editSession = self.bm.GetEditSession(); auto editSession = self.bm.GetEditSession();
editSession.MoveTrack(trackId, currentGroupId, groupId); editSession.MoveTrack(trackId, currentGroupId, groupId);
} }
} }
- (BOOL)hasRecentlyDeletedBookmark { - (BOOL)hasRecentlyDeletedBookmark
{
return self.bm.HasRecentlyDeletedBookmark(); return self.bm.HasRecentlyDeletedBookmark();
} }
@@ -786,39 +795,46 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
{ {
switch (author) switch (author)
{ {
case MWMBookmarkGroupAuthorTypeLocal: case MWMBookmarkGroupAuthorTypeLocal:
self.bm.GetEditSession().SetCategoryCustomProperty(groupId, @"author_type".UTF8String, @"local".UTF8String); self.bm.GetEditSession().SetCategoryCustomProperty(groupId, @"author_type".UTF8String, @"local".UTF8String);
break; break;
case MWMBookmarkGroupAuthorTypeTraveler: case MWMBookmarkGroupAuthorTypeTraveler:
self.bm.GetEditSession().SetCategoryCustomProperty(groupId, @"author_type".UTF8String, @"tourist".UTF8String); self.bm.GetEditSession().SetCategoryCustomProperty(groupId, @"author_type".UTF8String, @"tourist".UTF8String);
} }
} }
// MARK: - RecentlyDeletedCategoriesManager // MARK: - RecentlyDeletedCategoriesManager
- (uint64_t)recentlyDeletedCategoriesCount { - (uint64_t)recentlyDeletedCategoriesCount
{
return self.bm.GetRecentlyDeletedCategoriesCount(); return self.bm.GetRecentlyDeletedCategoriesCount();
} }
- (NSArray<RecentlyDeletedCategory *> *)getRecentlyDeletedCategories { - (NSArray<RecentlyDeletedCategory *> *)getRecentlyDeletedCategories
{
auto const categoriesCollection = self.bm.GetRecentlyDeletedCategories(); auto const categoriesCollection = self.bm.GetRecentlyDeletedCategories();
NSMutableArray<RecentlyDeletedCategory *> * recentlyDeletedCategories = [[NSMutableArray alloc] initWithCapacity:categoriesCollection->size()]; NSMutableArray<RecentlyDeletedCategory *> * recentlyDeletedCategories =
[[NSMutableArray alloc] initWithCapacity:categoriesCollection->size()];
for (auto const & [filePath, categoryPtr] : * categoriesCollection) { for (auto const & [filePath, categoryPtr] : *categoriesCollection)
{
ASSERT(categoryPtr, ("Recently deleted category shouldn't be nil.")); ASSERT(categoryPtr, ("Recently deleted category shouldn't be nil."));
RecentlyDeletedCategory * category = [[RecentlyDeletedCategory alloc] initWithCategoryData:categoryPtr->m_categoryData filePath:filePath]; RecentlyDeletedCategory * category =
[[RecentlyDeletedCategory alloc] initWithCategoryData:categoryPtr->m_categoryData filePath:filePath];
[recentlyDeletedCategories addObject:category]; [recentlyDeletedCategories addObject:category];
} }
return recentlyDeletedCategories; return recentlyDeletedCategories;
} }
- (void)deleteRecentlyDeletedCategoryAtURLs:(NSArray<NSURL *> *)urls { - (void)deleteRecentlyDeletedCategoryAtURLs:(NSArray<NSURL *> *)urls
{
std::vector<std::string> filePaths; std::vector<std::string> filePaths;
for (NSURL * url in urls) for (NSURL * url in urls)
filePaths.push_back(url.filePathURL.path.UTF8String); filePaths.push_back(url.filePathURL.path.UTF8String);
self.bm.DeleteRecentlyDeletedCategoriesAtPaths(filePaths); self.bm.DeleteRecentlyDeletedCategoriesAtPaths(filePaths);
} }
- (void)recoverRecentlyDeletedCategoriesAtURLs:(NSArray<NSURL *> *)urls { - (void)recoverRecentlyDeletedCategoriesAtURLs:(NSArray<NSURL *> *)urls
{
std::vector<std::string> filePaths; std::vector<std::string> filePaths;
for (NSURL * url in urls) for (NSURL * url in urls)
filePaths.push_back(url.filePathURL.path.UTF8String); filePaths.push_back(url.filePathURL.path.UTF8String);
@@ -830,51 +846,54 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
- (void)loopObservers:(void (^)(id<MWMBookmarksObserver> observer))block - (void)loopObservers:(void (^)(id<MWMBookmarksObserver> observer))block
{ {
for (id<MWMBookmarksObserver> observer in [self.observers copy]) for (id<MWMBookmarksObserver> observer in [self.observers copy])
{
if (observer) if (observer)
block(observer); block(observer);
}
} }
- (void)setElevationActivePoint:(CLLocationCoordinate2D)point distance:(double)distance trackId:(uint64_t)trackId { - (void)setElevationActivePoint:(CLLocationCoordinate2D)point distance:(double)distance trackId:(uint64_t)trackId
{
self.bm.SetElevationActivePoint(trackId, mercator::FromLatLon(point.latitude, point.longitude), distance); self.bm.SetElevationActivePoint(trackId, mercator::FromLatLon(point.latitude, point.longitude), distance);
} }
- (void)setElevationActivePointChanged:(uint64_t)trackId callback:(ElevationPointChangedBlock)callback { - (void)setElevationActivePointChanged:(uint64_t)trackId callback:(ElevationPointChangedBlock)callback
{
__weak __typeof(self) ws = self; __weak __typeof(self) ws = self;
self.bm.SetElevationActivePointChangedCallback([callback, trackId, ws] () { self.bm.SetElevationActivePointChangedCallback([callback, trackId, ws]()
callback(ws.bm.GetElevationActivePoint(trackId)); { callback(ws.bm.GetElevationActivePoint(trackId)); });
});
} }
- (void)resetElevationActivePointChanged { - (void)resetElevationActivePointChanged
{
self.bm.SetElevationActivePointChangedCallback(nullptr); self.bm.SetElevationActivePointChangedCallback(nullptr);
} }
- (void)setElevationMyPositionChanged:(uint64_t)trackId callback:(ElevationPointChangedBlock)callback { - (void)setElevationMyPositionChanged:(uint64_t)trackId callback:(ElevationPointChangedBlock)callback
{
__weak __typeof(self) ws = self; __weak __typeof(self) ws = self;
self.bm.SetElevationMyPositionChangedCallback([callback, trackId, ws] () { self.bm.SetElevationMyPositionChangedCallback([callback, trackId, ws]()
callback(ws.bm.GetElevationMyPosition(trackId)); { callback(ws.bm.GetElevationMyPosition(trackId)); });
});
} }
- (void)resetElevationMyPositionChanged { - (void)resetElevationMyPositionChanged
{
self.bm.SetElevationMyPositionChangedCallback(nullptr); self.bm.SetElevationMyPositionChangedCallback(nullptr);
} }
+ (dp::Color)getColorFromUIColor:(UIColor *)color { + (dp::Color)getColorFromUIColor:(UIColor *)color
{
CGFloat fRed, fGreen, fBlue, fAlpha; CGFloat fRed, fGreen, fBlue, fAlpha;
[color getRed:&fRed green:&fGreen blue:&fBlue alpha:&fAlpha]; [color getRed:&fRed green:&fGreen blue:&fBlue alpha:&fAlpha];
const uint8_t red = [self convertColorComponentToHex:fRed]; uint8_t const red = [self convertColorComponentToHex:fRed];
const uint8_t green = [self convertColorComponentToHex:fGreen]; uint8_t const green = [self convertColorComponentToHex:fGreen];
const uint8_t blue = [self convertColorComponentToHex:fBlue]; uint8_t const blue = [self convertColorComponentToHex:fBlue];
const uint8_t alpha = [self convertColorComponentToHex:fAlpha]; uint8_t const alpha = [self convertColorComponentToHex:fAlpha];
return dp::Color(red, green, blue, alpha); return dp::Color(red, green, blue, alpha);
} }
+ (uint8_t)convertColorComponentToHex:(CGFloat)color { + (uint8_t)convertColorComponentToHex:(CGFloat)color
{
ASSERT_LESS_OR_EQUAL(color, 1.f, ("Extended sRGB color space is not supported")); ASSERT_LESS_OR_EQUAL(color, 1.f, ("Extended sRGB color space is not supported"));
ASSERT_GREATER_OR_EQUAL(color, 0.f, ("Extended sRGB color space is not supported")); ASSERT_GREATER_OR_EQUAL(color, 0.f, ("Extended sRGB color space is not supported"));
static constexpr uint8_t kMaxChannelValue = 255; static constexpr uint8_t kMaxChannelValue = 255;

View File

@@ -2,19 +2,21 @@
#include "Framework.h" #include "Framework.h"
#include "geometry/mercator.hpp" #include "geometry/mercator.hpp"
@interface MWMCarPlayBookmarkObject() @interface MWMCarPlayBookmarkObject ()
@property(assign, nonatomic, readwrite) MWMMarkID bookmarkId; @property(assign, nonatomic, readwrite) MWMMarkID bookmarkId;
@property(strong, nonatomic, readwrite) NSString *prefferedName; @property(strong, nonatomic, readwrite) NSString * prefferedName;
@property(strong, nonatomic, readwrite) NSString *address; @property(strong, nonatomic, readwrite) NSString * address;
@property(assign, nonatomic, readwrite) CLLocationCoordinate2D coordinate; @property(assign, nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property(assign, nonatomic, readwrite) CGPoint mercatorPoint; @property(assign, nonatomic, readwrite) CGPoint mercatorPoint;
@end @end
@implementation MWMCarPlayBookmarkObject @implementation MWMCarPlayBookmarkObject
- (instancetype)initWithBookmarkId:(MWMMarkID)bookmarkId { - (instancetype)initWithBookmarkId:(MWMMarkID)bookmarkId
{
self = [super init]; self = [super init];
if (self) { if (self)
{
self.bookmarkId = bookmarkId; self.bookmarkId = bookmarkId;
auto const & bm = GetFramework().GetBookmarkManager(); auto const & bm = GetFramework().GetBookmarkManager();
Bookmark const * bookmark = bm.GetBookmark(bookmarkId); Bookmark const * bookmark = bm.GetBookmark(bookmarkId);

View File

@@ -6,9 +6,11 @@
@implementation MWMTrack (Core) @implementation MWMTrack (Core)
- (instancetype)initWithTrackId:(MWMTrackID)trackId trackData:(Track const *)track { - (instancetype)initWithTrackId:(MWMTrackID)trackId trackData:(Track const *)track
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_trackId = trackId; _trackId = trackId;
_trackName = @(track->GetName().c_str()); _trackName = @(track->GetName().c_str());
_trackLengthMeters = track->GetLengthMeters(); _trackLengthMeters = track->GetLengthMeters();

View File

@@ -1,13 +1,15 @@
#import "RecentlyDeletedCategory+Core.h" #import "RecentlyDeletedCategory+Core.h"
#include <map/bookmark_helpers.hpp>
#include <platform/platform_ios.h> #include <platform/platform_ios.h>
#include <map/bookmark_helpers.hpp>
@implementation RecentlyDeletedCategory @implementation RecentlyDeletedCategory
- (instancetype)initTitle:(NSString *)title fileURL:(NSURL *)fileURL deletionDate:(NSDate *)deletionDate { - (instancetype)initTitle:(NSString *)title fileURL:(NSURL *)fileURL deletionDate:(NSDate *)deletionDate
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_title = title; _title = title;
_fileURL = fileURL; _fileURL = fileURL;
_deletionDate = deletionDate; _deletionDate = deletionDate;
@@ -19,9 +21,11 @@
@implementation RecentlyDeletedCategory (Core) @implementation RecentlyDeletedCategory (Core)
- (instancetype)initWithCategoryData:(kml::CategoryData)data filePath:(std::string const &)filePath { - (instancetype)initWithCategoryData:(kml::CategoryData)data filePath:(std::string const &)filePath
{
self = [super init]; self = [super init];
if (self) { if (self)
{
auto const name = GetPreferredBookmarkStr(data.m_name); auto const name = GetPreferredBookmarkStr(data.m_name);
_title = [NSString stringWithCString:name.c_str() encoding:NSUTF8StringEncoding]; _title = [NSString stringWithCString:name.c_str() encoding:NSUTF8StringEncoding];
auto const pathString = [NSString stringWithCString:filePath.c_str() encoding:NSUTF8StringEncoding]; auto const pathString = [NSString stringWithCString:filePath.c_str() encoding:NSUTF8StringEncoding];

View File

@@ -1,9 +1,10 @@
#import "TrackInfo+Core.h"
#import "StringUtils.h" #import "StringUtils.h"
#import "TrackInfo+Core.h"
@implementation TrackInfo @implementation TrackInfo
+ (TrackInfo *)emptyInfo { + (TrackInfo *)emptyInfo
{
return [[TrackInfo alloc] initWithTrackStatistics:TrackStatistics()]; return [[TrackInfo alloc] initWithTrackStatistics:TrackStatistics()];
} }
@@ -11,17 +12,17 @@
@implementation TrackInfo (Core) @implementation TrackInfo (Core)
- (instancetype)initWithTrackStatistics:(TrackStatistics const &)statistics { - (instancetype)initWithTrackStatistics:(TrackStatistics const &)statistics
if (self = [super init]) { {
if (self = [super init])
{
_distance = ToNSString(statistics.GetFormattedLength()); _distance = ToNSString(statistics.GetFormattedLength());
_duration = ToNSString(statistics.GetFormattedDuration()); _duration = ToNSString(statistics.GetFormattedDuration());
_ascent = ToNSString(statistics.GetFormattedAscent()); _ascent = ToNSString(statistics.GetFormattedAscent());
_descent = ToNSString(statistics.GetFormattedDescent()); _descent = ToNSString(statistics.GetFormattedDescent());
_maxElevation = ToNSString(statistics.GetFormattedMaxElevation()); _maxElevation = ToNSString(statistics.GetFormattedMaxElevation());
_minElevation = ToNSString(statistics.GetFormattedMinElevation()); _minElevation = ToNSString(statistics.GetFormattedMinElevation());
_hasElevationInfo = statistics.m_ascent != 0 || _hasElevationInfo = statistics.m_ascent != 0 || statistics.m_descent != 0 || statistics.m_maxElevation != 0 ||
statistics.m_descent != 0 ||
statistics.m_maxElevation != 0 ||
statistics.m_minElevation != 0; statistics.m_minElevation != 0;
} }
return self; return self;

View File

@@ -24,9 +24,7 @@
{ {
static AppInfo * appInfo; static AppInfo * appInfo;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ appInfo = [[self alloc] init]; });
appInfo = [[self alloc] init];
});
return appInfo; return appInfo;
} }
@@ -94,7 +92,8 @@
NSURL * telURL = [NSURL URLWithString:@"tel://"]; NSURL * telURL = [NSURL URLWithString:@"tel://"];
if (![UIApplication.sharedApplication canOpenURL:telURL]) if (![UIApplication.sharedApplication canOpenURL:telURL])
return NO; return NO;
NSDictionary<NSString *,CTCarrier *> * dict = [[CTTelephonyNetworkInfo alloc] init].serviceSubscriberCellularProviders; NSDictionary<NSString *, CTCarrier *> * dict =
[[CTTelephonyNetworkInfo alloc] init].serviceSubscriberCellularProviders;
for (id key in dict) for (id key in dict)
{ {
NSString * networkCode = [dict objectForKey:key].mobileNetworkCode; NSString * networkCode = [dict objectForKey:key].mobileNetworkCode;

View File

@@ -1,12 +1,12 @@
#import "MWMGeoUtil.h" #import "MWMGeoUtil.h"
#include "geometry/mercator.hpp"
#include "geometry/angles.hpp" #include "geometry/angles.hpp"
#include "geometry/mercator.hpp"
#include "platform/locale.hpp" #include "platform/locale.hpp"
#include "platform/localization.hpp" #include "platform/localization.hpp"
#include "platform/settings.hpp"
#include "platform/measurement_utils.hpp" #include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
@implementation Measure @implementation Measure
@@ -31,34 +31,39 @@
let speedString = formatter.string(from: speedMeasurement) let speedString = formatter.string(from: speedMeasurement)
*/ */
- (NSString*) valueAsString { - (NSString *)valueAsString
{
auto const outString = measurement_utils::ToStringPrecision(self.value, self.value >= 10.0 ? 0 : 1); auto const outString = measurement_utils::ToStringPrecision(self.value, self.value >= 10.0 ? 0 : 1);
return [NSString stringWithUTF8String:outString.c_str()]; return [NSString stringWithUTF8String:outString.c_str()];
} }
- (instancetype)initAsSpeed:(double) mps { - (instancetype)initAsSpeed:(double)mps
self = [super init]; {
if (self) { self = [super init];
auto units = measurement_utils::Units::Metric; if (self)
settings::TryGet(settings::kMeasurementUnits, units); {
_value = measurement_utils::MpsToUnits(mps, units); auto units = measurement_utils::Units::Metric;
settings::TryGet(settings::kMeasurementUnits, units);
_value = measurement_utils::MpsToUnits(mps, units);
_unit = @(platform::GetLocalizedSpeedUnits(units).c_str()); _unit = @(platform::GetLocalizedSpeedUnits(units).c_str());
} }
return self; return self;
} }
@end @end
@implementation MWMGeoUtil @implementation MWMGeoUtil
+ (float)angleAtPoint:(CLLocationCoordinate2D)p1 toPoint:(CLLocationCoordinate2D)p2 { + (float)angleAtPoint:(CLLocationCoordinate2D)p1 toPoint:(CLLocationCoordinate2D)p2
{
auto mp1 = mercator::FromLatLon(p1.latitude, p1.longitude); auto mp1 = mercator::FromLatLon(p1.latitude, p1.longitude);
auto mp2 = mercator::FromLatLon(p2.latitude, p2.longitude); auto mp2 = mercator::FromLatLon(p2.latitude, p2.longitude);
return ang::AngleTo(mp1, mp2); return ang::AngleTo(mp1, mp2);
} }
+ (NSString *)formattedOsmLinkForCoordinate:(CLLocationCoordinate2D)coordinate zoomLevel:(int)zoomLevel { + (NSString *)formattedOsmLinkForCoordinate:(CLLocationCoordinate2D)coordinate zoomLevel:(int)zoomLevel
{
auto const link = measurement_utils::FormatOsmLink(coordinate.latitude, coordinate.longitude, zoomLevel); auto const link = measurement_utils::FormatOsmLink(coordinate.latitude, coordinate.longitude, zoomLevel);
return [NSString stringWithCString:link.c_str() encoding:NSUTF8StringEncoding]; return [NSString stringWithCString:link.c_str() encoding:NSUTF8StringEncoding];
} }

View File

@@ -6,17 +6,19 @@ static inline InAppFeatureHighlightType FeatureTypeFrom(url_scheme::InAppFeature
using namespace url_scheme; using namespace url_scheme;
switch (type) switch (type)
{ {
case InAppFeatureHighlightRequest::InAppFeatureType::None: return InAppFeatureHighlightTypeNone; case InAppFeatureHighlightRequest::InAppFeatureType::None: return InAppFeatureHighlightTypeNone;
case InAppFeatureHighlightRequest::InAppFeatureType::TrackRecorder: return InAppFeatureHighlightTypeTrackRecorder; case InAppFeatureHighlightRequest::InAppFeatureType::TrackRecorder: return InAppFeatureHighlightTypeTrackRecorder;
case InAppFeatureHighlightRequest::InAppFeatureType::iCloud: return InAppFeatureHighlightTypeICloud; case InAppFeatureHighlightRequest::InAppFeatureType::iCloud: return InAppFeatureHighlightTypeICloud;
} }
} }
@implementation DeepLinkInAppFeatureHighlightData @implementation DeepLinkInAppFeatureHighlightData
- (instancetype)init:(DeeplinkUrlType)urlType { - (instancetype)init:(DeeplinkUrlType)urlType
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_urlType = urlType; _urlType = urlType;
_feature = FeatureTypeFrom(GetFramework().GetInAppFeatureHighlightRequest().m_feature); _feature = FeatureTypeFrom(GetFramework().GetInAppFeatureHighlightRequest().m_feature);
} }

View File

@@ -9,29 +9,32 @@ static inline DeeplinkUrlType deeplinkUrlType(url_scheme::ParsedMapApi::UrlType
using namespace url_scheme; using namespace url_scheme;
switch (type) switch (type)
{ {
case ParsedMapApi::UrlType::Incorrect: return DeeplinkUrlTypeIncorrect; case ParsedMapApi::UrlType::Incorrect: return DeeplinkUrlTypeIncorrect;
case ParsedMapApi::UrlType::Map: return DeeplinkUrlTypeMap; case ParsedMapApi::UrlType::Map: return DeeplinkUrlTypeMap;
case ParsedMapApi::UrlType::Route: return DeeplinkUrlTypeRoute; case ParsedMapApi::UrlType::Route: return DeeplinkUrlTypeRoute;
case ParsedMapApi::UrlType::Search: return DeeplinkUrlTypeSearch; case ParsedMapApi::UrlType::Search: return DeeplinkUrlTypeSearch;
case ParsedMapApi::UrlType::Crosshair: return DeeplinkUrlTypeCrosshair; case ParsedMapApi::UrlType::Crosshair: return DeeplinkUrlTypeCrosshair;
case ParsedMapApi::UrlType::OAuth2: return DeeplinkUrlTypeOAuth2; case ParsedMapApi::UrlType::OAuth2: return DeeplinkUrlTypeOAuth2;
case ParsedMapApi::UrlType::Menu: return DeeplinkUrlTypeMenu; case ParsedMapApi::UrlType::Menu: return DeeplinkUrlTypeMenu;
case ParsedMapApi::UrlType::Settings: return DeeplinkUrlTypeSettings; case ParsedMapApi::UrlType::Settings: return DeeplinkUrlTypeSettings;
} }
} }
@implementation DeepLinkParser @implementation DeepLinkParser
+ (DeeplinkUrlType)parseAndSetApiURL:(NSURL *)url { + (DeeplinkUrlType)parseAndSetApiURL:(NSURL *)url
Framework &f = GetFramework(); {
Framework & f = GetFramework();
return deeplinkUrlType(f.ParseAndSetApiURL(url.absoluteString.UTF8String)); return deeplinkUrlType(f.ParseAndSetApiURL(url.absoluteString.UTF8String));
} }
+ (void)executeMapApiRequest { + (void)executeMapApiRequest
{
GetFramework().ExecuteMapApiRequest(); GetFramework().ExecuteMapApiRequest();
} }
+ (void)addBookmarksFile:(NSURL *)url { + (void)addBookmarksFile:(NSURL *)url
{
// iOS doesn't create temporary files on import at least in Safari and Files. // iOS doesn't create temporary files on import at least in Safari and Files.
GetFramework().AddBookmarksFile(url.path.UTF8String, false /* isTemporaryFile */); GetFramework().AddBookmarksFile(url.path.UTF8String, false /* isTemporaryFile */);
} }

View File

@@ -1,14 +1,16 @@
#import "DeepLinkSearchData.h" #import "DeepLinkSearchData.h"
#import <CoreApi/Framework.h> #import <CoreApi/Framework.h>
#include "drape_frontend/visual_params.hpp" #include "drape_frontend/visual_params.hpp"
#include "geometry/mercator.hpp"
#include "geometry/latlon.hpp" #include "geometry/latlon.hpp"
#include "geometry/mercator.hpp"
@implementation DeepLinkSearchData @implementation DeepLinkSearchData
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
auto const &request = GetFramework().GetParsedSearchRequest(); {
auto const & request = GetFramework().GetParsedSearchRequest();
ms::LatLon const center = GetFramework().GetParsedCenterLatLon(); ms::LatLon const center = GetFramework().GetParsedCenterLatLon();
_query = [@((request.m_query + " ").c_str()) stringByRemovingPercentEncoding]; _query = [@((request.m_query + " ").c_str()) stringByRemovingPercentEncoding];
_locale = @(request.m_locale.c_str()); _locale = @(request.m_locale.c_str());
@@ -19,11 +21,13 @@
return self; return self;
} }
- (BOOL)hasValidCenterLatLon { - (BOOL)hasValidCenterLatLon
{
return _centerLat != ms::LatLon::kInvalid && _centerLon != ms::LatLon::kInvalid; return _centerLat != ms::LatLon::kInvalid && _centerLon != ms::LatLon::kInvalid;
} }
- (void)onViewportChanged:(int)zoomLevel { - (void)onViewportChanged:(int)zoomLevel
{
auto const center = mercator::FromLatLon(_centerLat, _centerLon); auto const center = mercator::FromLatLon(_centerLat, _centerLon);
auto const rect = df::GetRectForDrawScale(zoomLevel, center); auto const rect = df::GetRectForDrawScale(zoomLevel, center);
GetFramework().GetSearchAPI().OnViewportChanged(rect); GetFramework().GetSearchAPI().OnViewportChanged(rect);

View File

@@ -4,7 +4,8 @@
@implementation AltitudeFormatter @implementation AltitudeFormatter
+ (NSString *)altitudeStringFromMeters:(double)meters { + (NSString *)altitudeStringFromMeters:(double)meters
{
auto const altitude = platform::Distance::FormatAltitude(meters); auto const altitude = platform::Distance::FormatAltitude(meters);
return [NSString stringWithUTF8String:altitude.c_str()]; return [NSString stringWithUTF8String:altitude.c_str()];
} }

View File

@@ -4,7 +4,8 @@
@implementation DistanceFormatter @implementation DistanceFormatter
+ (NSString *)distanceStringFromMeters:(double)meters { + (NSString *)distanceStringFromMeters:(double)meters
{
auto const coreDistance = platform::Distance::CreateFormatted(meters); auto const coreDistance = platform::Distance::CreateFormatted(meters);
return [NSString stringWithUTF8String:coreDistance.ToString().c_str()]; return [NSString stringWithUTF8String:coreDistance.ToString().c_str()];
} }

View File

@@ -4,7 +4,8 @@
@implementation DurationFormatter @implementation DurationFormatter
+ (NSString *)durationStringFromTimeInterval:(NSTimeInterval)timeInterval { + (NSString *)durationStringFromTimeInterval:(NSTimeInterval)timeInterval
{
auto const duration = platform::Duration(static_cast<int>(timeInterval)); auto const duration = platform::Duration(static_cast<int>(timeInterval));
return [NSString stringWithCString:duration.GetPlatformLocalizedString().c_str() encoding:NSUTF8StringEncoding]; return [NSString stringWithCString:duration.GetPlatformLocalizedString().c_str() encoding:NSUTF8StringEncoding];
} }

View File

@@ -1,7 +1,7 @@
#import "MWMFrameworkHelper.h" #import "MWMFrameworkHelper.h"
#import "ElevationProfileData+Core.h"
#import "MWMMapSearchResult+Core.h" #import "MWMMapSearchResult+Core.h"
#import "TrackInfo+Core.h" #import "TrackInfo+Core.h"
#import "ElevationProfileData+Core.h"
#include "Framework.h" #include "Framework.h"
@@ -12,15 +12,17 @@
@implementation MWMFrameworkHelper @implementation MWMFrameworkHelper
+ (void)processFirstLaunch:(BOOL)hasLocation { + (void)processFirstLaunch:(BOOL)hasLocation
auto &f = GetFramework(); {
auto & f = GetFramework();
if (!hasLocation) if (!hasLocation)
f.SwitchMyPositionNextMode(); f.SwitchMyPositionNextMode();
else else
f.RunFirstLaunchAnimation(); f.RunFirstLaunchAnimation();
} }
+ (void)setVisibleViewport:(CGRect)rect scaleFactor:(CGFloat)scale { + (void)setVisibleViewport:(CGRect)rect scaleFactor:(CGFloat)scale
{
CGFloat const x0 = rect.origin.x * scale; CGFloat const x0 = rect.origin.x * scale;
CGFloat const y0 = rect.origin.y * scale; CGFloat const y0 = rect.origin.y * scale;
CGFloat const x1 = x0 + rect.size.width * scale; CGFloat const x1 = x0 + rect.size.width * scale;
@@ -28,32 +30,27 @@
GetFramework().SetVisibleViewport(m2::RectD(x0, y0, x1, y1)); GetFramework().SetVisibleViewport(m2::RectD(x0, y0, x1, y1));
} }
+ (void)setTheme:(MWMTheme)theme { + (void)setTheme:(MWMTheme)theme
auto &f = GetFramework(); {
auto & f = GetFramework();
auto const style = f.GetMapStyle(); auto const style = f.GetMapStyle();
auto const isOutdoor = ^BOOL(MapStyle style) { auto const isOutdoor = ^BOOL(MapStyle style) {
switch (style) { switch (style)
case MapStyleOutdoorsLight: {
case MapStyleOutdoorsDark: case MapStyleOutdoorsLight:
return YES; case MapStyleOutdoorsDark: return YES;
default: default: return NO;
return NO;
} }
}(style); }(style);
auto const newStyle = ^MapStyle(MWMTheme theme) { auto const newStyle = ^MapStyle(MWMTheme theme) {
switch (theme) { switch (theme)
case MWMThemeDay: {
return isOutdoor ? MapStyleOutdoorsLight : MapStyleDefaultLight; case MWMThemeDay: return isOutdoor ? MapStyleOutdoorsLight : MapStyleDefaultLight;
case MWMThemeVehicleDay: case MWMThemeVehicleDay: return MapStyleVehicleLight;
return MapStyleVehicleLight; case MWMThemeNight: return isOutdoor ? MapStyleOutdoorsDark : MapStyleDefaultDark;
case MWMThemeNight: case MWMThemeVehicleNight: return MapStyleVehicleDark;
return isOutdoor ? MapStyleOutdoorsDark : MapStyleDefaultDark; case MWMThemeAuto: NSAssert(NO, @"Invalid theme"); return MapStyleDefaultLight;
case MWMThemeVehicleNight:
return MapStyleVehicleDark;
case MWMThemeAuto:
NSAssert(NO, @"Invalid theme");
return MapStyleDefaultLight;
} }
}(theme); }(theme);
@@ -61,135 +58,149 @@
f.SetMapStyle(newStyle); f.SetMapStyle(newStyle);
} }
+ (MWMDayTime)daytimeAtLocation:(CLLocation *)location { + (MWMDayTime)daytimeAtLocation:(CLLocation *)location
{
if (!location) if (!location)
return MWMDayTimeDay; return MWMDayTimeDay;
DayTimeType dayTime = DayTimeType dayTime =
GetDayTime(NSDate.date.timeIntervalSince1970, location.coordinate.latitude, location.coordinate.longitude); GetDayTime(NSDate.date.timeIntervalSince1970, location.coordinate.latitude, location.coordinate.longitude);
switch (dayTime) { switch (dayTime)
case DayTimeType::Day: {
case DayTimeType::PolarDay: case DayTimeType::Day:
return MWMDayTimeDay; case DayTimeType::PolarDay: return MWMDayTimeDay;
case DayTimeType::Night: case DayTimeType::Night:
case DayTimeType::PolarNight: case DayTimeType::PolarNight: return MWMDayTimeNight;
return MWMDayTimeNight;
} }
} }
+ (void)createFramework { + (void)createFramework
{
UNUSED_VALUE(GetFramework()); UNUSED_VALUE(GetFramework());
} }
+ (MWMMarkID)invalidBookmarkId { + (MWMMarkID)invalidBookmarkId
{
return kml::kInvalidMarkId; return kml::kInvalidMarkId;
} }
+ (MWMMarkGroupID)invalidCategoryId { + (MWMMarkGroupID)invalidCategoryId
{
return kml::kInvalidMarkGroupId; return kml::kInvalidMarkGroupId;
} }
+ (NSArray<NSString *> *)obtainLastSearchQueries { + (NSArray<NSString *> *)obtainLastSearchQueries
NSMutableArray *result = [NSMutableArray array]; {
auto const &queries = GetFramework().GetSearchAPI().GetLastSearchQueries(); NSMutableArray * result = [NSMutableArray array];
for (auto const &item : queries) { auto const & queries = GetFramework().GetSearchAPI().GetLastSearchQueries();
for (auto const & item : queries)
[result addObject:@(item.second.c_str())]; [result addObject:@(item.second.c_str())];
}
return [result copy]; return [result copy];
} }
#pragma mark - Map Interaction #pragma mark - Map Interaction
+ (void)zoomMap:(MWMZoomMode)mode { + (void)zoomMap:(MWMZoomMode)mode
switch (mode) { {
case MWMZoomModeIn: switch (mode)
GetFramework().Scale(Framework::SCALE_MAG, true); {
break; case MWMZoomModeIn: GetFramework().Scale(Framework::SCALE_MAG, true); break;
case MWMZoomModeOut: case MWMZoomModeOut: GetFramework().Scale(Framework::SCALE_MIN, true); break;
GetFramework().Scale(Framework::SCALE_MIN, true);
break;
} }
} }
+ (void)moveMap:(UIOffset)offset { + (void)moveMap:(UIOffset)offset
{
GetFramework().Move(offset.horizontal, offset.vertical, true); GetFramework().Move(offset.horizontal, offset.vertical, true);
} }
+ (void)scrollMap:(double) distanceX :(double) distanceY { + (void)scrollMap:(double)distanceX:(double)distanceY
{
GetFramework().Scroll(distanceX, distanceY); GetFramework().Scroll(distanceX, distanceY);
} }
+ (void)deactivateMapSelection { + (void)deactivateMapSelection
{
GetFramework().DeactivateMapSelection(); GetFramework().DeactivateMapSelection();
} }
+ (void)switchMyPositionMode { + (void)switchMyPositionMode
{
GetFramework().SwitchMyPositionNextMode(); GetFramework().SwitchMyPositionNextMode();
} }
+ (void)stopLocationFollow { + (void)stopLocationFollow
{
GetFramework().StopLocationFollow(); GetFramework().StopLocationFollow();
} }
+ (void)rotateMap:(double)azimuth animated:(BOOL)isAnimated { + (void)rotateMap:(double)azimuth animated:(BOOL)isAnimated
{
GetFramework().Rotate(azimuth, isAnimated); GetFramework().Rotate(azimuth, isAnimated);
} }
+ (void)updatePositionArrowOffset:(BOOL)useDefault offset:(int)offsetY { + (void)updatePositionArrowOffset:(BOOL)useDefault offset:(int)offsetY
{
GetFramework().UpdateMyPositionRoutingOffset(useDefault, offsetY); GetFramework().UpdateMyPositionRoutingOffset(useDefault, offsetY);
} }
+ (int64_t)dataVersion { + (int64_t)dataVersion
{
return GetFramework().GetCurrentDataVersion(); return GetFramework().GetCurrentDataVersion();
} }
+ (void)searchInDownloader:(NSString *)query + (void)searchInDownloader:(NSString *)query
inputLocale:(NSString *)locale inputLocale:(NSString *)locale
completion:(SearchInDownloaderCompletions)completion { completion:(SearchInDownloaderCompletions)completion
storage::DownloaderSearchParams params{ {
query.UTF8String, storage::DownloaderSearchParams params{query.UTF8String, locale.precomposedStringWithCompatibilityMapping.UTF8String,
locale.precomposedStringWithCompatibilityMapping.UTF8String, // m_onResults
// m_onResults [completion](storage::DownloaderSearchResults const & results)
[completion](storage::DownloaderSearchResults const & results) {
NSMutableArray * resultsArray = [NSMutableArray arrayWithCapacity:results.m_results.size()];
for (auto const & res : results.m_results)
{ {
NSMutableArray *resultsArray = [NSMutableArray arrayWithCapacity:results.m_results.size()]; MWMMapSearchResult * result = [[MWMMapSearchResult alloc] initWithSearchResult:res];
for (auto const & res : results.m_results) [resultsArray addObject:result];
{
MWMMapSearchResult *result = [[MWMMapSearchResult alloc] initWithSearchResult:res];
[resultsArray addObject:result];
}
completion(resultsArray, results.m_endMarker);
} }
}; completion(resultsArray, results.m_endMarker);
}};
GetFramework().GetSearchAPI().SearchInDownloader(std::move(params)); GetFramework().GetSearchAPI().SearchInDownloader(std::move(params));
} }
+ (BOOL)canEditMapAtViewportCenter { + (BOOL)canEditMapAtViewportCenter
auto const &f = GetFramework(); {
auto const & f = GetFramework();
return f.CanEditMapForPosition(f.GetViewportCenter()); return f.CanEditMapForPosition(f.GetViewportCenter());
} }
+ (void)showOnMap:(MWMMarkGroupID)categoryId { + (void)showOnMap:(MWMMarkGroupID)categoryId
{
GetFramework().ShowBookmarkCategory(categoryId); GetFramework().ShowBookmarkCategory(categoryId);
} }
+ (void)showBookmark:(MWMMarkID)bookmarkId { + (void)showBookmark:(MWMMarkID)bookmarkId
{
GetFramework().ShowBookmark(bookmarkId); GetFramework().ShowBookmark(bookmarkId);
} }
+ (void)showTrack:(MWMTrackID)trackId { + (void)showTrack:(MWMTrackID)trackId
{
GetFramework().ShowTrack(trackId); GetFramework().ShowTrack(trackId);
} }
+ (void)saveRouteAsTrack { + (void)saveRouteAsTrack
{
GetFramework().SaveRoute(); GetFramework().SaveRoute();
} }
+ (void)updatePlacePageData { + (void)updatePlacePageData
{
GetFramework().UpdatePlacePageInfoForCurrentSelection(); GetFramework().UpdatePlacePageInfoForCurrentSelection();
} }
+ (void)updateAfterDeleteBookmark { + (void)updateAfterDeleteBookmark
{
auto & frm = GetFramework(); auto & frm = GetFramework();
auto buildInfo = frm.GetCurrentPlacePageInfo().GetBuildInfo(); auto buildInfo = frm.GetCurrentPlacePageInfo().GetBuildInfo();
buildInfo.m_match = place_page::BuildInfo::Match::FeatureOnly; buildInfo.m_match = place_page::BuildInfo::Match::FeatureOnly;
@@ -198,45 +209,54 @@
frm.UpdatePlacePageInfoForCurrentSelection(buildInfo); frm.UpdatePlacePageInfoForCurrentSelection(buildInfo);
} }
+ (int)currentZoomLevel { + (int)currentZoomLevel
{
return GetFramework().GetDrawScale(); return GetFramework().GetDrawScale();
} }
// MARK: - TrackRecorder // MARK: - TrackRecorder
+ (void)startTrackRecording { + (void)startTrackRecording
{
GetFramework().StartTrackRecording(); GetFramework().StartTrackRecording();
} }
+ (void)setTrackRecordingUpdateHandler:(TrackRecordingUpdatedHandler _Nullable)trackRecordingDidUpdate { + (void)setTrackRecordingUpdateHandler:(TrackRecordingUpdatedHandler _Nullable)trackRecordingDidUpdate
{
if (!trackRecordingDidUpdate) if (!trackRecordingDidUpdate)
{ {
GetFramework().SetTrackRecordingUpdateHandler(nullptr); GetFramework().SetTrackRecordingUpdateHandler(nullptr);
return; return;
} }
GetFramework().SetTrackRecordingUpdateHandler([trackRecordingDidUpdate](TrackStatistics const & statistics) { GetFramework().SetTrackRecordingUpdateHandler([trackRecordingDidUpdate](TrackStatistics const & statistics)
{
TrackInfo * info = [[TrackInfo alloc] initWithTrackStatistics:statistics]; TrackInfo * info = [[TrackInfo alloc] initWithTrackStatistics:statistics];
trackRecordingDidUpdate(info); trackRecordingDidUpdate(info);
}); });
} }
+ (void)stopTrackRecording { + (void)stopTrackRecording
{
GetFramework().StopTrackRecording(); GetFramework().StopTrackRecording();
} }
+ (void)saveTrackRecordingWithName:(nonnull NSString *)name { + (void)saveTrackRecordingWithName:(nonnull NSString *)name
{
GetFramework().SaveTrackRecordingWithName(name.UTF8String); GetFramework().SaveTrackRecordingWithName(name.UTF8String);
} }
+ (BOOL)isTrackRecordingEnabled { + (BOOL)isTrackRecordingEnabled
{
return GetFramework().IsTrackRecordingEnabled(); return GetFramework().IsTrackRecordingEnabled();
} }
+ (BOOL)isTrackRecordingEmpty { + (BOOL)isTrackRecordingEmpty
{
return GetFramework().IsTrackRecordingEmpty(); return GetFramework().IsTrackRecordingEmpty();
} }
+ (ElevationProfileData * _Nonnull)trackRecordingElevationInfo { + (ElevationProfileData * _Nonnull)trackRecordingElevationInfo
{
return [[ElevationProfileData alloc] initWithElevationInfo:GetFramework().GetTrackRecordingElevationInfo()]; return [[ElevationProfileData alloc] initWithElevationInfo:GetFramework().GetTrackRecordingElevationInfo()];
} }

View File

@@ -6,11 +6,12 @@
@interface Logger () @interface Logger ()
@property (nullable, nonatomic) NSFileHandle * fileHandle; @property(nullable, nonatomic) NSFileHandle * fileHandle;
@property (nonnull, nonatomic) os_log_t osLogger; @property(nonnull, nonatomic) os_log_t osLogger;
/// This property is introduced to avoid the CoreApi => Maps target dependency and stores the MWMSettings.isFileLoggingEnabled value. /// This property is introduced to avoid the CoreApi => Maps target dependency and stores the
@property (class, nonatomic) BOOL fileLoggingEnabled; /// MWMSettings.isFileLoggingEnabled value.
@property (class, readonly, nonatomic) dispatch_queue_t fileLoggingQueue; @property(class, nonatomic) BOOL fileLoggingEnabled;
@property(class, readonly, nonatomic) dispatch_queue_t fileLoggingQueue;
+ (Logger *)logger; + (Logger *)logger;
+ (void)enableFileLogging; + (void)enableFileLogging;
@@ -28,10 +29,10 @@ NSString * const kLoggerSubsystem = [[NSBundle mainBundle] bundleIdentifier];
NSString * const kLoggerCategory = @"OM"; NSString * const kLoggerCategory = @"OM";
NSString * const kLogFileName = @"log.txt"; NSString * const kLogFileName = @"log.txt";
NSString * const kZipLogFileExtension = @"zip"; NSString * const kZipLogFileExtension = @"zip";
NSString * const kLogFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] NSString * const kLogFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
stringByAppendingPathComponent:kLogFileName]; firstObject] stringByAppendingPathComponent:kLogFileName];
// TODO: (KK) Review and change this limit after some testing. // TODO: (KK) Review and change this limit after some testing.
NSUInteger const kMaxLogFileSize = 1024 * 1024 * 100; // 100 MB; NSUInteger const kMaxLogFileSize = 1024 * 1024 * 100; // 100 MB;
@implementation Logger @implementation Logger
@@ -39,84 +40,102 @@ static BOOL _fileLoggingEnabled = NO;
+ (void)initialize + (void)initialize
{ {
if (self == [Logger class]) { if (self == [Logger class])
{
SetLogMessageFn(&LogMessage); SetLogMessageFn(&LogMessage);
SetAssertFunction(&AssertMessage); SetAssertFunction(&AssertMessage);
} }
} }
+ (Logger *)logger { + (Logger *)logger
{
static Logger * logger = nil; static Logger * logger = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ logger = [[self alloc] init]; });
logger = [[self alloc] init];
});
return logger; return logger;
} }
+ (dispatch_queue_t)fileLoggingQueue { + (dispatch_queue_t)fileLoggingQueue
{
static dispatch_queue_t fileLoggingQueue = nil; static dispatch_queue_t fileLoggingQueue = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0); dispatch_queue_attr_t attributes =
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
fileLoggingQueue = dispatch_queue_create("app.comaps.fileLoggingQueue", attributes); fileLoggingQueue = dispatch_queue_create("app.comaps.fileLoggingQueue", attributes);
}); });
return fileLoggingQueue; return fileLoggingQueue;
} }
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
_osLogger = os_log_create(kLoggerSubsystem.UTF8String, kLoggerCategory.UTF8String); _osLogger = os_log_create(kLoggerSubsystem.UTF8String, kLoggerCategory.UTF8String);
}
return self; return self;
} }
// MARK: - Public // MARK: - Public
+ (void)setFileLoggingEnabled:(BOOL)fileLoggingEnabled { + (void)setFileLoggingEnabled:(BOOL)fileLoggingEnabled
{
fileLoggingEnabled ? [self enableFileLogging] : [self disableFileLogging]; fileLoggingEnabled ? [self enableFileLogging] : [self disableFileLogging];
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
LOG_SHORT(LINFO, ("Local time:", NSDate.date.description.UTF8String, ", Time Zone:", NSTimeZone.defaultTimeZone.abbreviation.UTF8String)); LOG_SHORT(LINFO, ("Local time:", NSDate.date.description.UTF8String,
", Time Zone:", NSTimeZone.defaultTimeZone.abbreviation.UTF8String));
}); });
LOG(LINFO, ("File logging is enabled:", _fileLoggingEnabled ? "YES" : "NO")); LOG(LINFO, ("File logging is enabled:", _fileLoggingEnabled ? "YES" : "NO"));
} }
+ (BOOL)fileLoggingEnabled { + (BOOL)fileLoggingEnabled
{
return _fileLoggingEnabled; return _fileLoggingEnabled;
} }
+ (void)log:(LogLevel)level message:(NSString *)message { + (void)log:(LogLevel)level message:(NSString *)message
{
LOG_SHORT([self baseLevel:level], (message.UTF8String)); LOG_SHORT([self baseLevel:level], (message.UTF8String));
} }
+ (BOOL)canLog:(LogLevel)level { + (BOOL)canLog:(LogLevel)level
{
return [Logger baseLevel:level] >= base::g_LogLevel; return [Logger baseLevel:level] >= base::g_LogLevel;
} }
+ (nullable NSURL *)getLogFileURL { + (nullable NSURL *)getLogFileURL
if ([self fileLoggingEnabled]) { {
if (![NSFileManager.defaultManager fileExistsAtPath:kLogFilePath]) { if ([self fileLoggingEnabled])
{
if (![NSFileManager.defaultManager fileExistsAtPath:kLogFilePath])
{
LOG(LERROR, ("Log file doesn't exist while file logging is enabled:", kLogFilePath.UTF8String)); LOG(LERROR, ("Log file doesn't exist while file logging is enabled:", kLogFilePath.UTF8String));
return nil; return nil;
} }
return [self getZippedLogFile:kLogFilePath]; return [self getZippedLogFile:kLogFilePath];
} else { }
else
{
// Fetch logs from the OSLog store. // Fetch logs from the OSLog store.
if (@available(iOS 15.0, *)) { if (@available(iOS 15.0, *))
{
NSError * error; NSError * error;
OSLogStore * store = [OSLogStore storeWithScope:OSLogStoreCurrentProcessIdentifier error:&error]; OSLogStore * store = [OSLogStore storeWithScope:OSLogStoreCurrentProcessIdentifier error:&error];
if (error) { if (error)
{
LOG(LERROR, (error.localizedDescription.UTF8String)); LOG(LERROR, (error.localizedDescription.UTF8String));
return nil; return nil;
} }
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"subsystem == %@", kLoggerSubsystem]; NSPredicate * predicate = [NSPredicate predicateWithFormat:@"subsystem == %@", kLoggerSubsystem];
OSLogEnumerator * enumerator = [store entriesEnumeratorWithOptions:{} position:nil predicate:predicate error:&error]; OSLogEnumerator * enumerator = [store entriesEnumeratorWithOptions:{}
position:nil
predicate:predicate
error:&error];
if (error) { if (error)
{
LOG(LERROR, (error.localizedDescription.UTF8String)); LOG(LERROR, (error.localizedDescription.UTF8String));
return nil; return nil;
} }
@@ -125,27 +144,35 @@ static BOOL _fileLoggingEnabled = NO;
NSString * kNewLineStr = @"\n"; NSString * kNewLineStr = @"\n";
id object; id object;
while (object = [enumerator nextObject]) { while (object = [enumerator nextObject])
if ([object isMemberOfClass:[OSLogEntryLog class]]) { {
if ([object isMemberOfClass:[OSLogEntryLog class]])
{
[logString appendString:[object composedMessage]]; [logString appendString:[object composedMessage]];
[logString appendString:kNewLineStr]; [logString appendString:kNewLineStr];
} }
} }
if (logString.length == 0) { if (logString.length == 0)
{
LOG(LINFO, ("OSLog entry is empty.")); LOG(LINFO, ("OSLog entry is empty."));
return nil; return nil;
} }
[NSFileManager.defaultManager createFileAtPath:kLogFilePath contents:[logString dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; [NSFileManager.defaultManager createFileAtPath:kLogFilePath
contents:[logString dataUsingEncoding:NSUTF8StringEncoding]
attributes:nil];
return [self getZippedLogFile:kLogFilePath]; return [self getZippedLogFile:kLogFilePath];
} else { }
else
{
return nil; return nil;
} }
} }
} }
+ (uint64_t)getLogFileSize { + (uint64_t)getLogFileSize
{
Logger * logger = [self logger]; Logger * logger = [self logger];
return logger.fileHandle != nil ? [logger.fileHandle offsetInFile] : 0; return logger.fileHandle != nil ? [logger.fileHandle offsetInFile] : 0;
} }
@@ -166,7 +193,8 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
// MARK: - Private // MARK: - Private
+ (void)enableFileLogging { + (void)enableFileLogging
{
Logger * logger = [self logger]; Logger * logger = [self logger];
NSFileManager * fileManager = [NSFileManager defaultManager]; NSFileManager * fileManager = [NSFileManager defaultManager];
@@ -174,7 +202,8 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
if (![fileManager fileExistsAtPath:kLogFilePath]) if (![fileManager fileExistsAtPath:kLogFilePath])
[fileManager createFileAtPath:kLogFilePath contents:nil attributes:nil]; [fileManager createFileAtPath:kLogFilePath contents:nil attributes:nil];
NSFileHandle * fileHandle = [NSFileHandle fileHandleForWritingAtPath:kLogFilePath]; NSFileHandle * fileHandle = [NSFileHandle fileHandleForWritingAtPath:kLogFilePath];
if (fileHandle == nil) { if (fileHandle == nil)
{
LOG(LERROR, ("Failed to open log file for writing", kLogFilePath.UTF8String)); LOG(LERROR, ("Failed to open log file for writing", kLogFilePath.UTF8String));
[self disableFileLogging]; [self disableFileLogging];
return; return;
@@ -188,7 +217,8 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
_fileLoggingEnabled = YES; _fileLoggingEnabled = YES;
} }
+ (void)disableFileLogging { + (void)disableFileLogging
{
Logger * logger = [self logger]; Logger * logger = [self logger];
[logger.fileHandle closeFile]; [logger.fileHandle closeFile];
@@ -198,7 +228,8 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
_fileLoggingEnabled = NO; _fileLoggingEnabled = NO;
} }
+ (void)logMessageWithLevel:(base::LogLevel)level src:(base::SrcPoint const &)src message:(std::string const &)message { + (void)logMessageWithLevel:(base::LogLevel)level src:(base::SrcPoint const &)src message:(std::string const &)message
{
// Build the log message string. // Build the log message string.
auto & logHelper = base::LogHelper::Instance(); auto & logHelper = base::LogHelper::Instance();
std::ostringstream output; std::ostringstream output;
@@ -217,27 +248,35 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
[self tryWriteToFile:logString]; [self tryWriteToFile:logString];
} }
+ (void)tryWriteToFile:(std::string const &)logString { + (void)tryWriteToFile:(std::string const &)logString
{
NSFileHandle * fileHandle = [self logger].fileHandle; NSFileHandle * fileHandle = [self logger].fileHandle;
if (fileHandle != nil) { if (fileHandle != nil)
{
[fileHandle seekToEndOfFile]; [fileHandle seekToEndOfFile];
[fileHandle writeData:[NSData dataWithBytes:logString.c_str() length:logString.length()]]; [fileHandle writeData:[NSData dataWithBytes:logString.c_str() length:logString.length()]];
} }
} }
+ (NSURL *)getZippedLogFile:(NSString *)logFilePath { + (NSURL *)getZippedLogFile:(NSString *)logFilePath
NSString * zipFileName = [[logFilePath.lastPathComponent stringByDeletingPathExtension] stringByAppendingPathExtension:kZipLogFileExtension]; {
NSString * zipFilePath = [[NSFileManager.defaultManager temporaryDirectory] URLByAppendingPathComponent:zipFileName].path; NSString * zipFileName = [[logFilePath.lastPathComponent stringByDeletingPathExtension]
stringByAppendingPathExtension:kZipLogFileExtension];
NSString * zipFilePath =
[[NSFileManager.defaultManager temporaryDirectory] URLByAppendingPathComponent:zipFileName].path;
auto const success = CreateZipFromFiles({logFilePath.UTF8String}, zipFilePath.UTF8String); auto const success = CreateZipFromFiles({logFilePath.UTF8String}, zipFilePath.UTF8String);
if (!success) { if (!success)
{
LOG(LERROR, ("Failed to zip log file:", kLogFilePath.UTF8String, ". The original file will be returned.")); LOG(LERROR, ("Failed to zip log file:", kLogFilePath.UTF8String, ". The original file will be returned."));
return [NSURL fileURLWithPath:logFilePath]; return [NSURL fileURLWithPath:logFilePath];
} }
return [NSURL fileURLWithPath:zipFilePath]; return [NSURL fileURLWithPath:zipFilePath];
} }
+ (void)removeFileAtPath:(NSString *)filePath { + (void)removeFileAtPath:(NSString *)filePath
if ([NSFileManager.defaultManager fileExistsAtPath:filePath]) { {
if ([NSFileManager.defaultManager fileExistsAtPath:filePath])
{
NSError * error; NSError * error;
[NSFileManager.defaultManager removeItemAtPath:filePath error:&error]; [NSFileManager.defaultManager removeItemAtPath:filePath error:&error];
if (error) if (error)
@@ -245,13 +284,15 @@ bool AssertMessage(base::SrcPoint const & src, std::string const & message)
} }
} }
+ (base::LogLevel)baseLevel:(LogLevel)level { + (base::LogLevel)baseLevel:(LogLevel)level
switch (level) { {
case LogLevelDebug: return LDEBUG; switch (level)
case LogLevelInfo: return LINFO; {
case LogLevelWarning: return LWARNING; case LogLevelDebug: return LDEBUG;
case LogLevelError: return LERROR; case LogLevelInfo: return LINFO;
case LogLevelCritical: return LCRITICAL; case LogLevelWarning: return LWARNING;
case LogLevelError: return LERROR;
case LogLevelCritical: return LCRITICAL;
} }
} }

View File

@@ -5,68 +5,57 @@
@implementation MWMNetworkPolicy @implementation MWMNetworkPolicy
+ (MWMNetworkPolicy *)sharedPolicy { + (MWMNetworkPolicy *)sharedPolicy
static MWMNetworkPolicy *policy; {
static MWMNetworkPolicy * policy;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ policy = [[MWMNetworkPolicy alloc] init]; });
policy = [[MWMNetworkPolicy alloc] init];
});
return policy; return policy;
} }
- (MWMNetworkPolicyPermission)permission { - (MWMNetworkPolicyPermission)permission
switch (network_policy::GetStage()) { {
case network_policy::Ask: switch (network_policy::GetStage())
return MWMNetworkPolicyPermissionAsk; {
case network_policy::Always: case network_policy::Ask: return MWMNetworkPolicyPermissionAsk;
return MWMNetworkPolicyPermissionAlways; case network_policy::Always: return MWMNetworkPolicyPermissionAlways;
case network_policy::Never: case network_policy::Never: return MWMNetworkPolicyPermissionNever;
return MWMNetworkPolicyPermissionNever; case network_policy::Today: return MWMNetworkPolicyPermissionToday;
case network_policy::Today: case network_policy::NotToday: return MWMNetworkPolicyPermissionNotToday;
return MWMNetworkPolicyPermissionToday;
case network_policy::NotToday:
return MWMNetworkPolicyPermissionNotToday;
} }
} }
- (void)setPermission:(MWMNetworkPolicyPermission)permission { - (void)setPermission:(MWMNetworkPolicyPermission)permission
{
network_policy::Stage stage; network_policy::Stage stage;
switch (permission) { switch (permission)
case MWMNetworkPolicyPermissionAsk: {
stage = network_policy::Stage::Ask; case MWMNetworkPolicyPermissionAsk: stage = network_policy::Stage::Ask; break;
break; case MWMNetworkPolicyPermissionAlways: stage = network_policy::Stage::Always; break;
case MWMNetworkPolicyPermissionAlways: case MWMNetworkPolicyPermissionNever: stage = network_policy::Stage::Never; break;
stage = network_policy::Stage::Always; case MWMNetworkPolicyPermissionToday: stage = network_policy::Stage::Today; break;
break; case MWMNetworkPolicyPermissionNotToday: stage = network_policy::Stage::NotToday; break;
case MWMNetworkPolicyPermissionNever:
stage = network_policy::Stage::Never;
break;
case MWMNetworkPolicyPermissionToday:
stage = network_policy::Stage::Today;
break;
case MWMNetworkPolicyPermissionNotToday:
stage = network_policy::Stage::NotToday;
break;
} }
network_policy::SetStage(stage); network_policy::SetStage(stage);
} }
- (NSDate *)permissionExpirationDate { - (NSDate *)permissionExpirationDate
{
return network_policy::GetPolicyDate(); return network_policy::GetPolicyDate();
} }
- (BOOL)canUseNetwork { - (BOOL)canUseNetwork
{
return network_policy::CanUseNetwork(); return network_policy::CanUseNetwork();
} }
- (MWMConnectionType)connectionType { - (MWMConnectionType)connectionType
switch (GetPlatform().ConnectionStatus()) { {
case Platform::EConnectionType::CONNECTION_NONE: switch (GetPlatform().ConnectionStatus())
return MWMConnectionTypeNone; {
case Platform::EConnectionType::CONNECTION_WIFI: case Platform::EConnectionType::CONNECTION_NONE: return MWMConnectionTypeNone;
return MWMConnectionTypeWifi; case Platform::EConnectionType::CONNECTION_WIFI: return MWMConnectionTypeWifi;
case Platform::EConnectionType::CONNECTION_WWAN: case Platform::EConnectionType::CONNECTION_WWAN: return MWMConnectionTypeCellular;
return MWMConnectionTypeCellular;
} }
} }

View File

@@ -10,8 +10,7 @@ namespace
{ {
NSString * stringFromTimeSpan(Timespan const & timeSpan) NSString * stringFromTimeSpan(Timespan const & timeSpan)
{ {
return [NSString stringWithFormat:@"%@-%@", stringFromTime(timeSpan.GetStart()), return [NSString stringWithFormat:@"%@-%@", stringFromTime(timeSpan.GetStart()), stringFromTime(timeSpan.GetEnd())];
stringFromTime(timeSpan.GetEnd())];
} }
NSString * breaksFromClosedTime(TTimespans const & closedTimes, id<IOpeningHoursLocalization> localization) NSString * breaksFromClosedTime(TTimespans const & closedTimes, id<IOpeningHoursLocalization> localization)
@@ -22,8 +21,8 @@ NSString * breaksFromClosedTime(TTimespans const & closedTimes, id<IOpeningHours
{ {
if (i) if (i)
[breaks appendString:@"\n"]; [breaks appendString:@"\n"];
[breaks appendString:[NSString stringWithFormat:@"%@ %@", localization.breakString, [breaks appendString:[NSString
stringFromTimeSpan(closedTimes[i])]]; stringWithFormat:@"%@ %@", localization.breakString, stringFromTimeSpan(closedTimes[i])]];
} }
return [breaks copy]; return [breaks copy];
} }
@@ -81,9 +80,10 @@ void addUnhandledDays(ui::OpeningDays const & days, std::vector<Day> & allDays)
} // namespace } // namespace
namespace osmoh { namespace osmoh
{
std::pair<std::vector<osmoh::Day>, bool> processRawString(NSString *str, id<IOpeningHoursLocalization> localization) std::pair<std::vector<osmoh::Day>, bool> processRawString(NSString * str, id<IOpeningHoursLocalization> localization)
{ {
osmoh::OpeningHours oh(str.UTF8String); osmoh::OpeningHours oh(str.UTF8String);
bool const isClosed = oh.IsClosed(time(nullptr)); bool const isClosed = oh.IsClosed(time(nullptr));
@@ -98,8 +98,7 @@ std::pair<std::vector<osmoh::Day>, bool> processRawString(NSString *str, id<IOpe
cal.locale = NSLocale.currentLocale; cal.locale = NSLocale.currentLocale;
auto const timeTablesSize = timeTableSet.Size(); auto const timeTablesSize = timeTableSet.Size();
auto const today = auto const today = static_cast<Weekday>([cal components:NSCalendarUnitWeekday fromDate:[NSDate date]].weekday);
static_cast<Weekday>([cal components:NSCalendarUnitWeekday fromDate:[NSDate date]].weekday);
auto const unhandledDays = timeTableSet.GetUnhandledDays(); auto const unhandledDays = timeTableSet.GetUnhandledDays();
/// Schedule contains more than one rule for all days or unhandled days. /// Schedule contains more than one rule for all days or unhandled days.
@@ -126,4 +125,4 @@ std::pair<std::vector<osmoh::Day>, bool> processRawString(NSString *str, id<IOpe
return {std::move(days), isClosed}; return {std::move(days), isClosed};
} }
} // namespace osmoh } // namespace osmoh

View File

@@ -33,16 +33,14 @@ NSString * stringFromOpeningDays(editor::ui::OpeningDays const & openingDays)
NSMutableArray<NSString *> * spanNames = [NSMutableArray arrayWithCapacity:2]; NSMutableArray<NSString *> * spanNames = [NSMutableArray arrayWithCapacity:2];
NSMutableArray<NSString *> * spans = [NSMutableArray array]; NSMutableArray<NSString *> * spans = [NSMutableArray array];
auto weekdayFromDay = ^(NSUInteger day) auto weekdayFromDay = ^(NSUInteger day) {
{
NSUInteger idx = day + 1; NSUInteger idx = day + 1;
if (idx > static_cast<NSUInteger>(osmoh::Weekday::Saturday)) if (idx > static_cast<NSUInteger>(osmoh::Weekday::Saturday))
idx -= static_cast<NSUInteger>(osmoh::Weekday::Saturday); idx -= static_cast<NSUInteger>(osmoh::Weekday::Saturday);
return static_cast<osmoh::Weekday>(idx); return static_cast<osmoh::Weekday>(idx);
}; };
auto joinSpanNames = ^ auto joinSpanNames = ^{
{
NSUInteger const spanNamesCount = spanNames.count; NSUInteger const spanNamesCount = spanNames.count;
if (spanNamesCount == 0) if (spanNamesCount == 0)
return; return;

View File

@@ -1,13 +1,13 @@
#import "OpeningHours.h" #import "OpeningHours.h"
#import "MWMOpeningHours.h"
#include "3party/opening_hours/opening_hours.hpp" #include "3party/opening_hours/opening_hours.hpp"
#import "MWMOpeningHours.h"
@interface WorkingDay () @interface WorkingDay ()
@property(nonatomic, copy) NSString *workingDays; @property(nonatomic, copy) NSString * workingDays;
@property(nonatomic, copy) NSString *workingTimes; @property(nonatomic, copy) NSString * workingTimes;
@property(nonatomic, copy) NSString *breaks; @property(nonatomic, copy) NSString * breaks;
@property(nonatomic) BOOL isOpen; @property(nonatomic) BOOL isOpen;
@end @end
@@ -18,30 +18,32 @@
@interface OpeningHours () @interface OpeningHours ()
@property(nonatomic, strong) NSArray<WorkingDay *> *days; @property(nonatomic, strong) NSArray<WorkingDay *> * days;
@property(nonatomic) BOOL isClosedNow; @property(nonatomic) BOOL isClosedNow;
@end @end
@implementation OpeningHours @implementation OpeningHours
- (instancetype)initWithRawString:(NSString *)rawString localization:(id<IOpeningHoursLocalization>)localization { - (instancetype)initWithRawString:(NSString *)rawString localization:(id<IOpeningHoursLocalization>)localization
{
self = [super init]; self = [super init];
if (self) { if (self)
{
auto const [days, isClosed] = osmoh::processRawString(rawString, localization); auto const [days, isClosed] = osmoh::processRawString(rawString, localization);
_isClosedNow = isClosed; _isClosedNow = isClosed;
NSMutableArray *array = [NSMutableArray arrayWithCapacity:days.size()]; NSMutableArray * array = [NSMutableArray arrayWithCapacity:days.size()];
for (auto const & day : days) { for (auto const & day : days)
WorkingDay *wd = [[WorkingDay alloc] init]; {
WorkingDay * wd = [[WorkingDay alloc] init];
wd.isOpen = day.m_isOpen; wd.isOpen = day.m_isOpen;
wd.workingDays = day.m_workingDays; wd.workingDays = day.m_workingDays;
wd.workingTimes = day.m_isOpen ? day.m_workingTimes : localization.closedString; wd.workingTimes = day.m_isOpen ? day.m_workingTimes : localization.closedString;
wd.breaks = day.m_breaks; wd.breaks = day.m_breaks;
[array addObject:wd]; [array addObject:wd];
} }
if (array.count == 0) { if (array.count == 0)
return nil; return nil;
}
_days = [array copy]; _days = [array copy];
} }
return self; return self;

View File

@@ -1,5 +1,5 @@
#import "PlacePageBookmarkData+Core.h"
#import "MWMBookmarkColor+Core.h" #import "MWMBookmarkColor+Core.h"
#import "PlacePageBookmarkData+Core.h"
@implementation PlacePageBookmarkData @implementation PlacePageBookmarkData
@@ -7,13 +7,16 @@
@implementation PlacePageBookmarkData (Core) @implementation PlacePageBookmarkData (Core)
- (instancetype)initWithRawData:(place_page::Info const &)rawData { - (instancetype)initWithRawData:(place_page::Info const &)rawData
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_bookmarkId = rawData.GetBookmarkId(); _bookmarkId = rawData.GetBookmarkId();
_bookmarkGroupId = rawData.GetBookmarkCategoryId(); _bookmarkGroupId = rawData.GetBookmarkCategoryId();
_externalTitle = rawData.GetSecondaryTitle().empty() ? nil : @(rawData.GetSecondaryTitle().c_str()); _externalTitle = rawData.GetSecondaryTitle().empty() ? nil : @(rawData.GetSecondaryTitle().c_str());
_bookmarkDescription = rawData.IsBookmark() ? @(GetPreferredBookmarkStr(rawData.GetBookmarkData().m_description).c_str()) : nil; _bookmarkDescription =
rawData.IsBookmark() ? @(GetPreferredBookmarkStr(rawData.GetBookmarkData().m_description).c_str()) : nil;
_bookmarkCategory = rawData.IsBookmark() ? @(rawData.GetBookmarkCategoryName().c_str()) : nil; _bookmarkCategory = rawData.IsBookmark() ? @(rawData.GetBookmarkCategoryName().c_str()) : nil;
_isHtmlDescription = strings::IsHTML(GetPreferredBookmarkStr(rawData.GetBookmarkData().m_description)); _isHtmlDescription = strings::IsHTML(GetPreferredBookmarkStr(rawData.GetBookmarkData().m_description));
_color = convertKmlColor(rawData.GetBookmarkData().m_color.m_predefinedColor); _color = convertKmlColor(rawData.GetBookmarkData().m_color.m_predefinedColor);

View File

@@ -6,9 +6,11 @@
@implementation PlacePageButtonsData (Core) @implementation PlacePageButtonsData (Core)
- (instancetype)initWithRawData:(place_page::Info const &)rawData { - (instancetype)initWithRawData:(place_page::Info const &)rawData
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_showAddPlace = rawData.ShouldShowAddPlace() || rawData.ShouldShowAddBusiness(); _showAddPlace = rawData.ShouldShowAddPlace() || rawData.ShouldShowAddBusiness();
_showEditPlace = rawData.ShouldShowEditPlace(); _showEditPlace = rawData.ShouldShowEditPlace();
_enableAddPlace = rawData.ShouldEnableAddPlace(); _enableAddPlace = rawData.ShouldEnableAddPlace();

View File

@@ -7,8 +7,8 @@
#include "platform/localization.hpp" #include "platform/localization.hpp"
#include "indexer/validate_and_format_contacts.hpp"
#include "indexer/feature_meta.hpp" #include "indexer/feature_meta.hpp"
#include "indexer/validate_and_format_contacts.hpp"
#include "map/place_page_info.hpp" #include "map/place_page_info.hpp"
@@ -16,7 +16,8 @@ using namespace place_page;
using namespace osm; using namespace osm;
/// Get localized metadata value string when string format is "type.feature.value". /// Get localized metadata value string when string format is "type.feature.value".
NSString * GetLocalizedMetadataValueString(MapObject::MetadataID metaID, std::string const & value) { NSString * GetLocalizedMetadataValueString(MapObject::MetadataID metaID, std::string const & value)
{
return ToNSString(platform::GetLocalizedTypeName(feature::ToString(metaID) + "." + value)); return ToNSString(platform::GetLocalizedTypeName(feature::ToString(metaID) + "." + value));
} }
@@ -26,7 +27,8 @@ NSString * GetLocalizedMetadataValueString(MapObject::MetadataID metaID, std::st
@implementation PlacePageInfoData (Core) @implementation PlacePageInfoData (Core)
- (instancetype)initWithRawData:(Info const &)rawData ohLocalization:(id<IOpeningHoursLocalization>)localization { - (instancetype)initWithRawData:(Info const &)rawData ohLocalization:(id<IOpeningHoursLocalization>)localization
{
self = [super init]; self = [super init];
if (self) if (self)
{ {
@@ -40,75 +42,82 @@ NSString * GetLocalizedMetadataValueString(MapObject::MetadataID metaID, std::st
{ {
switch (metaID) switch (metaID)
{ {
case MetadataID::FMD_OPEN_HOURS: case MetadataID::FMD_OPEN_HOURS:
_openingHoursString = ToNSString(value); _openingHoursString = ToNSString(value);
_openingHours = [[OpeningHours alloc] initWithRawString:_openingHoursString _openingHours = [[OpeningHours alloc] initWithRawString:_openingHoursString localization:localization];
localization:localization]; break;
break; case MetadataID::FMD_PHONE_NUMBER:
case MetadataID::FMD_PHONE_NUMBER: {
{ NSArray<NSString *> * phones = [ToNSString(value) componentsSeparatedByString:@";"];
NSArray<NSString *> *phones = [ToNSString(value) componentsSeparatedByString:@";"]; NSMutableArray<PlacePagePhone *> * placePhones = [NSMutableArray new];
NSMutableArray<PlacePagePhone *> *placePhones = [NSMutableArray new]; [phones enumerateObjectsUsingBlock:^(NSString * _Nonnull phone, NSUInteger idx, BOOL * _Nonnull stop) {
[phones enumerateObjectsUsingBlock:^(NSString * _Nonnull phone, NSUInteger idx, BOOL * _Nonnull stop) { NSString * filteredDigits =
NSString *filteredDigits = [[phone componentsSeparatedByCharactersInSet: [[phone componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
componentsJoinedByString:@""]; NSString * resultNumber =
NSString *resultNumber = [phone hasPrefix:@"+"] ? [NSString stringWithFormat:@"+%@", filteredDigits] : filteredDigits; [phone hasPrefix:@"+"] ? [NSString stringWithFormat:@"+%@", filteredDigits] : filteredDigits;
NSURL *phoneUrl = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", resultNumber]]; NSURL * phoneUrl = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", resultNumber]];
[placePhones addObject:[PlacePagePhone placePagePhoneWithPhone:phone andURL:phoneUrl]]; [placePhones addObject:[PlacePagePhone placePagePhoneWithPhone:phone andURL:phoneUrl]];
}]; }];
_phones = [placePhones copy]; _phones = [placePhones copy];
break; break;
} }
case MetadataID::FMD_WEBSITE: _website = ToNSString(value); break; case MetadataID::FMD_WEBSITE: _website = ToNSString(value); break;
case MetadataID::FMD_WIKIPEDIA: _wikipedia = ToNSString(value); break; case MetadataID::FMD_WIKIPEDIA: _wikipedia = ToNSString(value); break;
case MetadataID::FMD_WIKIMEDIA_COMMONS: _wikimediaCommons = ToNSString(value); break; case MetadataID::FMD_WIKIMEDIA_COMMONS: _wikimediaCommons = ToNSString(value); break;
case MetadataID::FMD_EMAIL: case MetadataID::FMD_EMAIL:
_email = ToNSString(value); _email = ToNSString(value);
_emailUrl = [NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@", _email]]; _emailUrl = [NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@", _email]];
break; break;
case MetadataID::FMD_CONTACT_FEDIVERSE: _fediverse = ToNSString(value); break; case MetadataID::FMD_CONTACT_FEDIVERSE: _fediverse = ToNSString(value); break;
case MetadataID::FMD_CONTACT_FACEBOOK: _facebook = ToNSString(value); break; case MetadataID::FMD_CONTACT_FACEBOOK: _facebook = ToNSString(value); break;
case MetadataID::FMD_CONTACT_INSTAGRAM: _instagram = ToNSString(value); break; case MetadataID::FMD_CONTACT_INSTAGRAM: _instagram = ToNSString(value); break;
case MetadataID::FMD_CONTACT_TWITTER: _twitter = ToNSString(value); break; case MetadataID::FMD_CONTACT_TWITTER: _twitter = ToNSString(value); break;
case MetadataID::FMD_CONTACT_VK: _vk = ToNSString(value); break; case MetadataID::FMD_CONTACT_VK: _vk = ToNSString(value); break;
case MetadataID::FMD_CONTACT_LINE: _line = ToNSString(value); break; case MetadataID::FMD_CONTACT_LINE: _line = ToNSString(value); break;
case MetadataID::FMD_CONTACT_BLUESKY: _bluesky = ToNSString(value); break; case MetadataID::FMD_CONTACT_BLUESKY: _bluesky = ToNSString(value); break;
case MetadataID::FMD_PANORAMAX: _panoramax = ToNSString(value); break; case MetadataID::FMD_PANORAMAX: _panoramax = ToNSString(value); break;
case MetadataID::FMD_OPERATOR: _ppOperator = [NSString stringWithFormat:NSLocalizedString(@"operator", nil), ToNSString(value)]; break; case MetadataID::FMD_OPERATOR:
case MetadataID::FMD_INTERNET: _ppOperator = [NSString stringWithFormat:NSLocalizedString(@"operator", nil), ToNSString(value)];
_wifiAvailable = (rawData.GetInternet() == feature::Internet::No) break;
? NSLocalizedString(@"no_available", nil) : NSLocalizedString(@"yes_available", nil); case MetadataID::FMD_INTERNET:
break; _wifiAvailable = (rawData.GetInternet() == feature::Internet::No) ? NSLocalizedString(@"no_available", nil)
case MetadataID::FMD_LEVEL: _level = ToNSString(value); break; : NSLocalizedString(@"yes_available", nil);
case MetadataID::FMD_CAPACITY: _capacity = [NSString stringWithFormat:NSLocalizedString(@"capacity", nil), ToNSString(value)]; break; break;
case MetadataID::FMD_WHEELCHAIR: _wheelchair = ToNSString(platform::GetLocalizedTypeName(value)); break; case MetadataID::FMD_LEVEL: _level = ToNSString(value); break;
case MetadataID::FMD_DRIVE_THROUGH: case MetadataID::FMD_CAPACITY:
if (value == "yes") _capacity = [NSString stringWithFormat:NSLocalizedString(@"capacity", nil), ToNSString(value)];
_driveThrough = NSLocalizedString(@"drive_through", nil); break;
break; case MetadataID::FMD_WHEELCHAIR: _wheelchair = ToNSString(platform::GetLocalizedTypeName(value)); break;
case MetadataID::FMD_WEBSITE_MENU: _websiteMenu = ToNSString(value); break; case MetadataID::FMD_DRIVE_THROUGH:
case MetadataID::FMD_SELF_SERVICE: _selfService = GetLocalizedMetadataValueString(metaID, value); break; if (value == "yes")
case MetadataID::FMD_OUTDOOR_SEATING: _driveThrough = NSLocalizedString(@"drive_through", nil);
if (value == "yes") break;
_outdoorSeating = NSLocalizedString(@"outdoor_seating", nil); case MetadataID::FMD_WEBSITE_MENU: _websiteMenu = ToNSString(value); break;
break; case MetadataID::FMD_SELF_SERVICE: _selfService = GetLocalizedMetadataValueString(metaID, value); break;
case MetadataID::FMD_NETWORK: _network = [NSString stringWithFormat:NSLocalizedString(@"network", nil), ToNSString(value)]; break; case MetadataID::FMD_OUTDOOR_SEATING:
default: if (value == "yes")
break; _outdoorSeating = NSLocalizedString(@"outdoor_seating", nil);
break;
case MetadataID::FMD_NETWORK:
_network = [NSString stringWithFormat:NSLocalizedString(@"network", nil), ToNSString(value)];
break;
default: break;
} }
}); });
_atm = rawData.HasAtm() ? NSLocalizedString(@"type.amenity.atm", nil) : nil; _atm = rawData.HasAtm() ? NSLocalizedString(@"type.amenity.atm", nil) : nil;
_address = rawData.GetSecondarySubtitle().empty() ? nil : @(rawData.GetSecondarySubtitle().c_str()); _address = rawData.GetSecondarySubtitle().empty() ? nil : @(rawData.GetSecondarySubtitle().c_str());
_coordFormats = @[@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDMS).c_str()), _coordFormats = @[
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDecimal).c_str()), @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDMS).c_str()),
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::OLCFull).c_str()), @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDecimal).c_str()),
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::OSMLink).c_str()), @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::OLCFull).c_str()),
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::UTM).c_str()), @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::OSMLink).c_str()),
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::MGRS).c_str())]; @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::UTM).c_str()),
@(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::MGRS).c_str())
];
} }
return self; return self;
} }

View File

@@ -1,7 +1,7 @@
#import "PlacePagePreviewData+Core.h"
#import "DistanceFormatter.h"
#import "AltitudeFormatter.h" #import "AltitudeFormatter.h"
#import "DistanceFormatter.h"
#import "DurationFormatter.h" #import "DurationFormatter.h"
#import "PlacePagePreviewData+Core.h"
#import "TrackInfo.h" #import "TrackInfo.h"
#include "3party/opening_hours/opening_hours.hpp" #include "3party/opening_hours/opening_hours.hpp"
@@ -10,39 +10,41 @@ static PlacePageDataSchedule convertOpeningHours(std::string_view rawOH)
{ {
PlacePageDataSchedule schedule; PlacePageDataSchedule schedule;
if (rawOH.empty()) { if (rawOH.empty())
{
schedule.state = PlacePageDataOpeningHoursUnknown; schedule.state = PlacePageDataOpeningHoursUnknown;
return schedule; return schedule;
} }
/// @todo Avoid temporary string when OpeningHours (boost::spirit) will allow string_view. /// @todo Avoid temporary string when OpeningHours (boost::spirit) will allow string_view.
osmoh::OpeningHours oh((std::string(rawOH))); osmoh::OpeningHours oh((std::string(rawOH)));
if (!oh.IsValid()) { if (!oh.IsValid())
{
schedule.state = PlacePageDataOpeningHoursUnknown; schedule.state = PlacePageDataOpeningHoursUnknown;
return schedule; return schedule;
} }
if (oh.IsTwentyFourHours()) { if (oh.IsTwentyFourHours())
{
schedule.state = PlacePageDataOpeningHoursAllDay; schedule.state = PlacePageDataOpeningHoursAllDay;
return schedule; return schedule;
} }
auto const t = time(nullptr); auto const t = time(nullptr);
osmoh::OpeningHours::InfoT info = oh.GetInfo(t); osmoh::OpeningHours::InfoT info = oh.GetInfo(t);
switch (info.state) { switch (info.state)
case osmoh::RuleState::Open: {
schedule.state = PlacePageDataOpeningHoursOpen; case osmoh::RuleState::Open:
schedule.nextTimeClosed = info.nextTimeClosed; schedule.state = PlacePageDataOpeningHoursOpen;
break; schedule.nextTimeClosed = info.nextTimeClosed;
break;
case osmoh::RuleState::Closed: case osmoh::RuleState::Closed:
schedule.state = PlacePageDataOpeningHoursClosed; schedule.state = PlacePageDataOpeningHoursClosed;
schedule.nextTimeOpen = info.nextTimeOpen; schedule.nextTimeOpen = info.nextTimeOpen;
break; break;
case osmoh::RuleState::Unknown: case osmoh::RuleState::Unknown: schedule.state = PlacePageDataOpeningHoursUnknown; break;
schedule.state = PlacePageDataOpeningHoursUnknown;
break;
} }
return schedule; return schedule;
@@ -50,9 +52,11 @@ static PlacePageDataSchedule convertOpeningHours(std::string_view rawOH)
@implementation PlacePagePreviewData @implementation PlacePagePreviewData
- (instancetype)initWithTrackInfo:(TrackInfo * _Nonnull)trackInfo { - (instancetype)initWithTrackInfo:(TrackInfo * _Nonnull)trackInfo
{
self = [super init]; self = [super init];
if (self) { if (self)
{
NSString * kSeparator = @" • "; NSString * kSeparator = @" • ";
_title = [@[trackInfo.duration, trackInfo.distance] componentsJoinedByString:kSeparator]; _title = [@[trackInfo.duration, trackInfo.distance] componentsJoinedByString:kSeparator];
} }
@@ -63,15 +67,18 @@ static PlacePageDataSchedule convertOpeningHours(std::string_view rawOH)
@implementation PlacePagePreviewData (Core) @implementation PlacePagePreviewData (Core)
- (instancetype)initWithRawData:(place_page::Info const &)rawData { - (instancetype)initWithRawData:(place_page::Info const &)rawData
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_title = rawData.GetTitle().empty() ? nil : @(rawData.GetTitle().c_str()); _title = rawData.GetTitle().empty() ? nil : @(rawData.GetTitle().c_str());
_secondaryTitle = rawData.GetSecondaryTitle().empty() ? nil : @(rawData.GetSecondaryTitle().c_str()); _secondaryTitle = rawData.GetSecondaryTitle().empty() ? nil : @(rawData.GetSecondaryTitle().c_str());
_subtitle = rawData.GetSubtitle().empty() ? nil : @(rawData.GetSubtitle().c_str()); _subtitle = rawData.GetSubtitle().empty() ? nil : @(rawData.GetSubtitle().c_str());
_secondarySubtitle = rawData.GetSecondarySubtitle().empty() ? nil : @(rawData.GetSecondarySubtitle().c_str()); _secondarySubtitle = rawData.GetSecondarySubtitle().empty() ? nil : @(rawData.GetSecondarySubtitle().c_str());
if (!rawData.IsTrack()) { if (!rawData.IsTrack())
{
_coordinates = @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDMS).c_str()); _coordinates = @(rawData.GetFormattedCoordinate(place_page::CoordinatesFormat::LatLonDMS).c_str());
_isMyPosition = rawData.IsMyPosition(); _isMyPosition = rawData.IsMyPosition();
_schedule = convertOpeningHours(rawData.GetOpeningHours()); _schedule = convertOpeningHours(rawData.GetOpeningHours());

View File

@@ -1,5 +1,5 @@
#import "PlacePageTrackData+Core.h"
#import "ElevationProfileData+Core.h" #import "ElevationProfileData+Core.h"
#import "PlacePageTrackData+Core.h"
#import "TrackInfo+Core.h" #import "TrackInfo+Core.h"
@interface PlacePageTrackData () @interface PlacePageTrackData ()
@@ -11,10 +11,12 @@
@implementation PlacePageTrackData @implementation PlacePageTrackData
- (instancetype)initWithTrackInfo:(TrackInfo *)trackInfo - (instancetype)initWithTrackInfo:(TrackInfo *)trackInfo
elevationInfo:(ElevationProfileData * _Nullable)elevationInfo elevationInfo:(ElevationProfileData * _Nullable)elevationInfo
onActivePointChanged:(MWMVoidBlock)onActivePointChangedHandler { onActivePointChanged:(MWMVoidBlock)onActivePointChangedHandler
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_trackInfo = trackInfo; _trackInfo = trackInfo;
_elevationProfileData = elevationInfo; _elevationProfileData = elevationInfo;
_onActivePointChangedHandler = onActivePointChangedHandler; _onActivePointChangedHandler = onActivePointChangedHandler;
@@ -22,7 +24,8 @@
return self; return self;
} }
- (void)updateActivePointDistance:(double)distance { - (void)updateActivePointDistance:(double)distance
{
self.activePointDistance = distance; self.activePointDistance = distance;
if (self.onActivePointChangedHandler) if (self.onActivePointChangedHandler)
self.onActivePointChangedHandler(); self.onActivePointChangedHandler();
@@ -33,9 +36,11 @@
@implementation PlacePageTrackData (Core) @implementation PlacePageTrackData (Core)
- (instancetype)initWithRawData:(place_page::Info const &)rawData - (instancetype)initWithRawData:(place_page::Info const &)rawData
onActivePointChanged:(MWMVoidBlock)onActivePointChangedHandler { onActivePointChanged:(MWMVoidBlock)onActivePointChangedHandler
{
self = [super init]; self = [super init];
if (self) { if (self)
{
auto const trackPtr = GetFramework().GetBookmarkManager().GetTrack(rawData.GetTrackId()); auto const trackPtr = GetFramework().GetBookmarkManager().GetTrack(rawData.GetTrackId());
auto const & track = *trackPtr; auto const & track = *trackPtr;
auto const & bm = GetFramework().GetBookmarkManager(); auto const & bm = GetFramework().GetBookmarkManager();
@@ -43,7 +48,8 @@
_trackId = track.GetData().m_id; _trackId = track.GetData().m_id;
auto const & groupId = track.GetGroupId(); auto const & groupId = track.GetGroupId();
if (groupId && bm.HasBmCategory(groupId)) { if (groupId && bm.HasBmCategory(groupId))
{
_groupId = groupId; _groupId = groupId;
_trackCategory = [NSString stringWithCString:bm.GetCategoryName(groupId).c_str() encoding:NSUTF8StringEncoding]; _trackCategory = [NSString stringWithCString:bm.GetCategoryName(groupId).c_str() encoding:NSUTF8StringEncoding];
} }
@@ -58,7 +64,8 @@
_onActivePointChangedHandler = onActivePointChangedHandler; _onActivePointChangedHandler = onActivePointChangedHandler;
auto const & elevationInfo = track.GetElevationInfo(); auto const & elevationInfo = track.GetElevationInfo();
if (track.HasAltitudes() && elevationInfo.has_value()) { if (track.HasAltitudes() && elevationInfo.has_value())
{
_elevationProfileData = [[ElevationProfileData alloc] initWithTrackId:_trackId _elevationProfileData = [[ElevationProfileData alloc] initWithTrackId:_trackId
elevationInfo:elevationInfo.value()]; elevationInfo:elevationInfo.value()];
} }

View File

@@ -2,16 +2,14 @@
#include "geometry/mercator.hpp" #include "geometry/mercator.hpp"
static ElevationDifficulty convertDifficulty(uint8_t difficulty) { static ElevationDifficulty convertDifficulty(uint8_t difficulty)
switch (difficulty) { {
case ElevationInfo::Difficulty::Easy: switch (difficulty)
return ElevationDifficulty::ElevationDifficultyEasy; {
case ElevationInfo::Difficulty::Medium: case ElevationInfo::Difficulty::Easy: return ElevationDifficulty::ElevationDifficultyEasy;
return ElevationDifficulty::ElevationDifficultyMedium; case ElevationInfo::Difficulty::Medium: return ElevationDifficulty::ElevationDifficultyMedium;
case ElevationInfo::Difficulty::Hard: case ElevationInfo::Difficulty::Hard: return ElevationDifficulty::ElevationDifficultyHard;
return ElevationDifficulty::ElevationDifficultyHard; case ElevationInfo::Difficulty::Unknown: return ElevationDifficulty::ElevationDifficultyDisabled;
case ElevationInfo::Difficulty::Unknown:
return ElevationDifficulty::ElevationDifficultyDisabled;
} }
return ElevationDifficulty::ElevationDifficultyDisabled; return ElevationDifficulty::ElevationDifficultyDisabled;
} }
@@ -22,10 +20,11 @@ static ElevationDifficulty convertDifficulty(uint8_t difficulty) {
@implementation ElevationProfileData (Core) @implementation ElevationProfileData (Core)
- (instancetype)initWithTrackId:(MWMTrackID)trackId - (instancetype)initWithTrackId:(MWMTrackID)trackId elevationInfo:(ElevationInfo const &)elevationInfo
elevationInfo:(ElevationInfo const &)elevationInfo { {
self = [super init]; self = [super init];
if (self) { if (self)
{
_trackId = trackId; _trackId = trackId;
_difficulty = convertDifficulty(elevationInfo.GetDifficulty()); _difficulty = convertDifficulty(elevationInfo.GetDifficulty());
_points = [ElevationProfileData pointsFromElevationInfo:elevationInfo]; _points = [ElevationProfileData pointsFromElevationInfo:elevationInfo];
@@ -34,9 +33,11 @@ static ElevationDifficulty convertDifficulty(uint8_t difficulty) {
return self; return self;
} }
- (instancetype)initWithElevationInfo:(ElevationInfo const &)elevationInfo { - (instancetype)initWithElevationInfo:(ElevationInfo const &)elevationInfo
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_difficulty = convertDifficulty(elevationInfo.GetDifficulty()); _difficulty = convertDifficulty(elevationInfo.GetDifficulty());
_points = [ElevationProfileData pointsFromElevationInfo:elevationInfo]; _points = [ElevationProfileData pointsFromElevationInfo:elevationInfo];
_isTrackRecording = true; _isTrackRecording = true;
@@ -44,15 +45,18 @@ static ElevationDifficulty convertDifficulty(uint8_t difficulty) {
return self; return self;
} }
+ (NSArray<ElevationHeightPoint *> *)pointsFromElevationInfo:(ElevationInfo const &)elevationInfo { + (NSArray<ElevationHeightPoint *> *)pointsFromElevationInfo:(ElevationInfo const &)elevationInfo
{
auto const & points = elevationInfo.GetPoints(); auto const & points = elevationInfo.GetPoints();
NSMutableArray * pointsArray = [[NSMutableArray alloc] initWithCapacity:points.size()]; NSMutableArray * pointsArray = [[NSMutableArray alloc] initWithCapacity:points.size()];
for (auto const & point : points) { for (auto const & point : points)
{
auto pointLatLon = mercator::ToLatLon(point.m_point.GetPoint()); auto pointLatLon = mercator::ToLatLon(point.m_point.GetPoint());
CLLocationCoordinate2D coordinates = CLLocationCoordinate2DMake(pointLatLon.m_lat, pointLatLon.m_lon); CLLocationCoordinate2D coordinates = CLLocationCoordinate2DMake(pointLatLon.m_lat, pointLatLon.m_lon);
ElevationHeightPoint * elevationPoint = [[ElevationHeightPoint alloc] initWithCoordinates:coordinates ElevationHeightPoint * elevationPoint =
distance:point.m_distance [[ElevationHeightPoint alloc] initWithCoordinates:coordinates
andAltitude:point.m_point.GetAltitude()]; distance:point.m_distance
andAltitude:point.m_point.GetAltitude()];
[pointsArray addObject:elevationPoint]; [pointsArray addObject:elevationPoint];
} }
return pointsArray; return pointsArray;

View File

@@ -1,38 +1,40 @@
#import "PlacePageData.h" #import "PlacePageData.h"
#import "PlacePageButtonsData+Core.h"
#import "PlacePagePreviewData+Core.h"
#import "PlacePageInfoData+Core.h"
#import "PlacePageBookmarkData+Core.h"
#import "PlacePageTrackData+Core.h"
#import "ElevationProfileData+Core.h" #import "ElevationProfileData+Core.h"
#import "MWMMapNodeAttributes.h" #import "MWMMapNodeAttributes.h"
#import "PlacePageBookmarkData+Core.h"
#import "PlacePageButtonsData+Core.h"
#import "PlacePageInfoData+Core.h"
#import "PlacePagePreviewData+Core.h"
#import "PlacePageTrackData+Core.h"
#include <CoreApi/CoreApi.h> #include <CoreApi/CoreApi.h>
#include "platform/network_policy.hpp" #include "platform/network_policy.hpp"
static place_page::Info & rawData() { return GetFramework().GetCurrentPlacePageInfo(); } static place_page::Info & rawData()
{
return GetFramework().GetCurrentPlacePageInfo();
}
static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) { static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType)
switch (roadType) { {
case RoadWarningMarkType::Toll: switch (roadType)
return PlacePageRoadTypeToll; {
case RoadWarningMarkType::Ferry: case RoadWarningMarkType::Toll: return PlacePageRoadTypeToll;
return PlacePageRoadTypeFerry; case RoadWarningMarkType::Ferry: return PlacePageRoadTypeFerry;
case RoadWarningMarkType::Dirty: case RoadWarningMarkType::Dirty: return PlacePageRoadTypeDirty;
return PlacePageRoadTypeDirty; case RoadWarningMarkType::Count: return PlacePageRoadTypeNone;
case RoadWarningMarkType::Count:
return PlacePageRoadTypeNone;
} }
} }
@interface PlacePageData () <MWMStorageObserver> { @interface PlacePageData () <MWMStorageObserver>
{
FeatureID m_featureID; FeatureID m_featureID;
m2::PointD m_mercator; m2::PointD m_mercator;
std::vector<std::string> m_rawTypes; std::vector<std::string> m_rawTypes;
} }
@property(nonatomic, readwrite) PlacePagePreviewData *previewData; @property(nonatomic, readwrite) PlacePagePreviewData * previewData;
@property(nonatomic, readwrite) CLLocationCoordinate2D locationCoordinate; @property(nonatomic, readwrite) CLLocationCoordinate2D locationCoordinate;
- (PlacePageObjectType)objectTypeFromRawData; - (PlacePageObjectType)objectTypeFromRawData;
@@ -41,19 +43,19 @@ static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) {
@implementation PlacePageData @implementation PlacePageData
- (instancetype)initWithLocalizationProvider:(id<IOpeningHoursLocalization>)localization { - (instancetype)initWithLocalizationProvider:(id<IOpeningHoursLocalization>)localization
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_buttonsData = [[PlacePageButtonsData alloc] initWithRawData:rawData()]; _buttonsData = [[PlacePageButtonsData alloc] initWithRawData:rawData()];
_infoData = [[PlacePageInfoData alloc] initWithRawData:rawData() ohLocalization:localization]; _infoData = [[PlacePageInfoData alloc] initWithRawData:rawData() ohLocalization:localization];
if (rawData().IsBookmark()) { if (rawData().IsBookmark())
_bookmarkData = [[PlacePageBookmarkData alloc] initWithRawData:rawData()]; _bookmarkData = [[PlacePageBookmarkData alloc] initWithRawData:rawData()];
}
if (auto const & wikiDescription = rawData().GetWikiDescription(); !wikiDescription.empty()) { if (auto const & wikiDescription = rawData().GetWikiDescription(); !wikiDescription.empty())
_wikiDescriptionHtml = @(("<html><body>" + wikiDescription + "</body></html>").c_str()); _wikiDescriptionHtml = @(("<html><body>" + wikiDescription + "</body></html>").c_str());
}
_roadType = convertRoadType(rawData().GetRoadType()); _roadType = convertRoadType(rawData().GetRoadType());
@@ -63,21 +65,22 @@ static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) {
auto latlon = rawData().GetLatLon(); auto latlon = rawData().GetLatLon();
_locationCoordinate = CLLocationCoordinate2DMake(latlon.m_lat, latlon.m_lon); _locationCoordinate = CLLocationCoordinate2DMake(latlon.m_lat, latlon.m_lon);
NSMutableArray *tagsArray = [NSMutableArray array]; NSMutableArray * tagsArray = [NSMutableArray array];
for (auto const & s : rawData().GetRawTypes()) { for (auto const & s : rawData().GetRawTypes())
[tagsArray addObject:@(s.c_str())]; [tagsArray addObject:@(s.c_str())];
}
if (rawData().IsTrack()) { if (rawData().IsTrack())
{
__weak auto weakSelf = self; __weak auto weakSelf = self;
_trackData = [[PlacePageTrackData alloc] initWithRawData:rawData() onActivePointChanged:^(void) { _trackData =
[weakSelf handleActiveTrackSelectionPointChanged]; [[PlacePageTrackData alloc] initWithRawData:rawData()
}]; onActivePointChanged:^(void) { [weakSelf handleActiveTrackSelectionPointChanged]; }];
} }
_previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()]; _previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()];
auto const &countryId = rawData().GetCountryId(); auto const & countryId = rawData().GetCountryId();
if (!countryId.empty()) { if (!countryId.empty())
{
_mapNodeAttributes = [[MWMStorage sharedStorage] attributesForCountry:@(rawData().GetCountryId().c_str())]; _mapNodeAttributes = [[MWMStorage sharedStorage] attributesForCountry:@(rawData().GetCountryId().c_str())];
[[MWMStorage sharedStorage] addObserver:self]; [[MWMStorage sharedStorage] addObserver:self];
} }
@@ -91,23 +94,27 @@ static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) {
return self; return self;
} }
- (instancetype)initWithTrackInfo:(TrackInfo * _Nonnull)trackInfo elevationInfo:(ElevationProfileData * _Nullable)elevationInfo { - (instancetype)initWithTrackInfo:(TrackInfo * _Nonnull)trackInfo
elevationInfo:(ElevationProfileData * _Nullable)elevationInfo
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_objectType = PlacePageObjectTypeTrackRecording; _objectType = PlacePageObjectTypeTrackRecording;
_roadType = PlacePageRoadTypeNone; _roadType = PlacePageRoadTypeNone;
_previewData = [[PlacePagePreviewData alloc] initWithTrackInfo:trackInfo]; _previewData = [[PlacePagePreviewData alloc] initWithTrackInfo:trackInfo];
__weak auto weakSelf = self; __weak auto weakSelf = self;
_trackData = [[PlacePageTrackData alloc] initWithTrackInfo:trackInfo _trackData =
elevationInfo:elevationInfo [[PlacePageTrackData alloc] initWithTrackInfo:trackInfo
onActivePointChanged:^(void) { elevationInfo:elevationInfo
[weakSelf handleActiveTrackSelectionPointChanged]; onActivePointChanged:^(void) { [weakSelf handleActiveTrackSelectionPointChanged]; }];
}];
} }
return self; return self;
} }
- (void)updateWithTrackInfo:(TrackInfo * _Nonnull)trackInfo elevationInfo:(ElevationProfileData * _Nullable)elevationInfo { - (void)updateWithTrackInfo:(TrackInfo * _Nonnull)trackInfo
elevationInfo:(ElevationProfileData * _Nullable)elevationInfo
{
_previewData = [[PlacePagePreviewData alloc] initWithTrackInfo:trackInfo]; _previewData = [[PlacePagePreviewData alloc] initWithTrackInfo:trackInfo];
_trackData.trackInfo = trackInfo; _trackData.trackInfo = trackInfo;
_trackData.elevationProfileData = elevationInfo; _trackData.elevationProfileData = elevationInfo;
@@ -115,7 +122,8 @@ static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) {
self.onTrackRecordingProgressUpdate(); self.onTrackRecordingProgressUpdate();
} }
- (void)handleActiveTrackSelectionPointChanged { - (void)handleActiveTrackSelectionPointChanged
{
if (!self || !rawData().IsTrack()) if (!self || !rawData().IsTrack())
return; return;
auto const & trackInfo = GetFramework().GetBookmarkManager().GetTrackSelectionInfo(rawData().GetTrackId()); auto const & trackInfo = GetFramework().GetBookmarkManager().GetTrackSelectionInfo(rawData().GetTrackId());
@@ -124,66 +132,72 @@ static PlacePageRoadType convertRoadType(RoadWarningMarkType roadType) {
self.previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()]; self.previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()];
} }
- (void)dealloc { - (void)dealloc
if (self.mapNodeAttributes != nil) { {
if (self.mapNodeAttributes != nil)
[[MWMStorage sharedStorage] removeObserver:self]; [[MWMStorage sharedStorage] removeObserver:self];
}
} }
+ (BOOL)hasData { + (BOOL)hasData
{
return GetFramework().HasPlacePageInfo(); return GetFramework().HasPlacePageInfo();
} }
#pragma mark - Private #pragma mark - Private
- (void)updateBookmarkStatus { - (void)updateBookmarkStatus
if (!GetFramework().HasPlacePageInfo()) { {
if (!GetFramework().HasPlacePageInfo())
return; return;
} if (rawData().IsBookmark())
if (rawData().IsBookmark()) { {
_bookmarkData = [[PlacePageBookmarkData alloc] initWithRawData:rawData()]; _bookmarkData = [[PlacePageBookmarkData alloc] initWithRawData:rawData()];
} else if (rawData().IsTrack()) { }
else if (rawData().IsTrack())
{
__weak auto weakSelf = self; __weak auto weakSelf = self;
_trackData = [[PlacePageTrackData alloc] initWithRawData:rawData() onActivePointChanged:^(void) { _trackData =
[weakSelf handleActiveTrackSelectionPointChanged]; [[PlacePageTrackData alloc] initWithRawData:rawData()
}]; onActivePointChanged:^(void) { [weakSelf handleActiveTrackSelectionPointChanged]; }];
} else { }
else
{
_bookmarkData = nil; _bookmarkData = nil;
} }
_previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()]; _previewData = [[PlacePagePreviewData alloc] initWithRawData:rawData()];
_objectType = [self objectTypeFromRawData]; _objectType = [self objectTypeFromRawData];
if (self.onBookmarkStatusUpdate != nil) { if (self.onBookmarkStatusUpdate != nil)
self.onBookmarkStatusUpdate(); self.onBookmarkStatusUpdate();
}
} }
- (PlacePageObjectType)objectTypeFromRawData { - (PlacePageObjectType)objectTypeFromRawData
if (rawData().IsBookmark()) { {
if (rawData().IsBookmark())
return PlacePageObjectTypeBookmark; return PlacePageObjectTypeBookmark;
} else if (rawData().IsTrack()) { else if (rawData().IsTrack())
return PlacePageObjectTypeTrack; return PlacePageObjectTypeTrack;
} else if (self.trackData) { else if (self.trackData)
return PlacePageObjectTypeTrackRecording; return PlacePageObjectTypeTrackRecording;
} else { else
return PlacePageObjectTypePOI; return PlacePageObjectTypePOI;
}
} }
#pragma mark - MWMStorageObserver #pragma mark - MWMStorageObserver
- (void)processCountryEvent:(NSString *)countryId { - (void)processCountryEvent:(NSString *)countryId
if ([countryId isEqualToString:self.mapNodeAttributes.countryId]) { {
if ([countryId isEqualToString:self.mapNodeAttributes.countryId])
{
_mapNodeAttributes = [[MWMStorage sharedStorage] attributesForCountry:countryId]; _mapNodeAttributes = [[MWMStorage sharedStorage] attributesForCountry:countryId];
if (self.onMapNodeStatusUpdate != nil) { if (self.onMapNodeStatusUpdate != nil)
self.onMapNodeStatusUpdate(); self.onMapNodeStatusUpdate();
}
} }
} }
- (void)processCountry:(NSString *)countryId downloadedBytes:(uint64_t)downloadedBytes totalBytes:(uint64_t)totalBytes { - (void)processCountry:(NSString *)countryId downloadedBytes:(uint64_t)downloadedBytes totalBytes:(uint64_t)totalBytes
if ([countryId isEqualToString:self.mapNodeAttributes.countryId] && self.onMapNodeProgressUpdate != nil) { {
if ([countryId isEqualToString:self.mapNodeAttributes.countryId] && self.onMapNodeProgressUpdate != nil)
self.onMapNodeProgressUpdate(downloadedBytes, totalBytes); self.onMapNodeProgressUpdate(downloadedBytes, totalBytes);
}
} }
@end @end

View File

@@ -1,50 +1,47 @@
#import "MWMMapNodeAttributes+Core.h"
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
#import "MWMMapNodeAttributes+Core.h"
static MWMMapNodeStatus convertStatus(storage::NodeStatus status) { static MWMMapNodeStatus convertStatus(storage::NodeStatus status)
switch (status) { {
case storage::NodeStatus::Undefined: switch (status)
return MWMMapNodeStatusUndefined; {
case storage::NodeStatus::Downloading: case storage::NodeStatus::Undefined: return MWMMapNodeStatusUndefined;
return MWMMapNodeStatusDownloading; case storage::NodeStatus::Downloading: return MWMMapNodeStatusDownloading;
case storage::NodeStatus::Applying: case storage::NodeStatus::Applying: return MWMMapNodeStatusApplying;
return MWMMapNodeStatusApplying; case storage::NodeStatus::InQueue: return MWMMapNodeStatusInQueue;
case storage::NodeStatus::InQueue: case storage::NodeStatus::Error: return MWMMapNodeStatusError;
return MWMMapNodeStatusInQueue; case storage::NodeStatus::OnDiskOutOfDate: return MWMMapNodeStatusOnDiskOutOfDate;
case storage::NodeStatus::Error: case storage::NodeStatus::OnDisk: return MWMMapNodeStatusOnDisk;
return MWMMapNodeStatusError; case storage::NodeStatus::NotDownloaded: return MWMMapNodeStatusNotDownloaded;
case storage::NodeStatus::OnDiskOutOfDate: case storage::NodeStatus::Partly: return MWMMapNodeStatusPartly;
return MWMMapNodeStatusOnDiskOutOfDate;
case storage::NodeStatus::OnDisk:
return MWMMapNodeStatusOnDisk;
case storage::NodeStatus::NotDownloaded:
return MWMMapNodeStatusNotDownloaded;
case storage::NodeStatus::Partly:
return MWMMapNodeStatusPartly;
} }
} }
@interface MWMCountryIdAndName () @interface MWMCountryIdAndName ()
@property(nonatomic, copy) NSString *countryId; @property(nonatomic, copy) NSString * countryId;
@property(nonatomic, copy) NSString *countryName; @property(nonatomic, copy) NSString * countryName;
@end @end
@implementation MWMCountryIdAndName @implementation MWMCountryIdAndName
- (instancetype)initWithCountryId:(NSString *)countryId name:(NSString *)countryName { - (instancetype)initWithCountryId:(NSString *)countryId name:(NSString *)countryName
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_countryId = countryId; _countryId = countryId;
_countryName = countryName; _countryName = countryName;
} }
return self; return self;
} }
- (instancetype)initWithCountryAndName:(storage::CountryIdAndName const &)countryAndName { - (instancetype)initWithCountryAndName:(storage::CountryIdAndName const &)countryAndName
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_countryId = @(countryAndName.m_id.c_str()); _countryId = @(countryAndName.m_id.c_str());
_countryName = @(countryAndName.m_localName.c_str()); _countryName = @(countryAndName.m_localName.c_str());
} }
@@ -62,9 +59,11 @@ static MWMMapNodeStatus convertStatus(storage::NodeStatus status) {
- (instancetype)initWithCoreAttributes:(storage::NodeAttrs const &)attributes - (instancetype)initWithCoreAttributes:(storage::NodeAttrs const &)attributes
countryId:(NSString *)countryId countryId:(NSString *)countryId
hasParent:(BOOL)hasParent hasParent:(BOOL)hasParent
hasChildren:(BOOL)hasChildren { hasChildren:(BOOL)hasChildren
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_countryId = [countryId copy]; _countryId = [countryId copy];
_totalMwmCount = attributes.m_mwmCounter; _totalMwmCount = attributes.m_mwmCounter;
_downloadedMwmCount = attributes.m_localMwmCounter; _downloadedMwmCount = attributes.m_localMwmCounter;
@@ -79,22 +78,23 @@ static MWMMapNodeStatus convertStatus(storage::NodeStatus status) {
_hasParent = hasParent; _hasParent = hasParent;
storage::Storage::UpdateInfo updateInfo; storage::Storage::UpdateInfo updateInfo;
if (GetFramework().GetStorage().GetUpdateInfo([countryId UTF8String], updateInfo)) { if (GetFramework().GetStorage().GetUpdateInfo([countryId UTF8String], updateInfo))
_totalUpdateSizeBytes = updateInfo.m_totalDownloadSizeInBytes; _totalUpdateSizeBytes = updateInfo.m_totalDownloadSizeInBytes;
} else { else
_totalUpdateSizeBytes = 0; _totalUpdateSizeBytes = 0;
}
NSMutableArray *parentInfoArray = [NSMutableArray arrayWithCapacity:attributes.m_parentInfo.size()]; NSMutableArray * parentInfoArray = [NSMutableArray arrayWithCapacity:attributes.m_parentInfo.size()];
for (auto const &pi : attributes.m_parentInfo) { for (auto const & pi : attributes.m_parentInfo)
MWMCountryIdAndName *cn = [[MWMCountryIdAndName alloc] initWithCountryAndName:pi]; {
MWMCountryIdAndName * cn = [[MWMCountryIdAndName alloc] initWithCountryAndName:pi];
[parentInfoArray addObject:cn]; [parentInfoArray addObject:cn];
} }
_parentInfo = [parentInfoArray copy]; _parentInfo = [parentInfoArray copy];
NSMutableArray *topmostInfoArray = [NSMutableArray arrayWithCapacity:attributes.m_topmostParentInfo.size()]; NSMutableArray * topmostInfoArray = [NSMutableArray arrayWithCapacity:attributes.m_topmostParentInfo.size()];
for (auto const &pi : attributes.m_topmostParentInfo) { for (auto const & pi : attributes.m_topmostParentInfo)
MWMCountryIdAndName *cn = [[MWMCountryIdAndName alloc] initWithCountryAndName:pi]; {
MWMCountryIdAndName * cn = [[MWMCountryIdAndName alloc] initWithCountryAndName:pi];
[topmostInfoArray addObject:cn]; [topmostInfoArray addObject:cn];
} }
_topmostParentInfo = topmostInfoArray.count > 0 ? [topmostInfoArray copy] : nil; _topmostParentInfo = topmostInfoArray.count > 0 ? [topmostInfoArray copy] : nil;

View File

@@ -6,9 +6,11 @@
@implementation MWMMapSearchResult (Core) @implementation MWMMapSearchResult (Core)
- (instancetype)initWithSearchResult:(storage::DownloaderSearchResult const &)searchResult { - (instancetype)initWithSearchResult:(storage::DownloaderSearchResult const &)searchResult
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_countryId = @(searchResult.m_countryId.c_str()); _countryId = @(searchResult.m_countryId.c_str());
_matchedName = @(searchResult.m_matchedName.c_str()); _matchedName = @(searchResult.m_matchedName.c_str());
} }

View File

@@ -6,9 +6,11 @@
@implementation MWMMapUpdateInfo (Core) @implementation MWMMapUpdateInfo (Core)
- (instancetype)initWithUpdateInfo:(storage::Storage::UpdateInfo const &)updateInfo { - (instancetype)initWithUpdateInfo:(storage::Storage::UpdateInfo const &)updateInfo
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_numberOfFiles = updateInfo.m_numberOfMwmFilesToUpdate; _numberOfFiles = updateInfo.m_numberOfMwmFilesToUpdate;
_updateSize = updateInfo.m_totalDownloadSizeInBytes; _updateSize = updateInfo.m_totalDownloadSizeInBytes;
_differenceSize = updateInfo.m_sizeDifference; _differenceSize = updateInfo.m_sizeDifference;

View File

@@ -19,92 +19,110 @@ using namespace storage;
@interface MWMStorage () @interface MWMStorage ()
@property(nonatomic, strong) NSHashTable<id<MWMStorageObserver>> *observers; @property(nonatomic, strong) NSHashTable<id<MWMStorageObserver>> * observers;
@end @end
@implementation MWMStorage @implementation MWMStorage
+ (instancetype)sharedStorage { + (instancetype)sharedStorage
static MWMStorage *instance; {
static MWMStorage * instance;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; });
instance = [[self alloc] init];
});
return instance; return instance;
} }
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_observers = [NSHashTable weakObjectsHashTable]; _observers = [NSHashTable weakObjectsHashTable];
NSHashTable *observers = _observers; NSHashTable * observers = _observers;
GetFramework().GetStorage().Subscribe( GetFramework().GetStorage().Subscribe(
[observers](CountryId const & countryId) { [observers](CountryId const & countryId)
// A copy is created, because MWMMapDownloadDialog is unsubscribed inside this notification with {
// NSGenericException', reason: '*** Collection <NSConcreteHashTable> was mutated while being enumerated.' // A copy is created, because MWMMapDownloadDialog is unsubscribed inside this notification with
NSHashTable *observersCopy = [observers copy]; // NSGenericException', reason: '*** Collection <NSConcreteHashTable> was mutated while being enumerated.'
for (id<MWMStorageObserver> observer in observersCopy) { NSHashTable * observersCopy = [observers copy];
[observer processCountryEvent:@(countryId.c_str())]; for (id<MWMStorageObserver> observer in observersCopy)
[observer processCountryEvent:@(countryId.c_str())];
}, [observers](CountryId const & countryId, downloader::Progress const & progress)
{
for (id<MWMStorageObserver> observer in observers)
{
// processCountry function in observer's implementation may not exist.
/// @todo We can face with an invisible bug, if function's signature will be changed.
if ([observer respondsToSelector:@selector(processCountry:downloadedBytes:totalBytes:)])
{
[observer processCountry:@(countryId.c_str())
downloadedBytes:progress.m_bytesDownloaded
totalBytes:progress.m_bytesTotal];
} }
}, }
[observers](CountryId const & countryId, downloader::Progress const & progress) { });
for (id<MWMStorageObserver> observer in observers) {
// processCountry function in observer's implementation may not exist.
/// @todo We can face with an invisible bug, if function's signature will be changed.
if ([observer respondsToSelector:@selector(processCountry:downloadedBytes:totalBytes:)]) {
[observer processCountry:@(countryId.c_str())
downloadedBytes:progress.m_bytesDownloaded
totalBytes:progress.m_bytesTotal];
}
}
});
} }
return self; return self;
} }
- (void)addObserver:(id<MWMStorageObserver>)observer { - (void)addObserver:(id<MWMStorageObserver>)observer
{
[self.observers addObject:observer]; [self.observers addObject:observer];
} }
- (void)removeObserver:(id<MWMStorageObserver>)observer { - (void)removeObserver:(id<MWMStorageObserver>)observer
{
[self.observers removeObject:observer]; [self.observers removeObject:observer];
} }
- (BOOL)downloadNode:(NSString *)countryId error:(NSError * __autoreleasing _Nullable *)error
- (BOOL)downloadNode:(NSString *)countryId error:(NSError *__autoreleasing _Nullable *)error { {
if (IsEnoughSpaceForDownload(countryId.UTF8String, GetFramework().GetStorage())) { if (IsEnoughSpaceForDownload(countryId.UTF8String, GetFramework().GetStorage()))
NSError *connectionError; {
if ([self checkConnection:&connectionError]) { NSError * connectionError;
if ([self checkConnection:&connectionError])
{
GetFramework().GetStorage().DownloadNode(countryId.UTF8String); GetFramework().GetStorage().DownloadNode(countryId.UTF8String);
return YES; return YES;
} else if (error) { }
else if (error)
{
*error = connectionError; *error = connectionError;
} }
} else if (error) { }
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil]; *error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
} }
return NO; return NO;
} }
- (void)retryDownloadNode:(NSString *)countryId { - (void)retryDownloadNode:(NSString *)countryId
if ([self checkConnection:nil]) { {
if ([self checkConnection:nil])
GetFramework().GetStorage().RetryDownloadNode(countryId.UTF8String); GetFramework().GetStorage().RetryDownloadNode(countryId.UTF8String);
}
} }
- (BOOL)updateNode:(NSString *)countryId error:(NSError *__autoreleasing _Nullable *)error { - (BOOL)updateNode:(NSString *)countryId error:(NSError * __autoreleasing _Nullable *)error
if (IsEnoughSpaceForUpdate(countryId.UTF8String, GetFramework().GetStorage())) { {
NSError *connectionError; if (IsEnoughSpaceForUpdate(countryId.UTF8String, GetFramework().GetStorage()))
if ([self checkConnection:&connectionError]) { {
NSError * connectionError;
if ([self checkConnection:&connectionError])
{
GetFramework().GetStorage().UpdateNode(countryId.UTF8String); GetFramework().GetStorage().UpdateNode(countryId.UTF8String);
return YES; return YES;
} else if (error) { }
else if (error)
{
*error = connectionError; *error = connectionError;
} }
} else if (error) { }
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil]; *error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
} }
@@ -112,21 +130,24 @@ using namespace storage;
} }
- (BOOL)deleteNode:(NSString *)countryId - (BOOL)deleteNode:(NSString *)countryId
ignoreUnsavedEdits:(BOOL)force ignoreUnsavedEdits:(BOOL)force
error:(NSError *__autoreleasing _Nullable *)error { error:(NSError * __autoreleasing _Nullable *)error
auto &f = GetFramework(); {
if (f.GetRoutingManager().IsRoutingActive()) { auto & f = GetFramework();
if (error) { if (f.GetRoutingManager().IsRoutingActive())
{
if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageRoutingActive userInfo:nil]; *error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageRoutingActive userInfo:nil];
}
return NO; return NO;
} }
if (!force && f.HasUnsavedEdits(countryId.UTF8String)) { if (!force && f.HasUnsavedEdits(countryId.UTF8String))
if (error) { {
if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageHaveUnsavedEdits userInfo:nil]; *error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageHaveUnsavedEdits userInfo:nil];
} }
} else { else
{
f.GetStorage().DeleteNode(countryId.UTF8String); f.GetStorage().DeleteNode(countryId.UTF8String);
return YES; return YES;
} }
@@ -134,135 +155,152 @@ using namespace storage;
return NO; return NO;
} }
- (void)cancelDownloadNode:(NSString *)countryId { - (void)cancelDownloadNode:(NSString *)countryId
{
GetFramework().GetStorage().CancelDownloadNode(countryId.UTF8String); GetFramework().GetStorage().CancelDownloadNode(countryId.UTF8String);
} }
- (void)showNode:(NSString *)countryId { - (void)showNode:(NSString *)countryId
{
GetFramework().ShowNode(countryId.UTF8String); GetFramework().ShowNode(countryId.UTF8String);
} }
- (BOOL)downloadNodes:(NSArray<NSString *> *)countryIds error:(NSError *__autoreleasing _Nullable *)error { - (BOOL)downloadNodes:(NSArray<NSString *> *)countryIds error:(NSError * __autoreleasing _Nullable *)error
auto &s = GetFramework().GetStorage(); {
auto & s = GetFramework().GetStorage();
MwmSize requiredSize = 0; MwmSize requiredSize = 0;
for (NSString *countryId in countryIds) { for (NSString * countryId in countryIds)
{
NodeAttrs nodeAttrs; NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(countryId.UTF8String, nodeAttrs); GetFramework().GetStorage().GetNodeAttrs(countryId.UTF8String, nodeAttrs);
requiredSize += nodeAttrs.m_mwmSize; requiredSize += nodeAttrs.m_mwmSize;
} }
if (storage::IsEnoughSpaceForDownload(requiredSize)) { if (storage::IsEnoughSpaceForDownload(requiredSize))
NSError *connectionError; {
if ([self checkConnection:&connectionError]) { NSError * connectionError;
for (NSString *countryId in countryIds) { if ([self checkConnection:&connectionError])
{
for (NSString * countryId in countryIds)
s.DownloadNode(countryId.UTF8String); s.DownloadNode(countryId.UTF8String);
}
return YES; return YES;
} else if (error) { }
else if (error)
{
*error = connectionError; *error = connectionError;
} }
} else if (error) { }
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil]; *error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
} }
return NO; return NO;
} }
- (BOOL)checkConnection:(NSError *__autoreleasing *)error { - (BOOL)checkConnection:(NSError * __autoreleasing *)error
switch (Platform::ConnectionStatus()) { {
case Platform::EConnectionType::CONNECTION_NONE: switch (Platform::ConnectionStatus())
if (error) { {
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNoConnection userInfo:nil]; case Platform::EConnectionType::CONNECTION_NONE:
} if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNoConnection userInfo:nil];
return NO;
break;
case Platform::EConnectionType::CONNECTION_WIFI:
if (error)
*error = nil;
return YES;
break;
case Platform::EConnectionType::CONNECTION_WWAN:
{
if (!GetFramework().GetDownloadingPolicy().IsCellularDownloadEnabled())
{
if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageCellularForbidden userInfo:nil];
return NO; return NO;
break;
case Platform::EConnectionType::CONNECTION_WIFI:
if (error) {
*error = nil;
}
return YES;
break;
case Platform::EConnectionType::CONNECTION_WWAN: {
if (!GetFramework().GetDownloadingPolicy().IsCellularDownloadEnabled()) {
if (error) {
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageCellularForbidden userInfo:nil];
}
return NO;
} else {
if (error) {
*error = nil;
}
return YES;
}
break;
} }
else
{
if (error)
*error = nil;
return YES;
}
break;
}
} }
} }
- (BOOL)haveDownloadedCountries { - (BOOL)haveDownloadedCountries
{
return GetFramework().GetStorage().HaveDownloadedCountries(); return GetFramework().GetStorage().HaveDownloadedCountries();
} }
- (BOOL)downloadInProgress { - (BOOL)downloadInProgress
{
return GetFramework().GetStorage().IsDownloadInProgress(); return GetFramework().GetStorage().IsDownloadInProgress();
} }
- (void)enableCellularDownload:(BOOL)enable { - (void)enableCellularDownload:(BOOL)enable
{
GetFramework().GetDownloadingPolicy().EnableCellularDownload(enable); GetFramework().GetDownloadingPolicy().EnableCellularDownload(enable);
} }
#pragma mark - Attributes #pragma mark - Attributes
- (NSArray<NSString *> *)allCountries { - (NSArray<NSString *> *)allCountries
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str()); {
NSString * rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self allCountriesWithParent:rootId]; return [self allCountriesWithParent:rootId];
} }
- (NSArray<NSString *> *)allCountriesWithParent:(NSString *)countryId { - (NSArray<NSString *> *)allCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren; storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren; storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren, GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren,
true /* keepAvailableChildren */); true /* keepAvailableChildren */);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:availableChildren.size()]; NSMutableArray * result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const &cid : availableChildren) { for (auto const & cid : availableChildren)
[result addObject:@(cid.c_str())]; [result addObject:@(cid.c_str())];
}
return [result copy]; return [result copy];
} }
- (NSArray<NSString *> *)availableCountriesWithParent:(NSString *)countryId { - (NSArray<NSString *> *)availableCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren; storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren; storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren); GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:availableChildren.size()]; NSMutableArray * result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const &cid : availableChildren) { for (auto const & cid : availableChildren)
[result addObject:@(cid.c_str())]; [result addObject:@(cid.c_str())];
}
return [result copy]; return [result copy];
} }
- (NSArray<NSString *> *)downloadedCountries { - (NSArray<NSString *> *)downloadedCountries
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str()); {
NSString * rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self downloadedCountriesWithParent:rootId]; return [self downloadedCountriesWithParent:rootId];
} }
- (NSArray<NSString *> *)downloadedCountriesWithParent:(NSString *)countryId { - (NSArray<NSString *> *)downloadedCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren; storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren; storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren); GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:downloadedChildren.size()]; NSMutableArray * result = [NSMutableArray arrayWithCapacity:downloadedChildren.size()];
for (auto const &cid : downloadedChildren) { for (auto const & cid : downloadedChildren)
[result addObject:@(cid.c_str())]; [result addObject:@(cid.c_str())];
}
return [result copy]; return [result copy];
} }
- (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId { - (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId
auto const &s = GetFramework().GetStorage(); {
auto const & s = GetFramework().GetStorage();
storage::NodeAttrs nodeAttrs; storage::NodeAttrs nodeAttrs;
s.GetNodeAttrs(countryId.UTF8String, nodeAttrs); s.GetNodeAttrs(countryId.UTF8String, nodeAttrs);
storage::CountriesVec children; storage::CountriesVec children;
@@ -274,25 +312,30 @@ using namespace storage;
hasChildren:!children.empty()]; hasChildren:!children.empty()];
} }
- (MWMMapNodeAttributes *)attributesForRoot { - (MWMMapNodeAttributes *)attributesForRoot
{
return [self attributesForCountry:@(GetFramework().GetStorage().GetRootId().c_str())]; return [self attributesForCountry:@(GetFramework().GetStorage().GetRootId().c_str())];
} }
- (NSString *)getRootId { - (NSString *)getRootId
{
return @(GetFramework().GetStorage().GetRootId().c_str()); return @(GetFramework().GetStorage().GetRootId().c_str());
} }
- (NSString *)nameForCountry:(NSString *)countryId { - (NSString *)nameForCountry:(NSString *)countryId
{
return @(GetFramework().GetStorage().GetNodeLocalName(countryId.UTF8String).c_str()); return @(GetFramework().GetStorage().GetNodeLocalName(countryId.UTF8String).c_str());
} }
- (NSArray<NSString *> *)nearbyAvailableCountries:(CLLocationCoordinate2D)location { - (NSArray<NSString *> *)nearbyAvailableCountries:(CLLocationCoordinate2D)location
auto &f = GetFramework(); {
auto & f = GetFramework();
storage::CountriesVec closestCoutryIds; storage::CountriesVec closestCoutryIds;
f.GetCountryInfoGetter().GetRegionsCountryId(mercator::FromLatLon(location.latitude, location.longitude), f.GetCountryInfoGetter().GetRegionsCountryId(mercator::FromLatLon(location.latitude, location.longitude),
closestCoutryIds); closestCoutryIds);
NSMutableArray *nearmeCountries = [NSMutableArray array]; NSMutableArray * nearmeCountries = [NSMutableArray array];
for (auto const &countryId : closestCoutryIds) { for (auto const & countryId : closestCoutryIds)
{
storage::NodeStatuses nodeStatuses; storage::NodeStatuses nodeStatuses;
f.GetStorage().GetNodeStatuses(countryId, nodeStatuses); f.GetStorage().GetNodeStatuses(countryId, nodeStatuses);
if (nodeStatuses.m_status != storage::NodeStatus::OnDisk) if (nodeStatuses.m_status != storage::NodeStatus::OnDisk)
@@ -302,14 +345,14 @@ using namespace storage;
return nearmeCountries.count > 0 ? [nearmeCountries copy] : nil; return nearmeCountries.count > 0 ? [nearmeCountries copy] : nil;
} }
- (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId { - (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId
auto const &s = GetFramework().GetStorage(); {
auto const & s = GetFramework().GetStorage();
Storage::UpdateInfo updateInfo; Storage::UpdateInfo updateInfo;
if (countryId.length > 0) { if (countryId.length > 0)
s.GetUpdateInfo(countryId.UTF8String, updateInfo); s.GetUpdateInfo(countryId.UTF8String, updateInfo);
} else { else
s.GetUpdateInfo(s.GetRootId(), updateInfo); s.GetUpdateInfo(s.GetRootId(), updateInfo);
}
return [[MWMMapUpdateInfo alloc] initWithUpdateInfo:updateInfo]; return [[MWMMapUpdateInfo alloc] initWithUpdateInfo:updateInfo];
} }

View File

@@ -2,12 +2,12 @@
#include "Framework.h" #include "Framework.h"
static NSString *kGuidesWasShown = @"guidesWasShown"; static NSString * kGuidesWasShown = @"guidesWasShown";
static NSString *didChangeOutdoorMapStyle = @"didChangeOutdoorMapStyle"; static NSString * didChangeOutdoorMapStyle = @"didChangeOutdoorMapStyle";
@interface MWMMapOverlayManager () @interface MWMMapOverlayManager ()
@property(nonatomic) NSHashTable<id<MWMMapOverlayManagerObserver>> *observers; @property(nonatomic) NSHashTable<id<MWMMapOverlayManagerObserver>> * observers;
@end @end
@@ -15,195 +15,197 @@ static NSString *didChangeOutdoorMapStyle = @"didChangeOutdoorMapStyle";
#pragma mark - Instance #pragma mark - Instance
+ (MWMMapOverlayManager *)manager { + (MWMMapOverlayManager *)manager
static MWMMapOverlayManager *manager; {
static MWMMapOverlayManager * manager;
static dispatch_once_t onceToken = 0; static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ manager = [[self alloc] initManager]; });
manager = [[self alloc] initManager];
});
return manager; return manager;
} }
- (instancetype)initManager { - (instancetype)initManager
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_observers = [NSHashTable weakObjectsHashTable]; _observers = [NSHashTable weakObjectsHashTable];
GetFramework().GetTrafficManager().SetStateListener([self](TrafficManager::TrafficState state) { GetFramework().GetTrafficManager().SetStateListener([self](TrafficManager::TrafficState state)
for (id<MWMMapOverlayManagerObserver> observer in self.observers) { {
if ([observer respondsToSelector:@selector(onTrafficStateUpdated)]) { for (id<MWMMapOverlayManagerObserver> observer in self.observers)
if ([observer respondsToSelector:@selector(onTrafficStateUpdated)])
[observer onTrafficStateUpdated]; [observer onTrafficStateUpdated];
}
}
}); });
GetFramework().GetTransitManager().SetStateListener([self](TransitReadManager::TransitSchemeState state) { GetFramework().GetTransitManager().SetStateListener([self](TransitReadManager::TransitSchemeState state)
for (id<MWMMapOverlayManagerObserver> observer in self.observers) { {
if ([observer respondsToSelector:@selector(onTransitStateUpdated)]) { for (id<MWMMapOverlayManagerObserver> observer in self.observers)
if ([observer respondsToSelector:@selector(onTransitStateUpdated)])
[observer onTransitStateUpdated]; [observer onTransitStateUpdated];
}
}
}); });
GetFramework().GetIsolinesManager().SetStateListener([self](IsolinesManager::IsolinesState state) { GetFramework().GetIsolinesManager().SetStateListener([self](IsolinesManager::IsolinesState state)
for (id<MWMMapOverlayManagerObserver> observer in self.observers) { {
if ([observer respondsToSelector:@selector(onIsoLinesStateUpdated)]) { for (id<MWMMapOverlayManagerObserver> observer in self.observers)
if ([observer respondsToSelector:@selector(onIsoLinesStateUpdated)])
[observer onIsoLinesStateUpdated]; [observer onIsoLinesStateUpdated];
}
}
}); });
[NSNotificationCenter.defaultCenter addObserverForName:didChangeOutdoorMapStyle object:nil queue:nil usingBlock:^(NSNotification * _Nonnull notification) { [NSNotificationCenter.defaultCenter addObserverForName:didChangeOutdoorMapStyle
for (id<MWMMapOverlayManagerObserver> observer in self.observers) { object:nil
if ([observer respondsToSelector:@selector(onOutdoorStateUpdated)]) { queue:nil
[observer onOutdoorStateUpdated]; usingBlock:^(NSNotification * _Nonnull notification) {
} for (id<MWMMapOverlayManagerObserver> observer in self.observers)
} if ([observer respondsToSelector:@selector(onOutdoorStateUpdated)])
}]; [observer onOutdoorStateUpdated];
}];
} }
return self; return self;
} }
#pragma mark - Add/Remove Observers #pragma mark - Add/Remove Observers
+ (void)addObserver:(id<MWMMapOverlayManagerObserver>)observer { + (void)addObserver:(id<MWMMapOverlayManagerObserver>)observer
{
[[MWMMapOverlayManager manager].observers addObject:observer]; [[MWMMapOverlayManager manager].observers addObject:observer];
} }
+ (void)removeObserver:(id<MWMMapOverlayManagerObserver>)observer { + (void)removeObserver:(id<MWMMapOverlayManagerObserver>)observer
{
[[MWMMapOverlayManager manager].observers removeObject:observer]; [[MWMMapOverlayManager manager].observers removeObject:observer];
} }
#pragma mark - Properties #pragma mark - Properties
+ (MWMMapOverlayTrafficState)trafficState { + (MWMMapOverlayTrafficState)trafficState
switch (GetFramework().GetTrafficManager().GetState()) { {
case TrafficManager::TrafficState::Disabled: switch (GetFramework().GetTrafficManager().GetState())
return MWMMapOverlayTrafficStateDisabled; {
case TrafficManager::TrafficState::Enabled: case TrafficManager::TrafficState::Disabled: return MWMMapOverlayTrafficStateDisabled;
return MWMMapOverlayTrafficStateEnabled; case TrafficManager::TrafficState::Enabled: return MWMMapOverlayTrafficStateEnabled;
case TrafficManager::TrafficState::WaitingData: case TrafficManager::TrafficState::WaitingData: return MWMMapOverlayTrafficStateWaitingData;
return MWMMapOverlayTrafficStateWaitingData; case TrafficManager::TrafficState::Outdated: return MWMMapOverlayTrafficStateOutdated;
case TrafficManager::TrafficState::Outdated: case TrafficManager::TrafficState::NoData: return MWMMapOverlayTrafficStateNoData;
return MWMMapOverlayTrafficStateOutdated; case TrafficManager::TrafficState::NetworkError: return MWMMapOverlayTrafficStateNetworkError;
case TrafficManager::TrafficState::NoData: case TrafficManager::TrafficState::ExpiredData: return MWMMapOverlayTrafficStateExpiredData;
return MWMMapOverlayTrafficStateNoData; case TrafficManager::TrafficState::ExpiredApp: return MWMMapOverlayTrafficStateExpiredApp;
case TrafficManager::TrafficState::NetworkError:
return MWMMapOverlayTrafficStateNetworkError;
case TrafficManager::TrafficState::ExpiredData:
return MWMMapOverlayTrafficStateExpiredData;
case TrafficManager::TrafficState::ExpiredApp:
return MWMMapOverlayTrafficStateExpiredApp;
} }
} }
+ (MWMMapOverlayTransitState)transitState { + (MWMMapOverlayTransitState)transitState
switch (GetFramework().GetTransitManager().GetState()) { {
case TransitReadManager::TransitSchemeState::Disabled: switch (GetFramework().GetTransitManager().GetState())
return MWMMapOverlayTransitStateDisabled; {
case TransitReadManager::TransitSchemeState::Enabled: case TransitReadManager::TransitSchemeState::Disabled: return MWMMapOverlayTransitStateDisabled;
return MWMMapOverlayTransitStateEnabled; case TransitReadManager::TransitSchemeState::Enabled: return MWMMapOverlayTransitStateEnabled;
case TransitReadManager::TransitSchemeState::NoData: case TransitReadManager::TransitSchemeState::NoData: return MWMMapOverlayTransitStateNoData;
return MWMMapOverlayTransitStateNoData;
} }
} }
+ (MWMMapOverlayIsolinesState)isolinesState { + (MWMMapOverlayIsolinesState)isolinesState
switch (GetFramework().GetIsolinesManager().GetState()) { {
case IsolinesManager::IsolinesState::Disabled: switch (GetFramework().GetIsolinesManager().GetState())
return MWMMapOverlayIsolinesStateDisabled; {
case IsolinesManager::IsolinesState::Enabled: case IsolinesManager::IsolinesState::Disabled: return MWMMapOverlayIsolinesStateDisabled;
return MWMMapOverlayIsolinesStateEnabled; case IsolinesManager::IsolinesState::Enabled: return MWMMapOverlayIsolinesStateEnabled;
case IsolinesManager::IsolinesState::ExpiredData: case IsolinesManager::IsolinesState::ExpiredData: return MWMMapOverlayIsolinesStateExpiredData;
return MWMMapOverlayIsolinesStateExpiredData; case IsolinesManager::IsolinesState::NoData: return MWMMapOverlayIsolinesStateNoData;
case IsolinesManager::IsolinesState::NoData:
return MWMMapOverlayIsolinesStateNoData;
} }
} }
+ (MWMMapOverlayOutdoorState)outdoorState { + (MWMMapOverlayOutdoorState)outdoorState
switch (GetFramework().GetMapStyle()) { {
case MapStyleOutdoorsLight: switch (GetFramework().GetMapStyle())
case MapStyleOutdoorsDark: {
return MWMMapOverlayOutdoorStateEnabled; case MapStyleOutdoorsLight:
default: case MapStyleOutdoorsDark: return MWMMapOverlayOutdoorStateEnabled;
return MWMMapOverlayOutdoorStateDisabled; default: return MWMMapOverlayOutdoorStateDisabled;
} }
} }
+ (BOOL)trafficEnabled { + (BOOL)trafficEnabled
{
return self.trafficState != MWMMapOverlayTrafficStateDisabled; return self.trafficState != MWMMapOverlayTrafficStateDisabled;
} }
+ (BOOL)transitEnabled { + (BOOL)transitEnabled
{
return self.transitState != MWMMapOverlayTransitStateDisabled; return self.transitState != MWMMapOverlayTransitStateDisabled;
} }
+ (BOOL)isoLinesEnabled { + (BOOL)isoLinesEnabled
{
return self.isolinesState != MWMMapOverlayIsolinesStateDisabled; return self.isolinesState != MWMMapOverlayIsolinesStateDisabled;
} }
+ (BOOL)isolinesVisible { + (BOOL)isolinesVisible
{
return GetFramework().GetIsolinesManager().IsVisible(); return GetFramework().GetIsolinesManager().IsVisible();
} }
+ (BOOL)outdoorEnabled { + (BOOL)outdoorEnabled
{
return self.outdoorState != MWMMapOverlayOutdoorStateDisabled; return self.outdoorState != MWMMapOverlayOutdoorStateDisabled;
} }
+ (void)setTrafficEnabled:(BOOL)enable { + (void)setTrafficEnabled:(BOOL)enable
if (enable) { {
if (enable)
{
[self setTransitEnabled:false]; [self setTransitEnabled:false];
[self setIsoLinesEnabled:false]; [self setIsoLinesEnabled:false];
} }
auto &f = GetFramework(); auto & f = GetFramework();
f.GetTrafficManager().SetEnabled(enable); f.GetTrafficManager().SetEnabled(enable);
f.SaveTrafficEnabled(enable); f.SaveTrafficEnabled(enable);
} }
+ (void)setTransitEnabled:(BOOL)enable { + (void)setTransitEnabled:(BOOL)enable
if (enable) { {
if (enable)
{
[self setTrafficEnabled:!enable]; [self setTrafficEnabled:!enable];
[self setIsoLinesEnabled:false]; [self setIsoLinesEnabled:false];
[self setOutdoorEnabled:false]; [self setOutdoorEnabled:false];
} }
auto &f = GetFramework(); auto & f = GetFramework();
f.GetTransitManager().EnableTransitSchemeMode(enable); f.GetTransitManager().EnableTransitSchemeMode(enable);
f.SaveTransitSchemeEnabled(enable); f.SaveTransitSchemeEnabled(enable);
} }
+ (void)setIsoLinesEnabled:(BOOL)enable { + (void)setIsoLinesEnabled:(BOOL)enable
if (enable) { {
if (enable)
{
[self setTrafficEnabled:false]; [self setTrafficEnabled:false];
[self setTransitEnabled:false]; [self setTransitEnabled:false];
} }
auto &f = GetFramework(); auto & f = GetFramework();
f.GetIsolinesManager().SetEnabled(enable); f.GetIsolinesManager().SetEnabled(enable);
f.SaveIsolinesEnabled(enable); f.SaveIsolinesEnabled(enable);
} }
+ (void)setOutdoorEnabled:(BOOL)enable { + (void)setOutdoorEnabled:(BOOL)enable
if (enable) { {
if (enable)
{
[self setTransitEnabled:false]; [self setTransitEnabled:false];
[self setTrafficEnabled:false]; [self setTrafficEnabled:false];
} }
auto &f = GetFramework(); auto & f = GetFramework();
switch (f.GetMapStyle()) { switch (f.GetMapStyle())
case MapStyleDefaultLight: {
case MapStyleVehicleLight: case MapStyleDefaultLight:
case MapStyleOutdoorsLight: case MapStyleVehicleLight:
f.SetMapStyle(enable ? MapStyleOutdoorsLight : MapStyleDefaultLight); case MapStyleOutdoorsLight: f.SetMapStyle(enable ? MapStyleOutdoorsLight : MapStyleDefaultLight); break;
break; case MapStyleDefaultDark:
case MapStyleDefaultDark: case MapStyleVehicleDark:
case MapStyleVehicleDark: case MapStyleOutdoorsDark: f.SetMapStyle(enable ? MapStyleOutdoorsDark : MapStyleDefaultDark); break;
case MapStyleOutdoorsDark: default: break;
f.SetMapStyle(enable ? MapStyleOutdoorsDark : MapStyleDefaultDark);
break;
default:
break;
} }
// TODO: - Observing for the selected/deselected state of the Outdoor style should be implemented not by NSNotificationCenter but the same way as for IsoLines with 'GetFramework().GetIsolinesManager().SetStateListener'. // TODO: - Observing for the selected/deselected state of the Outdoor style should be implemented not by
// NSNotificationCenter but the same way as for IsoLines with 'GetFramework().GetIsolinesManager().SetStateListener'.
[NSNotificationCenter.defaultCenter postNotificationName:didChangeOutdoorMapStyle object:nil]; [NSNotificationCenter.defaultCenter postNotificationName:didChangeOutdoorMapStyle object:nil];
} }

View File

@@ -3,6 +3,9 @@
@implementation CLLocation (Mercator) @implementation CLLocation (Mercator)
- (m2::PointD)mercator { return location_helpers::ToMercator(self.coordinate); } - (m2::PointD)mercator
{
return location_helpers::ToMercator(self.coordinate);
}
@end @end

View File

@@ -11,23 +11,26 @@
#include "platform/localization.hpp" #include "platform/localization.hpp"
@interface MWMCarPlaySearchResultObject() @interface MWMCarPlaySearchResultObject ()
@property(assign, nonatomic, readwrite) NSInteger originalRow; @property(assign, nonatomic, readwrite) NSInteger originalRow;
@property(strong, nonatomic, readwrite) NSString *title; @property(strong, nonatomic, readwrite) NSString * title;
@property(strong, nonatomic, readwrite) NSString *address; @property(strong, nonatomic, readwrite) NSString * address;
@property(assign, nonatomic, readwrite) CLLocationCoordinate2D coordinate; @property(assign, nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property(assign, nonatomic, readwrite) CGPoint mercatorPoint; @property(assign, nonatomic, readwrite) CGPoint mercatorPoint;
@end @end
@implementation MWMCarPlaySearchResultObject @implementation MWMCarPlaySearchResultObject
- (instancetype)initForRow:(NSInteger)row { - (instancetype)initForRow:(NSInteger)row
{
self = [super init]; self = [super init];
if (self) { if (self)
{
self.originalRow = row; self.originalRow = row;
NSInteger containerIndex = [MWMSearch containerIndexWithRow:row]; NSInteger containerIndex = [MWMSearch containerIndexWithRow:row];
SearchItemType type = [MWMSearch resultTypeWithRow:row]; SearchItemType type = [MWMSearch resultTypeWithRow:row];
if (type == SearchItemTypeRegular) { if (type == SearchItemTypeRegular)
{
auto const & result = [MWMSearch resultWithContainerIndex:containerIndex]; auto const & result = [MWMSearch resultWithContainerIndex:containerIndex];
self.title = result.titleText; self.title = result.titleText;
self.address = result.addressText; self.address = result.addressText;

View File

@@ -5,19 +5,22 @@
#import "SwiftBridge.h" #import "SwiftBridge.h"
API_AVAILABLE(ios(12.0)) API_AVAILABLE(ios(12.0))
@interface MWMCarPlaySearchService ()<MWMSearchObserver> @interface MWMCarPlaySearchService () <MWMSearchObserver>
@property(strong, nonatomic, nullable) void (^completionHandler)(NSArray<MWMCarPlaySearchResultObject *> *searchResults); @property(strong, nonatomic, nullable) void (^completionHandler)
@property(strong, nonatomic, nullable) NSString *lastQuery; (NSArray<MWMCarPlaySearchResultObject *> * searchResults);
@property(strong, nonatomic, nullable) NSString *inputLocale; @property(strong, nonatomic, nullable) NSString * lastQuery;
@property(strong, nonatomic, readwrite) NSArray<MWMCarPlaySearchResultObject *> *lastResults; @property(strong, nonatomic, nullable) NSString * inputLocale;
@property(strong, nonatomic, readwrite) NSArray<MWMCarPlaySearchResultObject *> * lastResults;
@end @end
@implementation MWMCarPlaySearchService @implementation MWMCarPlaySearchService
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
{
[MWMSearch addObserver:self]; [MWMSearch addObserver:self];
self.lastResults = @[]; self.lastResults = @[];
} }
@@ -25,8 +28,9 @@ API_AVAILABLE(ios(12.0))
} }
- (void)searchText:(NSString *)text - (void)searchText:(NSString *)text
forInputLocale:(NSString *)inputLocale forInputLocale:(NSString *)inputLocale
completionHandler:(void (^)(NSArray<MWMCarPlaySearchResultObject *> *searchResults))completionHandler { completionHandler:(void (^)(NSArray<MWMCarPlaySearchResultObject *> * searchResults))completionHandler
{
self.lastQuery = text; self.lastQuery = text;
self.inputLocale = inputLocale; self.inputLocale = inputLocale;
self.lastResults = @[]; self.lastResults = @[];
@@ -36,26 +40,34 @@ API_AVAILABLE(ios(12.0))
[MWMSearch searchQuery:query]; [MWMSearch searchQuery:query];
} }
- (void)saveLastQuery { - (void)saveLastQuery
if (self.lastQuery != nil && self.inputLocale != nil) { {
SearchQuery * query = [[SearchQuery alloc] init:self.lastQuery locale:self.inputLocale source:SearchTextSourceTypedText]; if (self.lastQuery != nil && self.inputLocale != nil)
{
SearchQuery * query = [[SearchQuery alloc] init:self.lastQuery
locale:self.inputLocale
source:SearchTextSourceTypedText];
[MWMSearch saveQuery:query]; [MWMSearch saveQuery:query];
} }
} }
#pragma mark - MWMSearchObserver #pragma mark - MWMSearchObserver
- (void)onSearchCompleted { - (void)onSearchCompleted
void (^completionHandler)(NSArray<MWMCarPlaySearchResultObject *> *searchResults) = self.completionHandler; {
if (completionHandler == nil) { return; } void (^completionHandler)(NSArray<MWMCarPlaySearchResultObject *> * searchResults) = self.completionHandler;
if (completionHandler == nil)
NSMutableArray<MWMCarPlaySearchResultObject *> *results = [NSMutableArray array]; return;
NSMutableArray<MWMCarPlaySearchResultObject *> * results = [NSMutableArray array];
NSInteger count = [MWMSearch resultsCount]; NSInteger count = [MWMSearch resultsCount];
for (NSInteger row = 0; row < count; row++) { for (NSInteger row = 0; row < count; row++)
MWMCarPlaySearchResultObject *result = [[MWMCarPlaySearchResultObject alloc] initForRow:row]; {
if (result != nil) { [results addObject:result]; } MWMCarPlaySearchResultObject * result = [[MWMCarPlaySearchResultObject alloc] initForRow:row];
if (result != nil)
[results addObject:result];
} }
self.lastResults = results; self.lastResults = results;
completionHandler(results); completionHandler(results);
self.completionHandler = nil; self.completionHandler = nil;

View File

@@ -6,7 +6,7 @@
@property(copy, nonatomic) MWMVoidBlock doneBlock; @property(copy, nonatomic) MWMVoidBlock doneBlock;
@property(copy, nonatomic) MWMVoidBlock cancelBlock; @property(copy, nonatomic) MWMVoidBlock cancelBlock;
@property(assign, nonatomic) NSLayoutConstraint* topConstraint; @property(assign, nonatomic) NSLayoutConstraint * topConstraint;
@end @end
@@ -24,7 +24,7 @@
navBar.doneBlock = done; navBar.doneBlock = done;
navBar.cancelBlock = cancel; navBar.cancelBlock = cancel;
navBar.translatesAutoresizingMaskIntoConstraints = false; navBar.translatesAutoresizingMaskIntoConstraints = false;
[superview addSubview:navBar]; [superview addSubview:navBar];
navBar.topConstraint = [navBar.topAnchor constraintEqualToAnchor:superview.topAnchor]; navBar.topConstraint = [navBar.topAnchor constraintEqualToAnchor:superview.topAnchor];
navBar.topConstraint.active = true; navBar.topConstraint.active = true;
@@ -40,10 +40,7 @@
f.EnableChoosePositionMode(true /* enable */, enableBounds, optionalPosition); f.EnableChoosePositionMode(true /* enable */, enableBounds, optionalPosition);
f.BlockTapEvents(true); f.BlockTapEvents(true);
[UIView animateWithDuration:kDefaultAnimationDuration animations:^ [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ self.topConstraint.constant = 0; }];
{
self.topConstraint.constant = 0;
}];
} }
- (void)dismissWithBlock:(MWMVoidBlock)block - (void)dismissWithBlock:(MWMVoidBlock)block
@@ -52,15 +49,12 @@
f.EnableChoosePositionMode(false /* enable */, false /* enableBounds */, nullptr /* optionalPosition */); f.EnableChoosePositionMode(false /* enable */, false /* enableBounds */, nullptr /* optionalPosition */);
f.BlockTapEvents(false); f.BlockTapEvents(false);
[UIView animateWithDuration:kDefaultAnimationDuration animations:^ [UIView animateWithDuration:kDefaultAnimationDuration
{ animations:^{ self.topConstraint.constant = -self.height; }
self.topConstraint.constant = -self.height; completion:^(BOOL finished) {
} [self removeFromSuperview];
completion:^(BOOL finished) block();
{ }];
[self removeFromSuperview];
block();
}];
} }
- (IBAction)doneTap - (IBAction)doneTap

View File

@@ -6,24 +6,26 @@
#import "MapsAppDelegate.h" #import "MapsAppDelegate.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"; static NSString * const kAlertControllerNibIdentifier = @"MWMAlertViewController";
@interface MWMAlertViewController () <UIGestureRecognizerDelegate> @interface MWMAlertViewController () <UIGestureRecognizerDelegate>
@property(weak, nonatomic, readwrite) UIViewController *ownerViewController; @property(weak, nonatomic, readwrite) UIViewController * ownerViewController;
@end @end
@implementation MWMAlertViewController @implementation MWMAlertViewController
+ (nonnull MWMAlertViewController *)activeAlertController { + (nonnull MWMAlertViewController *)activeAlertController
UIViewController *tvc = [MapViewController sharedController]; {
UIViewController * tvc = [MapViewController sharedController];
ASSERT([tvc conformsToProtocol:@protocol(MWMController)], ()); ASSERT([tvc conformsToProtocol:@protocol(MWMController)], ());
UIViewController<MWMController> *mwmController = static_cast<UIViewController<MWMController> *>(tvc); UIViewController<MWMController> * mwmController = static_cast<UIViewController<MWMController> *>(tvc);
return mwmController.alertController; return mwmController.alertController;
} }
- (nonnull instancetype)initWithViewController:(nonnull UIViewController *)viewController { - (nonnull instancetype)initWithViewController:(nonnull UIViewController *)viewController
{
self = [super initWithNibName:kAlertControllerNibIdentifier bundle:nil]; self = [super initWithNibName:kAlertControllerNibIdentifier bundle:nil];
if (self) if (self)
_ownerViewController = viewController; _ownerViewController = viewController;
@@ -31,53 +33,63 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
} }
- (void)viewWillTransitionToSize:(CGSize)size - (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
auto const orient = size.width > size.height ? UIInterfaceOrientationLandscapeLeft : UIInterfaceOrientationPortrait; auto const orient = size.width > size.height ? UIInterfaceOrientationLandscapeLeft : UIInterfaceOrientationPortrait;
[coordinator [coordinator
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
for (MWMAlert *alert in self.view.subviews) for (MWMAlert * alert in self.view.subviews)
[alert rotate:orient duration:context.transitionDuration]; [alert rotate:orient duration:context.transitionDuration];
} }
completion:^(id<UIViewControllerTransitionCoordinatorContext> context){ completion:^(id<UIViewControllerTransitionCoordinatorContext> context){}];
}];
} }
#pragma mark - Actions #pragma mark - Actions
- (void)presentLocationAlertWithCancelBlock:(MWMVoidBlock)cancelBlock { - (void)presentLocationAlertWithCancelBlock:(MWMVoidBlock)cancelBlock
{
[self displayAlert:[MWMAlert locationAlertWithCancelBlock:cancelBlock]]; [self displayAlert:[MWMAlert locationAlertWithCancelBlock:cancelBlock]];
} }
- (void)presentPoint2PointAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock needToRebuild:(BOOL)needToRebuild { - (void)presentPoint2PointAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock needToRebuild:(BOOL)needToRebuild
{
[self displayAlert:[MWMAlert point2PointAlertWithOkBlock:okBlock needToRebuild:needToRebuild]]; [self displayAlert:[MWMAlert point2PointAlertWithOkBlock:okBlock needToRebuild:needToRebuild]];
} }
- (void)presentLocationServiceNotSupportedAlert { - (void)presentLocationServiceNotSupportedAlert
{
[self displayAlert:[MWMAlert locationServiceNotSupportedAlert]]; [self displayAlert:[MWMAlert locationServiceNotSupportedAlert]];
} }
- (void)presentNoConnectionAlert { - (void)presentNoConnectionAlert
{
[self displayAlert:[MWMAlert noConnectionAlert]]; [self displayAlert:[MWMAlert noConnectionAlert]];
} }
- (void)presentDeleteMapProhibitedAlert { - (void)presentDeleteMapProhibitedAlert
{
[self displayAlert:[MWMAlert deleteMapProhibitedAlert]]; [self displayAlert:[MWMAlert deleteMapProhibitedAlert]];
} }
- (void)presentUnsavedEditsAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock { - (void)presentUnsavedEditsAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock
{
[self displayAlert:[MWMAlert unsavedEditsAlertWithOkBlock:okBlock]]; [self displayAlert:[MWMAlert unsavedEditsAlertWithOkBlock:okBlock]];
} }
- (void)presentNoWiFiAlertWithOkBlock:(nullable MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock { - (void)presentNoWiFiAlertWithOkBlock:(nullable MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock
{
[self displayAlert:[MWMAlert noWiFiAlertWithOkBlock:okBlock andCancelBlock:cancelBlock]]; [self displayAlert:[MWMAlert noWiFiAlertWithOkBlock:okBlock andCancelBlock:cancelBlock]];
} }
- (void)presentIncorrectFeauturePositionAlert { - (void)presentIncorrectFeauturePositionAlert
{
[self displayAlert:[MWMAlert incorrectFeaturePositionAlert]]; [self displayAlert:[MWMAlert incorrectFeaturePositionAlert]];
} }
- (void)presentNotEnoughSpaceAlert { - (void)presentNotEnoughSpaceAlert
{
[self displayAlert:[MWMAlert notEnoughSpaceAlert]]; [self displayAlert:[MWMAlert notEnoughSpaceAlert]];
} }
- (void)presentInvalidUserNameOrPasswordAlert { - (void)presentInvalidUserNameOrPasswordAlert
{
[self displayAlert:[MWMAlert invalidUserNameOrPasswordAlert]]; [self displayAlert:[MWMAlert invalidUserNameOrPasswordAlert]];
} }
@@ -85,7 +97,8 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
code:(routing::RouterResultCode)code code:(routing::RouterResultCode)code
cancelBlock:(MWMVoidBlock)cancelBlock cancelBlock:(MWMVoidBlock)cancelBlock
downloadBlock:(MWMDownloadBlock)downloadBlock downloadBlock:(MWMDownloadBlock)downloadBlock
downloadCompleteBlock:(MWMVoidBlock)downloadCompleteBlock { downloadCompleteBlock:(MWMVoidBlock)downloadCompleteBlock
{
[self displayAlert:[MWMAlert downloaderAlertWithAbsentCountries:countries [self displayAlert:[MWMAlert downloaderAlertWithAbsentCountries:countries
code:code code:code
cancelBlock:cancelBlock cancelBlock:cancelBlock
@@ -93,95 +106,113 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
downloadCompleteBlock:downloadCompleteBlock]]; downloadCompleteBlock:downloadCompleteBlock]];
} }
- (void)presentRoutingDisclaimerAlertWithOkBlock:(MWMVoidBlock)block { - (void)presentRoutingDisclaimerAlertWithOkBlock:(MWMVoidBlock)block
{
[self displayAlert:[MWMAlert routingDisclaimerAlertWithOkBlock:block]]; [self displayAlert:[MWMAlert routingDisclaimerAlertWithOkBlock:block]];
} }
- (void)presentDisabledLocationAlert { - (void)presentDisabledLocationAlert
{
[self displayAlert:[MWMAlert disabledLocationAlert]]; [self displayAlert:[MWMAlert disabledLocationAlert]];
} }
- (void)presentLocationServicesDisabledAlert; { - (void)presentLocationServicesDisabledAlert;
{
[self displayAlert:[MWMAlert locationServicesDisabledAlert]]; [self displayAlert:[MWMAlert locationServicesDisabledAlert]];
} }
- (void)presentAlert:(routing::RouterResultCode)type { - (void)presentAlert:(routing::RouterResultCode)type
{
[self displayAlert:[MWMAlert alert:type]]; [self displayAlert:[MWMAlert alert:type]];
} }
- (void)presentDownloaderNoConnectionAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock - (void)presentDownloaderNoConnectionAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock
cancelBlock:(nonnull MWMVoidBlock)cancelBlock { cancelBlock:(nonnull MWMVoidBlock)cancelBlock
{
[self displayAlert:[MWMAlert downloaderNoConnectionAlertWithOkBlock:okBlock cancelBlock:cancelBlock]]; [self displayAlert:[MWMAlert downloaderNoConnectionAlertWithOkBlock:okBlock cancelBlock:cancelBlock]];
} }
- (void)presentDownloaderNotEnoughSpaceAlert { - (void)presentDownloaderNotEnoughSpaceAlert
{
[self displayAlert:[MWMAlert downloaderNotEnoughSpaceAlert]]; [self displayAlert:[MWMAlert downloaderNotEnoughSpaceAlert]];
} }
- (void)presentDownloaderInternalErrorAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock - (void)presentDownloaderInternalErrorAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock
cancelBlock:(nonnull MWMVoidBlock)cancelBlock { cancelBlock:(nonnull MWMVoidBlock)cancelBlock
{
[self displayAlert:[MWMAlert downloaderInternalErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]]; [self displayAlert:[MWMAlert downloaderInternalErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]];
} }
- (void)presentPlaceDoesntExistAlertWithBlock:(MWMStringBlock)block { - (void)presentPlaceDoesntExistAlertWithBlock:(MWMStringBlock)block
{
[self displayAlert:[MWMAlert placeDoesntExistAlertWithBlock:block]]; [self displayAlert:[MWMAlert placeDoesntExistAlertWithBlock:block]];
} }
- (void)presentResetChangesAlertWithBlock:(MWMVoidBlock)block { - (void)presentResetChangesAlertWithBlock:(MWMVoidBlock)block
{
[self displayAlert:[MWMAlert resetChangesAlertWithBlock:block]]; [self displayAlert:[MWMAlert resetChangesAlertWithBlock:block]];
} }
- (void)presentDeleteFeatureAlertWithBlock:(MWMVoidBlock)block { - (void)presentDeleteFeatureAlertWithBlock:(MWMVoidBlock)block
{
[self displayAlert:[MWMAlert deleteFeatureAlertWithBlock:block]]; [self displayAlert:[MWMAlert deleteFeatureAlertWithBlock:block]];
} }
- (void)presentPersonalInfoWarningAlertWithBlock:(nonnull MWMVoidBlock)block { - (void)presentPersonalInfoWarningAlertWithBlock:(nonnull MWMVoidBlock)block
{
[self displayAlert:[MWMAlert personalInfoWarningAlertWithBlock:block]]; [self displayAlert:[MWMAlert personalInfoWarningAlertWithBlock:block]];
} }
- (void)presentTrackWarningAlertWithCancelBlock:(nonnull MWMVoidBlock)block { - (void)presentTrackWarningAlertWithCancelBlock:(nonnull MWMVoidBlock)block
{
[self displayAlert:[MWMAlert trackWarningAlertWithCancelBlock:block]]; [self displayAlert:[MWMAlert trackWarningAlertWithCancelBlock:block]];
} }
- (void)presentMobileInternetAlertWithBlock:(nonnull MWMMobileInternetAlertCompletionBlock)block { - (void)presentMobileInternetAlertWithBlock:(nonnull MWMMobileInternetAlertCompletionBlock)block
{
[self displayAlert:[MWMMobileInternetAlert alertWithBlock:block]]; [self displayAlert:[MWMMobileInternetAlert alertWithBlock:block]];
} }
- (void)presentInfoAlert:(nonnull NSString *)title text:(nonnull NSString *)text { - (void)presentInfoAlert:(nonnull NSString *)title text:(nonnull NSString *)text
{
[self displayAlert:[MWMAlert infoAlert:title text:text]]; [self displayAlert:[MWMAlert infoAlert:title text:text]];
} }
- (void)presentInfoAlert:(nonnull NSString *)title { - (void)presentInfoAlert:(nonnull NSString *)title
{
[self displayAlert:[MWMAlert infoAlert:title text:nil]]; [self displayAlert:[MWMAlert infoAlert:title text:nil]];
} }
- (void)presentCreateBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max - (void)presentCreateBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min minCharacterNum:(NSUInteger)min
callback:(nonnull MWMCheckStringBlock)callback { callback:(nonnull MWMCheckStringBlock)callback
{
auto alert = auto alert =
static_cast<MWMBCCreateCategoryAlert *>([MWMAlert createBookmarkCategoryAlertWithMaxCharacterNum:max static_cast<MWMBCCreateCategoryAlert *>([MWMAlert createBookmarkCategoryAlertWithMaxCharacterNum:max
minCharacterNum:min minCharacterNum:min
callback:callback]); callback:callback]);
[self displayAlert:alert]; [self displayAlert:alert];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [alert.textField becomeFirstResponder]; });
[alert.textField becomeFirstResponder];
});
} }
- (void)presentSpinnerAlertWithTitle:(nonnull NSString *)title cancel:(nullable MWMVoidBlock)cancel { - (void)presentSpinnerAlertWithTitle:(nonnull NSString *)title cancel:(nullable MWMVoidBlock)cancel
{
[self displayAlert:[MWMAlert spinnerAlertWithTitle:title cancel:cancel]]; [self displayAlert:[MWMAlert spinnerAlertWithTitle:title cancel:cancel]];
} }
- (void)presentBookmarkConversionErrorAlert { - (void)presentBookmarkConversionErrorAlert
{
[self displayAlert:[MWMAlert bookmarkConversionErrorAlert]]; [self displayAlert:[MWMAlert bookmarkConversionErrorAlert]];
} }
- (void)presentTagsLoadingErrorAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock - (void)presentTagsLoadingErrorAlertWithOkBlock:(nonnull MWMVoidBlock)okBlock
cancelBlock:(nonnull MWMVoidBlock)cancelBlock { cancelBlock:(nonnull MWMVoidBlock)cancelBlock
{
[self displayAlert:[MWMAlert tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]]; [self displayAlert:[MWMAlert tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]];
} }
- (void)presentBugReportAlertWithTitle:(nonnull NSString *)title { - (void)presentBugReportAlertWithTitle:(nonnull NSString *)title
{
[self displayAlert:[MWMAlert bugReportAlertWithTitle:title]]; [self displayAlert:[MWMAlert bugReportAlertWithTitle:title]];
} }
@@ -189,7 +220,8 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
message:(nullable NSString *)message message:(nullable NSString *)message
rightButtonTitle:(nonnull NSString *)rightButtonTitle rightButtonTitle:(nonnull NSString *)rightButtonTitle
leftButtonTitle:(nullable NSString *)leftButtonTitle leftButtonTitle:(nullable NSString *)leftButtonTitle
rightButtonAction:(nullable MWMVoidBlock)action { rightButtonAction:(nullable MWMVoidBlock)action
{
[self displayAlert:[MWMAlert defaultAlertWithTitle:title [self displayAlert:[MWMAlert defaultAlertWithTitle:title
message:message message:message
rightButtonTitle:rightButtonTitle rightButtonTitle:rightButtonTitle
@@ -197,46 +229,44 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
rightButtonAction:action]]; rightButtonAction:action]];
} }
- (void)displayAlert:(MWMAlert *)alert { - (void)displayAlert:(MWMAlert *)alert
UIViewController *ownerVC = self.ownerViewController; {
if (ownerVC.navigationController != nil) { UIViewController * ownerVC = self.ownerViewController;
if (ownerVC.navigationController != nil)
ownerVC = ownerVC.navigationController; ownerVC = ownerVC.navigationController;
}
BOOL isOwnerLoaded = ownerVC.isViewLoaded; BOOL isOwnerLoaded = ownerVC.isViewLoaded;
if (!isOwnerLoaded) { if (!isOwnerLoaded)
return; return;
}
// TODO(igrechuhin): Remove this check on location manager refactoring. // TODO(igrechuhin): Remove this check on location manager refactoring.
// Workaround for current location manager duplicate error alerts. // Workaround for current location manager duplicate error alerts.
if ([alert isKindOfClass:[MWMLocationAlert class]]) { if ([alert isKindOfClass:[MWMLocationAlert class]])
for (MWMAlert *view in self.view.subviews) { {
for (MWMAlert * view in self.view.subviews)
if ([view isKindOfClass:[MWMLocationAlert class]]) if ([view isKindOfClass:[MWMLocationAlert class]])
return; return;
}
} }
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
delay:0 delay:0
options:UIViewAnimationOptionBeginFromCurrentState options:UIViewAnimationOptionBeginFromCurrentState
animations:^{ animations:^{
for (MWMAlert *view in self.view.subviews) { for (MWMAlert * view in self.view.subviews)
if (view != alert) if (view != alert)
view.alpha = 0.0; view.alpha = 0.0;
}
} }
completion:nil]; completion:nil];
[self willMoveToParentViewController:NULL]; [self willMoveToParentViewController:NULL];
[self.view removeFromSuperview]; [self.view removeFromSuperview];
[self removeFromParentViewController]; [self removeFromParentViewController];
alert.alertController = self; alert.alertController = self;
[ownerVC addChildViewController:self]; [ownerVC addChildViewController:self];
self.view.frame = CGRectMake(0, 0, ownerVC.view.frame.size.width, ownerVC.view.frame.size.height); self.view.frame = CGRectMake(0, 0, ownerVC.view.frame.size.width, ownerVC.view.frame.size.height);
[ownerVC.view addSubview:self.view]; [ownerVC.view addSubview:self.view];
[self didMoveToParentViewController:ownerVC]; [self didMoveToParentViewController:ownerVC];
alert.alpha = 0.; alert.alpha = 0.;
[self.view addSubview:alert]; [self.view addSubview:alert];
CGFloat const scale = 1.1; CGFloat const scale = 1.1;
@@ -250,29 +280,31 @@ static NSString *const kAlertControllerNibIdentifier = @"MWMAlertViewController"
[[MapsAppDelegate theApp].window endEditing:YES]; [[MapsAppDelegate theApp].window endEditing:YES];
} }
- (void)closeAlert:(nullable MWMVoidBlock)completion { - (void)closeAlert:(nullable MWMVoidBlock)completion
NSArray *subviews = self.view.subviews; {
MWMAlert *closeAlert = subviews.lastObject; NSArray * subviews = self.view.subviews;
MWMAlert *showAlert = (subviews.count >= 2 ? subviews[subviews.count - 2] : nil); MWMAlert * closeAlert = subviews.lastObject;
MWMAlert * showAlert = (subviews.count >= 2 ? subviews[subviews.count - 2] : nil);
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
delay:0 delay:0
options:UIViewAnimationOptionBeginFromCurrentState options:UIViewAnimationOptionBeginFromCurrentState
animations:^{ animations:^{
closeAlert.alpha = 0.; closeAlert.alpha = 0.;
if (showAlert) if (showAlert)
showAlert.alpha = 1.; showAlert.alpha = 1.;
else else
self.view.alpha = 0.; self.view.alpha = 0.;
}
completion:^(BOOL finished) {
[closeAlert removeFromSuperview];
if (!showAlert) {
[self.view removeFromSuperview];
[self removeFromParentViewController];
} }
if (completion) completion:^(BOOL finished) {
completion(); [closeAlert removeFromSuperview];
}]; if (!showAlert)
{
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
if (completion)
completion();
}];
} }
@end @end

View File

@@ -10,42 +10,52 @@
@implementation MWMAlert @implementation MWMAlert
+ (MWMAlert *)locationAlertWithCancelBlock:(MWMVoidBlock)cancelBlock { + (MWMAlert *)locationAlertWithCancelBlock:(MWMVoidBlock)cancelBlock
{
return [MWMLocationAlert alertWithCancelBlock:cancelBlock]; return [MWMLocationAlert alertWithCancelBlock:cancelBlock];
} }
+ (MWMAlert *)point2PointAlertWithOkBlock:(MWMVoidBlock)block needToRebuild:(BOOL)needToRebuild { + (MWMAlert *)point2PointAlertWithOkBlock:(MWMVoidBlock)block needToRebuild:(BOOL)needToRebuild
{
return [MWMDefaultAlert point2PointAlertWithOkBlock:block needToRebuild:needToRebuild]; return [MWMDefaultAlert point2PointAlertWithOkBlock:block needToRebuild:needToRebuild];
} }
+ (MWMAlert *)routingDisclaimerAlertWithOkBlock:(MWMVoidBlock)block { + (MWMAlert *)routingDisclaimerAlertWithOkBlock:(MWMVoidBlock)block
{
return [MWMRoutingDisclaimerAlert alertWithOkBlock:block]; return [MWMRoutingDisclaimerAlert alertWithOkBlock:block];
} }
+ (MWMAlert *)disabledLocationAlert { + (MWMAlert *)disabledLocationAlert
{
return [MWMDefaultAlert disabledLocationAlert]; return [MWMDefaultAlert disabledLocationAlert];
} }
+ (MWMAlert *)locationServicesDisabledAlert { + (MWMAlert *)locationServicesDisabledAlert
{
return [LocationServicesDisabledAlert alert]; return [LocationServicesDisabledAlert alert];
} }
+ (MWMAlert *)noWiFiAlertWithOkBlock:(MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock { + (MWMAlert *)noWiFiAlertWithOkBlock:(MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock
{
return [MWMDefaultAlert noWiFiAlertWithOkBlock:okBlock andCancelBlock:cancelBlock]; return [MWMDefaultAlert noWiFiAlertWithOkBlock:okBlock andCancelBlock:cancelBlock];
} }
+ (MWMAlert *)noConnectionAlert { + (MWMAlert *)noConnectionAlert
{
return [MWMDefaultAlert noConnectionAlert]; return [MWMDefaultAlert noConnectionAlert];
} }
+ (MWMAlert *)deleteMapProhibitedAlert { + (MWMAlert *)deleteMapProhibitedAlert
{
return [MWMDefaultAlert deleteMapProhibitedAlert]; return [MWMDefaultAlert deleteMapProhibitedAlert];
} }
+ (MWMAlert *)unsavedEditsAlertWithOkBlock:(MWMVoidBlock)okBlock { + (MWMAlert *)unsavedEditsAlertWithOkBlock:(MWMVoidBlock)okBlock
{
return [MWMDefaultAlert unsavedEditsAlertWithOkBlock:okBlock]; return [MWMDefaultAlert unsavedEditsAlertWithOkBlock:okBlock];
} }
+ (MWMAlert *)locationServiceNotSupportedAlert { + (MWMAlert *)locationServiceNotSupportedAlert
{
return [MWMDefaultAlert locationServiceNotSupportedAlert]; return [MWMDefaultAlert locationServiceNotSupportedAlert];
} }
@@ -53,7 +63,8 @@
code:(routing::RouterResultCode)code code:(routing::RouterResultCode)code
cancelBlock:(MWMVoidBlock)cancelBlock cancelBlock:(MWMVoidBlock)cancelBlock
downloadBlock:(MWMDownloadBlock)downloadBlock downloadBlock:(MWMDownloadBlock)downloadBlock
downloadCompleteBlock:(MWMVoidBlock)downloadCompleteBlock { downloadCompleteBlock:(MWMVoidBlock)downloadCompleteBlock
{
return [MWMDownloadTransitMapAlert downloaderAlertWithMaps:countries return [MWMDownloadTransitMapAlert downloaderAlertWithMaps:countries
code:code code:code
cancelBlock:cancelBlock cancelBlock:cancelBlock
@@ -61,105 +72,115 @@
downloadCompleteBlock:downloadCompleteBlock]; downloadCompleteBlock:downloadCompleteBlock];
} }
+ (MWMAlert *)alert:(routing::RouterResultCode)type { + (MWMAlert *)alert:(routing::RouterResultCode)type
switch (type) { {
case routing::RouterResultCode::NoCurrentPosition: switch (type)
return [MWMDefaultAlert noCurrentPositionAlert]; {
case routing::RouterResultCode::StartPointNotFound: case routing::RouterResultCode::NoCurrentPosition: return [MWMDefaultAlert noCurrentPositionAlert];
return [MWMDefaultAlert startPointNotFoundAlert]; case routing::RouterResultCode::StartPointNotFound: return [MWMDefaultAlert startPointNotFoundAlert];
case routing::RouterResultCode::EndPointNotFound: case routing::RouterResultCode::EndPointNotFound: return [MWMDefaultAlert endPointNotFoundAlert];
return [MWMDefaultAlert endPointNotFoundAlert]; case routing::RouterResultCode::PointsInDifferentMWM: return [MWMDefaultAlert pointsInDifferentMWMAlert];
case routing::RouterResultCode::PointsInDifferentMWM: case routing::RouterResultCode::TransitRouteNotFoundNoNetwork:
return [MWMDefaultAlert pointsInDifferentMWMAlert]; return [MWMDefaultAlert routeNotFoundNoPublicTransportAlert];
case routing::RouterResultCode::TransitRouteNotFoundNoNetwork: case routing::RouterResultCode::TransitRouteNotFoundTooLongPedestrian:
return [MWMDefaultAlert routeNotFoundNoPublicTransportAlert]; return [MWMDefaultAlert routeNotFoundTooLongPedestrianAlert];
case routing::RouterResultCode::TransitRouteNotFoundTooLongPedestrian: case routing::RouterResultCode::RouteNotFoundRedressRouteError:
return [MWMDefaultAlert routeNotFoundTooLongPedestrianAlert]; case routing::RouterResultCode::RouteNotFound:
case routing::RouterResultCode::RouteNotFoundRedressRouteError: case routing::RouterResultCode::InconsistentMWMandRoute: return [MWMDefaultAlert routeNotFoundAlert];
case routing::RouterResultCode::RouteNotFound: case routing::RouterResultCode::RouteFileNotExist:
case routing::RouterResultCode::InconsistentMWMandRoute: case routing::RouterResultCode::FileTooOld: return [MWMDefaultAlert routeFileNotExistAlert];
return [MWMDefaultAlert routeNotFoundAlert]; case routing::RouterResultCode::InternalError: return [MWMDefaultAlert internalRoutingErrorAlert];
case routing::RouterResultCode::RouteFileNotExist: case routing::RouterResultCode::Cancelled:
case routing::RouterResultCode::FileTooOld: case routing::RouterResultCode::NoError:
return [MWMDefaultAlert routeFileNotExistAlert]; case routing::RouterResultCode::HasWarnings:
case routing::RouterResultCode::InternalError: case routing::RouterResultCode::NeedMoreMaps: return nil;
return [MWMDefaultAlert internalRoutingErrorAlert]; case routing::RouterResultCode::IntermediatePointNotFound: return [MWMDefaultAlert intermediatePointNotFoundAlert];
case routing::RouterResultCode::Cancelled:
case routing::RouterResultCode::NoError:
case routing::RouterResultCode::HasWarnings:
case routing::RouterResultCode::NeedMoreMaps:
return nil;
case routing::RouterResultCode::IntermediatePointNotFound:
return [MWMDefaultAlert intermediatePointNotFoundAlert];
} }
} }
+ (MWMAlert *)incorrectFeaturePositionAlert { + (MWMAlert *)incorrectFeaturePositionAlert
{
return [MWMDefaultAlert incorrectFeaturePositionAlert]; return [MWMDefaultAlert incorrectFeaturePositionAlert];
} }
+ (MWMAlert *)notEnoughSpaceAlert { + (MWMAlert *)notEnoughSpaceAlert
{
return [MWMDefaultAlert notEnoughSpaceAlert]; return [MWMDefaultAlert notEnoughSpaceAlert];
} }
+ (MWMAlert *)invalidUserNameOrPasswordAlert { + (MWMAlert *)invalidUserNameOrPasswordAlert
{
return [MWMDefaultAlert invalidUserNameOrPasswordAlert]; return [MWMDefaultAlert invalidUserNameOrPasswordAlert];
} }
+ (MWMAlert *)downloaderNoConnectionAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock { + (MWMAlert *)downloaderNoConnectionAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock
{
return [MWMDefaultAlert downloaderNoConnectionAlertWithOkBlock:okBlock cancelBlock:cancelBlock]; return [MWMDefaultAlert downloaderNoConnectionAlertWithOkBlock:okBlock cancelBlock:cancelBlock];
} }
+ (MWMAlert *)downloaderNotEnoughSpaceAlert { + (MWMAlert *)downloaderNotEnoughSpaceAlert
{
return [MWMDefaultAlert downloaderNotEnoughSpaceAlert]; return [MWMDefaultAlert downloaderNotEnoughSpaceAlert];
} }
+ (MWMAlert *)downloaderInternalErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock { + (MWMAlert *)downloaderInternalErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock
{
return [MWMDefaultAlert downloaderInternalErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]; return [MWMDefaultAlert downloaderInternalErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock];
} }
+ (MWMAlert *)placeDoesntExistAlertWithBlock:(MWMStringBlock)block { + (MWMAlert *)placeDoesntExistAlertWithBlock:(MWMStringBlock)block
{
return [MWMPlaceDoesntExistAlert alertWithBlock:block]; return [MWMPlaceDoesntExistAlert alertWithBlock:block];
} }
+ (MWMAlert *)resetChangesAlertWithBlock:(MWMVoidBlock)block { + (MWMAlert *)resetChangesAlertWithBlock:(MWMVoidBlock)block
{
return [MWMDefaultAlert resetChangesAlertWithBlock:block]; return [MWMDefaultAlert resetChangesAlertWithBlock:block];
} }
+ (MWMAlert *)deleteFeatureAlertWithBlock:(MWMVoidBlock)block { + (MWMAlert *)deleteFeatureAlertWithBlock:(MWMVoidBlock)block
{
return [MWMDefaultAlert deleteFeatureAlertWithBlock:block]; return [MWMDefaultAlert deleteFeatureAlertWithBlock:block];
} }
+ (MWMAlert *)personalInfoWarningAlertWithBlock:(MWMVoidBlock)block { + (MWMAlert *)personalInfoWarningAlertWithBlock:(MWMVoidBlock)block
{
return [MWMDefaultAlert personalInfoWarningAlertWithBlock:block]; return [MWMDefaultAlert personalInfoWarningAlertWithBlock:block];
} }
+ (MWMAlert *)trackWarningAlertWithCancelBlock:(MWMVoidBlock)block { + (MWMAlert *)trackWarningAlertWithCancelBlock:(MWMVoidBlock)block
{
return [MWMDefaultAlert trackWarningAlertWithCancelBlock:block]; return [MWMDefaultAlert trackWarningAlertWithCancelBlock:block];
} }
+ (MWMAlert *)infoAlert:(NSString *)title text:(NSString *)text { + (MWMAlert *)infoAlert:(NSString *)title text:(NSString *)text
{
return [MWMDefaultAlert infoAlert:title text:text]; return [MWMDefaultAlert infoAlert:title text:text];
} }
+ (MWMAlert *)createBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max + (MWMAlert *)createBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min minCharacterNum:(NSUInteger)min
callback:(MWMCheckStringBlock)callback { callback:(MWMCheckStringBlock)callback
{
return [MWMBCCreateCategoryAlert alertWithMaxCharachersNum:max minCharactersNum:min callback:callback]; return [MWMBCCreateCategoryAlert alertWithMaxCharachersNum:max minCharactersNum:min callback:callback];
} }
+ (MWMAlert *)spinnerAlertWithTitle:(NSString *)title cancel:(MWMVoidBlock)cancel { + (MWMAlert *)spinnerAlertWithTitle:(NSString *)title cancel:(MWMVoidBlock)cancel
{
return [MWMSpinnerAlert alertWithTitle:title cancel:cancel]; return [MWMSpinnerAlert alertWithTitle:title cancel:cancel];
} }
+ (MWMAlert *)bookmarkConversionErrorAlert { + (MWMAlert *)bookmarkConversionErrorAlert
{
return [MWMDefaultAlert bookmarkConversionErrorAlert]; return [MWMDefaultAlert bookmarkConversionErrorAlert];
} }
+ (MWMAlert *)tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock { + (MWMAlert *)tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock
{
return [MWMDefaultAlert tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock]; return [MWMDefaultAlert tagsLoadingErrorAlertWithOkBlock:okBlock cancelBlock:cancelBlock];
} }
+ (MWMAlert *)bugReportAlertWithTitle:(NSString *)title { + (MWMAlert *)bugReportAlertWithTitle:(NSString *)title
{
return [MWMDefaultAlert bugReportAlertWithTitle:title]; return [MWMDefaultAlert bugReportAlertWithTitle:title];
} }
@@ -167,66 +188,76 @@
message:(NSString *)message message:(NSString *)message
rightButtonTitle:(NSString *)rightButtonTitle rightButtonTitle:(NSString *)rightButtonTitle
leftButtonTitle:(NSString *)leftButtonTitle leftButtonTitle:(NSString *)leftButtonTitle
rightButtonAction:(MWMVoidBlock)action { rightButtonAction:(MWMVoidBlock)action
{
return [MWMDefaultAlert defaultAlertWithTitle:title return [MWMDefaultAlert defaultAlertWithTitle:title
message:message message:message
rightButtonTitle:rightButtonTitle rightButtonTitle:rightButtonTitle
leftButtonTitle:leftButtonTitle leftButtonTitle:leftButtonTitle
rightButtonAction:action rightButtonAction:action
log:nil]; log:nil];
} }
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
// Should override this method if you want custom relayout after rotation. // Should override this method if you want custom relayout after rotation.
} }
- (void)close:(MWMVoidBlock)completion { - (void)close:(MWMVoidBlock)completion
{
[self.alertController closeAlert:completion]; [self.alertController closeAlert:completion];
} }
- (void)setNeedsCloseAlertAfterEnterBackground { - (void)setNeedsCloseAlertAfterEnterBackground
{
[NSNotificationCenter.defaultCenter addObserver:self [NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(applicationDidEnterBackground) selector:@selector(applicationDidEnterBackground)
name:UIApplicationDidEnterBackgroundNotification name:UIApplicationDidEnterBackgroundNotification
object:nil]; object:nil];
} }
- (void)dealloc { - (void)dealloc
{
[NSNotificationCenter.defaultCenter removeObserver:self]; [NSNotificationCenter.defaultCenter removeObserver:self];
} }
- (void)applicationDidEnterBackground { - (void)applicationDidEnterBackground
{
// Should close alert when application entered background. // Should close alert when application entered background.
[self close:nil]; [self close:nil];
} }
- (void)rotate:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - (void)rotate:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if ([self respondsToSelector:@selector(willRotateToInterfaceOrientation:)]) if ([self respondsToSelector:@selector(willRotateToInterfaceOrientation:)])
[self willRotateToInterfaceOrientation:toInterfaceOrientation]; [self willRotateToInterfaceOrientation:toInterfaceOrientation];
} }
- (void)addControllerViewToWindow { - (void)addControllerViewToWindow
UIWindow *window = UIApplication.sharedApplication.delegate.window; {
UIView *view = self.alertController.view; UIWindow * window = UIApplication.sharedApplication.delegate.window;
UIView * view = self.alertController.view;
[window addSubview:view]; [window addSubview:view];
view.frame = window.bounds; view.frame = window.bounds;
} }
- (void)layoutSubviews { - (void)layoutSubviews
{
[super layoutSubviews]; [super layoutSubviews];
self.frame = self.superview.bounds; self.frame = self.superview.bounds;
[super layoutSubviews]; [super layoutSubviews];
} }
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection]; [super traitCollectionDidChange:previousTraitCollection];
if (self.traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) { if (self.traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle)
[self updateViewStyle:self]; [self updateViewStyle:self];
}
} }
- (void)updateViewStyle:(UIView *)view { - (void)updateViewStyle:(UIView *)view
{
if (!view) if (!view)
return; return;
for (UIView *subview in view.subviews) for (UIView * subview in view.subviews)
[self updateViewStyle:subview]; [self updateViewStyle:subview];
[view applyTheme]; [view applyTheme];
} }

View File

@@ -7,354 +7,387 @@ static CGFloat const kDividerTopConstant = -8.;
@interface MWMDefaultAlert () @interface MWMDefaultAlert ()
@property(weak, nonatomic) IBOutlet UILabel *messageLabel; @property(weak, nonatomic) IBOutlet UILabel * messageLabel;
@property(weak, nonatomic) IBOutlet UIButton *rightButton; @property(weak, nonatomic) IBOutlet UIButton * rightButton;
@property(weak, nonatomic) IBOutlet UIButton *leftButton; @property(weak, nonatomic) IBOutlet UIButton * leftButton;
@property(weak, nonatomic) IBOutlet UILabel *titleLabel; @property(weak, nonatomic) IBOutlet UILabel * titleLabel;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *rightButtonWidth; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * rightButtonWidth;
@property(copy, nonatomic) MWMVoidBlock leftButtonAction; @property(copy, nonatomic) MWMVoidBlock leftButtonAction;
@property(copy, nonatomic, readwrite) MWMVoidBlock rightButtonAction; @property(copy, nonatomic, readwrite) MWMVoidBlock rightButtonAction;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *dividerTop; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * dividerTop;
@property(weak, nonatomic) IBOutlet UIView *vDivider; @property(weak, nonatomic) IBOutlet UIView * vDivider;
@end @end
static NSString *const kDefaultAlertNibName = @"MWMDefaultAlert"; static NSString * const kDefaultAlertNibName = @"MWMDefaultAlert";
@implementation MWMDefaultAlert @implementation MWMDefaultAlert
+ (instancetype)routeFileNotExistAlert { + (instancetype)routeFileNotExistAlert
{
return [self defaultAlertWithTitle:L(@"dialog_routing_download_files") return [self defaultAlertWithTitle:L(@"dialog_routing_download_files")
message:L(@"dialog_routing_download_and_update_all") message:L(@"dialog_routing_download_and_update_all")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Route File Not Exist Alert"]; log:@"Route File Not Exist Alert"];
} }
+ (instancetype)routeNotFoundAlert { + (instancetype)routeNotFoundAlert
{
return [self defaultAlertWithTitle:L(@"dialog_routing_unable_locate_route") return [self defaultAlertWithTitle:L(@"dialog_routing_unable_locate_route")
message:L(@"dialog_routing_change_start_or_end") message:L(@"dialog_routing_change_start_or_end")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Route File Not Exist Alert"]; log:@"Route File Not Exist Alert"];
} }
+ (instancetype)routeNotFoundNoPublicTransportAlert { + (instancetype)routeNotFoundNoPublicTransportAlert
{
return [self defaultAlertWithTitle:L(@"transit_not_found") return [self defaultAlertWithTitle:L(@"transit_not_found")
message:nil message:nil
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"transit_not_found"]; log:@"transit_not_found"];
} }
+ (instancetype)routeNotFoundTooLongPedestrianAlert { + (instancetype)routeNotFoundTooLongPedestrianAlert
{
return [self defaultAlertWithTitle:L(@"dialog_pedestrian_route_is_long_header") return [self defaultAlertWithTitle:L(@"dialog_pedestrian_route_is_long_header")
message:L(@"dialog_pedestrian_route_is_long_message") message:L(@"dialog_pedestrian_route_is_long_message")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Long Pedestrian Route Alert"]; log:@"Long Pedestrian Route Alert"];
} }
+ (instancetype)locationServiceNotSupportedAlert { + (instancetype)locationServiceNotSupportedAlert
{
return [self defaultAlertWithTitle:L(@"current_location_unknown_error_title") return [self defaultAlertWithTitle:L(@"current_location_unknown_error_title")
message:L(@"current_location_unknown_error_message") message:L(@"current_location_unknown_error_message")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Location Service Not Supported Alert"]; log:@"Location Service Not Supported Alert"];
} }
+ (instancetype)noConnectionAlert { + (instancetype)noConnectionAlert
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"common_check_internet_connection_dialog") {
message:nil MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"common_check_internet_connection_dialog")
rightButtonTitle:L(@"ok") message:nil
leftButtonTitle:nil rightButtonTitle:L(@"ok")
rightButtonAction:nil leftButtonTitle:nil
log:@"No Connection Alert"]; rightButtonAction:nil
log:@"No Connection Alert"];
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)deleteMapProhibitedAlert { + (instancetype)deleteMapProhibitedAlert
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"downloader_delete_map") {
message:L(@"downloader_delete_map_while_routing_dialog") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"downloader_delete_map")
rightButtonTitle:L(@"ok") message:L(@"downloader_delete_map_while_routing_dialog")
leftButtonTitle:nil rightButtonTitle:L(@"ok")
rightButtonAction:nil leftButtonTitle:nil
log:@"Delete Map Prohibited Alert"]; rightButtonAction:nil
log:@"Delete Map Prohibited Alert"];
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)unsavedEditsAlertWithOkBlock:(MWMVoidBlock)okBlock { + (instancetype)unsavedEditsAlertWithOkBlock:(MWMVoidBlock)okBlock
{
return [self defaultAlertWithTitle:L(@"please_note") return [self defaultAlertWithTitle:L(@"please_note")
message:L(@"downloader_delete_map_dialog") message:L(@"downloader_delete_map_dialog")
rightButtonTitle:L(@"delete") rightButtonTitle:L(@"delete")
leftButtonTitle:L(@"cancel") leftButtonTitle:L(@"cancel")
rightButtonAction:okBlock rightButtonAction:okBlock
log:@"Editor unsaved changes on delete"]; log:@"Editor unsaved changes on delete"];
} }
+ (instancetype)noWiFiAlertWithOkBlock:(MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock { + (instancetype)noWiFiAlertWithOkBlock:(MWMVoidBlock)okBlock andCancelBlock:(MWMVoidBlock)cancelBlock
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"download_over_mobile_header") {
message:L(@"download_over_mobile_message") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"download_over_mobile_header")
rightButtonTitle:L(@"use_cellular_data") message:L(@"download_over_mobile_message")
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"use_cellular_data")
rightButtonAction:okBlock leftButtonTitle:L(@"cancel")
log:@"No WiFi Alert"]; rightButtonAction:okBlock
log:@"No WiFi Alert"];
alert.leftButtonAction = cancelBlock; alert.leftButtonAction = cancelBlock;
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)endPointNotFoundAlert { + (instancetype)endPointNotFoundAlert
NSString *message = [NSString {
stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_end_not_determined"), L(@"dialog_routing_select_closer_end")]; NSString * message = [NSString
stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_end_not_determined"), L(@"dialog_routing_select_closer_end")];
return [self defaultAlertWithTitle:L(@"dialog_routing_change_end") return [self defaultAlertWithTitle:L(@"dialog_routing_change_end")
message:message message:message
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"End Point Not Found Alert"]; log:@"End Point Not Found Alert"];
} }
+ (instancetype)startPointNotFoundAlert { + (instancetype)startPointNotFoundAlert
NSString *message = [NSString {
stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_start_not_determined"), L(@"dialog_routing_select_closer_start")]; NSString * message = [NSString stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_start_not_determined"),
L(@"dialog_routing_select_closer_start")];
return [self defaultAlertWithTitle:L(@"dialog_routing_change_start") return [self defaultAlertWithTitle:L(@"dialog_routing_change_start")
message:message message:message
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Start Point Not Found Alert"]; log:@"Start Point Not Found Alert"];
} }
+ (instancetype)intermediatePointNotFoundAlert { + (instancetype)intermediatePointNotFoundAlert
{
return [self defaultAlertWithTitle:L(@"dialog_routing_change_intermediate") return [self defaultAlertWithTitle:L(@"dialog_routing_change_intermediate")
message:L(@"dialog_routing_intermediate_not_determined") message:L(@"dialog_routing_intermediate_not_determined")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Intermediate Point Not Found Alert"]; log:@"Intermediate Point Not Found Alert"];
} }
+ (instancetype)internalRoutingErrorAlert { + (instancetype)internalRoutingErrorAlert
NSString *message = {
[NSString stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_application_error"), L(@"dialog_routing_try_again")]; NSString * message =
[NSString stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_application_error"), L(@"dialog_routing_try_again")];
return [self defaultAlertWithTitle:L(@"dialog_routing_system_error") return [self defaultAlertWithTitle:L(@"dialog_routing_system_error")
message:message message:message
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Internal Routing Error Alert"]; log:@"Internal Routing Error Alert"];
} }
+ (instancetype)incorrectFeaturePositionAlert { + (instancetype)incorrectFeaturePositionAlert
{
return [self defaultAlertWithTitle:L(@"dialog_incorrect_feature_position") return [self defaultAlertWithTitle:L(@"dialog_incorrect_feature_position")
message:L(@"message_invalid_feature_position") message:L(@"message_invalid_feature_position")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Incorrect Feature Possition Alert"]; log:@"Incorrect Feature Possition Alert"];
} }
+ (instancetype)notEnoughSpaceAlert { + (instancetype)notEnoughSpaceAlert
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"downloader_no_space_title") {
message:L(@"migration_no_space_message") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"downloader_no_space_title")
rightButtonTitle:L(@"ok") message:L(@"migration_no_space_message")
leftButtonTitle:nil rightButtonTitle:L(@"ok")
rightButtonAction:nil leftButtonTitle:nil
log:@"Not Enough Space Alert"]; rightButtonAction:nil
log:@"Not Enough Space Alert"];
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)invalidUserNameOrPasswordAlert { + (instancetype)invalidUserNameOrPasswordAlert
{
return [self defaultAlertWithTitle:L(@"invalid_username_or_password") return [self defaultAlertWithTitle:L(@"invalid_username_or_password")
message:nil message:nil
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Invalid User Name or Password Alert"]; log:@"Invalid User Name or Password Alert"];
} }
+ (instancetype)noCurrentPositionAlert { + (instancetype)noCurrentPositionAlert
NSString *message = [NSString stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_error_location_not_found"), {
L(@"dialog_routing_location_turn_wifi")]; NSString * message = [NSString stringWithFormat:@"%@\n\n%@", L(@"dialog_routing_error_location_not_found"),
L(@"dialog_routing_location_turn_wifi")];
return [self defaultAlertWithTitle:L(@"dialog_routing_check_gps") return [self defaultAlertWithTitle:L(@"dialog_routing_check_gps")
message:message message:message
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"No Current Position Alert"]; log:@"No Current Position Alert"];
} }
+ (instancetype)disabledLocationAlert { + (instancetype)disabledLocationAlert
MWMVoidBlock action = ^{ {
GetFramework().SwitchMyPositionNextMode(); MWMVoidBlock action = ^{ GetFramework().SwitchMyPositionNextMode(); };
};
return [self defaultAlertWithTitle:L(@"dialog_routing_location_turn_on") return [self defaultAlertWithTitle:L(@"dialog_routing_location_turn_on")
message:L(@"dialog_routing_location_unknown_turn_on") message:L(@"dialog_routing_location_unknown_turn_on")
rightButtonTitle:L(@"turn_on") rightButtonTitle:L(@"turn_on")
leftButtonTitle:L(@"later") leftButtonTitle:L(@"later")
rightButtonAction:action rightButtonAction:action
log:@"Disabled Location Alert"]; log:@"Disabled Location Alert"];
} }
+ (instancetype)pointsInDifferentMWMAlert { + (instancetype)pointsInDifferentMWMAlert
{
return [self defaultAlertWithTitle:L(@"routing_failed_cross_mwm_building") return [self defaultAlertWithTitle:L(@"routing_failed_cross_mwm_building")
message:nil message:nil
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Points In Different MWM Alert"]; log:@"Points In Different MWM Alert"];
} }
+ (instancetype)point2PointAlertWithOkBlock:(MWMVoidBlock)okBlock needToRebuild:(BOOL)needToRebuild { + (instancetype)point2PointAlertWithOkBlock:(MWMVoidBlock)okBlock needToRebuild:(BOOL)needToRebuild
if (needToRebuild) { {
if (needToRebuild)
{
return [self defaultAlertWithTitle:L(@"p2p_only_from_current") return [self defaultAlertWithTitle:L(@"p2p_only_from_current")
message:L(@"p2p_reroute_from_current") message:L(@"p2p_reroute_from_current")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:L(@"cancel") leftButtonTitle:L(@"cancel")
rightButtonAction:okBlock rightButtonAction:okBlock
log:@"Default Alert"]; log:@"Default Alert"];
} else { }
else
{
return [self defaultAlertWithTitle:L(@"p2p_only_from_current") return [self defaultAlertWithTitle:L(@"p2p_only_from_current")
message:nil message:nil
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Default Alert"]; log:@"Default Alert"];
} }
} }
+ (instancetype)downloaderNoConnectionAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock { + (instancetype)downloaderNoConnectionAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"downloader_status_failed") {
message:L(@"common_check_internet_connection_dialog") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"downloader_status_failed")
rightButtonTitle:L(@"downloader_retry") message:L(@"common_check_internet_connection_dialog")
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"downloader_retry")
rightButtonAction:okBlock leftButtonTitle:L(@"cancel")
log:@"Downloader No Connection Alert"]; rightButtonAction:okBlock
log:@"Downloader No Connection Alert"];
alert.leftButtonAction = cancelBlock; alert.leftButtonAction = cancelBlock;
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)downloaderNotEnoughSpaceAlert { + (instancetype)downloaderNotEnoughSpaceAlert
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"downloader_no_space_title") {
message:L(@"downloader_no_space_message") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"downloader_no_space_title")
rightButtonTitle:L(@"close") message:L(@"downloader_no_space_message")
leftButtonTitle:nil rightButtonTitle:L(@"close")
rightButtonAction:nil leftButtonTitle:nil
log:@"Downloader Not Enough Space Alert"]; rightButtonAction:nil
log:@"Downloader Not Enough Space Alert"];
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)downloaderInternalErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock { + (instancetype)downloaderInternalErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"migration_download_error_dialog") {
message:nil MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"migration_download_error_dialog")
rightButtonTitle:L(@"downloader_retry") message:nil
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"downloader_retry")
rightButtonAction:okBlock leftButtonTitle:L(@"cancel")
log:@"Downloader Internal Error Alert"]; rightButtonAction:okBlock
log:@"Downloader Internal Error Alert"];
alert.leftButtonAction = cancelBlock; alert.leftButtonAction = cancelBlock;
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)resetChangesAlertWithBlock:(MWMVoidBlock)block { + (instancetype)resetChangesAlertWithBlock:(MWMVoidBlock)block
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"editor_reset_edits_message") {
message:nil MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"editor_reset_edits_message")
rightButtonTitle:L(@"editor_reset_edits_button") message:nil
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"editor_reset_edits_button")
rightButtonAction:block leftButtonTitle:L(@"cancel")
log:@"Reset changes alert"]; rightButtonAction:block
log:@"Reset changes alert"];
return alert; return alert;
} }
+ (instancetype)deleteFeatureAlertWithBlock:(MWMVoidBlock)block { + (instancetype)deleteFeatureAlertWithBlock:(MWMVoidBlock)block
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"editor_remove_place_message") {
message:nil MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"editor_remove_place_message")
rightButtonTitle:L(@"editor_remove_place_button") message:nil
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"editor_remove_place_button")
rightButtonAction:block leftButtonTitle:L(@"cancel")
log:@"Delete feature alert"]; rightButtonAction:block
log:@"Delete feature alert"];
return alert; return alert;
} }
+ (instancetype)personalInfoWarningAlertWithBlock:(MWMVoidBlock)block { + (instancetype)personalInfoWarningAlertWithBlock:(MWMVoidBlock)block
NSString *message = [NSString {
stringWithFormat:@"%@\n%@", L(@"editor_share_to_all_dialog_message_1"), L(@"editor_share_to_all_dialog_message_2")]; NSString * message = [NSString stringWithFormat:@"%@\n%@", L(@"editor_share_to_all_dialog_message_1"),
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"editor_share_to_all_dialog_title") L(@"editor_share_to_all_dialog_message_2")];
message:message MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"editor_share_to_all_dialog_title")
rightButtonTitle:L(@"editor_report_problem_send_button") message:message
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"editor_report_problem_send_button")
rightButtonAction:block leftButtonTitle:L(@"cancel")
log:@"Personal info warning alert"]; rightButtonAction:block
log:@"Personal info warning alert"];
return alert; return alert;
} }
+ (instancetype)trackWarningAlertWithCancelBlock:(MWMVoidBlock)block { + (instancetype)trackWarningAlertWithCancelBlock:(MWMVoidBlock)block
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"recent_track_background_dialog_title") {
message:L(@"recent_track_background_dialog_message") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"recent_track_background_dialog_title")
rightButtonTitle:L(@"off_recent_track_background_button") message:L(@"recent_track_background_dialog_message")
leftButtonTitle:L(@"continue_button") rightButtonTitle:L(@"off_recent_track_background_button")
rightButtonAction:block leftButtonTitle:L(@"continue_button")
log:@"Track warning alert"]; rightButtonAction:block
log:@"Track warning alert"];
return alert; return alert;
} }
+ (instancetype)infoAlert:(NSString *)title text:(NSString *)text { + (instancetype)infoAlert:(NSString *)title text:(NSString *)text
{
return [self defaultAlertWithTitle:title return [self defaultAlertWithTitle:title
message:text message:text
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:@"Info Alert"]; log:@"Info Alert"];
} }
+ (instancetype)convertBookmarksWithCount:(NSUInteger)count okBlock:(MWMVoidBlock)okBlock { + (instancetype)convertBookmarksWithCount:(NSUInteger)count okBlock:(MWMVoidBlock)okBlock
{
return [self defaultAlertWithTitle:L(@"bookmarks_detect_title") return [self defaultAlertWithTitle:L(@"bookmarks_detect_title")
message:[NSString stringWithFormat:L(@"bookmarks_detect_message"), count] message:[NSString stringWithFormat:L(@"bookmarks_detect_message"), count]
rightButtonTitle:L(@"button_convert") rightButtonTitle:L(@"button_convert")
leftButtonTitle:L(@"cancel") leftButtonTitle:L(@"cancel")
rightButtonAction:okBlock rightButtonAction:okBlock
log:nil]; log:nil];
} }
+ (instancetype)bookmarkConversionErrorAlert { + (instancetype)bookmarkConversionErrorAlert
{
return [self defaultAlertWithTitle:L(@"bookmarks_convert_error_title") return [self defaultAlertWithTitle:L(@"bookmarks_convert_error_title")
message:L(@"bookmarks_convert_error_message") message:L(@"bookmarks_convert_error_message")
rightButtonTitle:L(@"ok") rightButtonTitle:L(@"ok")
leftButtonTitle:nil leftButtonTitle:nil
rightButtonAction:nil rightButtonAction:nil
log:nil]; log:nil];
} }
+ (instancetype)tagsLoadingErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock { + (instancetype)tagsLoadingErrorAlertWithOkBlock:(MWMVoidBlock)okBlock cancelBlock:(MWMVoidBlock)cancelBlock
MWMDefaultAlert *alert = [self defaultAlertWithTitle:L(@"title_error_downloading_bookmarks") {
message:L(@"tags_loading_error_subtitle") MWMDefaultAlert * alert = [self defaultAlertWithTitle:L(@"title_error_downloading_bookmarks")
rightButtonTitle:L(@"downloader_retry") message:L(@"tags_loading_error_subtitle")
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"downloader_retry")
rightButtonAction:okBlock leftButtonTitle:L(@"cancel")
log:nil]; rightButtonAction:okBlock
log:nil];
alert.leftButtonAction = cancelBlock; alert.leftButtonAction = cancelBlock;
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
+ (instancetype)bugReportAlertWithTitle:(NSString *)title { + (instancetype)bugReportAlertWithTitle:(NSString *)title
MWMDefaultAlert *alert = [self defaultAlertWithTitle:title {
message:L(@"bugreport_alert_message") MWMDefaultAlert * alert = [self defaultAlertWithTitle:title
rightButtonTitle:L(@"report_a_bug") message:L(@"bugreport_alert_message")
leftButtonTitle:L(@"cancel") rightButtonTitle:L(@"report_a_bug")
rightButtonAction:^{ [MailComposer sendBugReportWithTitle:title]; } leftButtonTitle:L(@"cancel")
log:nil]; rightButtonAction:^{ [MailComposer sendBugReportWithTitle:title]; }
log:nil];
[alert setNeedsCloseAlertAfterEnterBackground]; [alert setNeedsCloseAlertAfterEnterBackground];
return alert; return alert;
} }
@@ -364,14 +397,15 @@ static NSString *const kDefaultAlertNibName = @"MWMDefaultAlert";
rightButtonTitle:(NSString *)rightButtonTitle rightButtonTitle:(NSString *)rightButtonTitle
leftButtonTitle:(NSString *)leftButtonTitle leftButtonTitle:(NSString *)leftButtonTitle
rightButtonAction:(MWMVoidBlock)action rightButtonAction:(MWMVoidBlock)action
log:(NSString *)log { log:(NSString *)log
if (log) { {
if (log)
LOG(LINFO, ([log UTF8String])); LOG(LINFO, ([log UTF8String]));
} MWMDefaultAlert * alert = [NSBundle.mainBundle loadNibNamed:kDefaultAlertNibName owner:self options:nil].firstObject;
MWMDefaultAlert *alert = [NSBundle.mainBundle loadNibNamed:kDefaultAlertNibName owner:self options:nil].firstObject;
alert.titleLabel.text = title; alert.titleLabel.text = title;
alert.messageLabel.text = message; alert.messageLabel.text = message;
if (!message) { if (!message)
{
alert.dividerTop.constant = kDividerTopConstant; alert.dividerTop.constant = kDividerTopConstant;
[alert layoutIfNeeded]; [alert layoutIfNeeded];
} }
@@ -380,10 +414,13 @@ static NSString *const kDefaultAlertNibName = @"MWMDefaultAlert";
[alert.rightButton setTitle:rightButtonTitle forState:UIControlStateDisabled]; [alert.rightButton setTitle:rightButtonTitle forState:UIControlStateDisabled];
alert.rightButtonAction = action; alert.rightButtonAction = action;
if (leftButtonTitle) { if (leftButtonTitle)
{
[alert.leftButton setTitle:leftButtonTitle forState:UIControlStateNormal]; [alert.leftButton setTitle:leftButtonTitle forState:UIControlStateNormal];
[alert.leftButton setTitle:leftButtonTitle forState:UIControlStateDisabled]; [alert.leftButton setTitle:leftButtonTitle forState:UIControlStateDisabled];
} else { }
else
{
alert.vDivider.hidden = YES; alert.vDivider.hidden = YES;
alert.leftButton.hidden = YES; alert.leftButton.hidden = YES;
alert.rightButtonWidth.constant = [alert.subviews.firstObject width]; alert.rightButtonWidth.constant = [alert.subviews.firstObject width];
@@ -393,11 +430,13 @@ static NSString *const kDefaultAlertNibName = @"MWMDefaultAlert";
#pragma mark - Actions #pragma mark - Actions
- (IBAction)rightButtonTap { - (IBAction)rightButtonTap
{
[self close:self.rightButtonAction]; [self close:self.rightButtonAction];
} }
- (IBAction)leftButtonTap { - (IBAction)leftButtonTap
{
[self close:self.leftButtonAction]; [self close:self.leftButtonAction];
} }

View File

@@ -17,34 +17,37 @@ CGFloat const kCellHeight = 32.;
CGFloat const kHeaderHeight = 44.; CGFloat const kHeaderHeight = 44.;
CGFloat const kMinimumOffset = 20.; CGFloat const kMinimumOffset = 20.;
CGFloat const kAnimationDuration = .05; CGFloat const kAnimationDuration = .05;
} // namespace } // namespace
@interface MWMDownloadTransitMapAlert () <UITableViewDataSource, UITableViewDelegate, MWMStorageObserver, MWMCircularProgressProtocol> @interface MWMDownloadTransitMapAlert () <UITableViewDataSource,
UITableViewDelegate,
MWMStorageObserver,
MWMCircularProgressProtocol>
@property(copy, nonatomic) MWMVoidBlock cancelBlock; @property(copy, nonatomic) MWMVoidBlock cancelBlock;
@property(copy, nonatomic) MWMDownloadBlock downloadBlock; @property(copy, nonatomic) MWMDownloadBlock downloadBlock;
@property(copy, nonatomic) MWMVoidBlock downloadCompleteBlock; @property(copy, nonatomic) MWMVoidBlock downloadCompleteBlock;
@property (nonatomic) MWMCircularProgress * progress; @property(nonatomic) MWMCircularProgress * progress;
@property (weak, nonatomic) IBOutlet UIView * containerView; @property(weak, nonatomic) IBOutlet UIView * containerView;
@property (weak, nonatomic) IBOutlet UILabel * titleLabel; @property(weak, nonatomic) IBOutlet UILabel * titleLabel;
@property (weak, nonatomic) IBOutlet UILabel * messageLabel; @property(weak, nonatomic) IBOutlet UILabel * messageLabel;
@property (weak, nonatomic) IBOutlet UITableView * dialogsTableView; @property(weak, nonatomic) IBOutlet UITableView * dialogsTableView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * tableViewHeight; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * tableViewHeight;
@property (nonatomic) MWMDownloaderDialogHeader * listHeader; @property(nonatomic) MWMDownloaderDialogHeader * listHeader;
@property (nonatomic) BOOL listExpanded; @property(nonatomic) BOOL listExpanded;
@property (weak, nonatomic) IBOutlet UIView * progressWrapper; @property(weak, nonatomic) IBOutlet UIView * progressWrapper;
@property (weak, nonatomic) IBOutlet UIView * hDivider; @property(weak, nonatomic) IBOutlet UIView * hDivider;
@property (weak, nonatomic) IBOutlet UIView * vDivider; @property(weak, nonatomic) IBOutlet UIView * vDivider;
@property (weak, nonatomic) IBOutlet UIButton * leftButton; @property(weak, nonatomic) IBOutlet UIButton * leftButton;
@property (weak, nonatomic) IBOutlet UIButton * rightButton; @property(weak, nonatomic) IBOutlet UIButton * rightButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * dialogsBottomOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * dialogsBottomOffset;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * progressWrapperBottomOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * progressWrapperBottomOffset;
@property (copy, nonatomic) NSArray<NSString *> * countriesNames; @property(copy, nonatomic) NSArray<NSString *> * countriesNames;
@property (copy, nonatomic) NSString * countriesSize; @property(copy, nonatomic) NSString * countriesSize;
@end @end
@@ -62,23 +65,21 @@ CGFloat const kAnimationDuration = .05;
MWMDownloadTransitMapAlert * alert = [self alertWithCountries:countries]; MWMDownloadTransitMapAlert * alert = [self alertWithCountries:countries];
switch (code) switch (code)
{ {
case routing::RouterResultCode::InconsistentMWMandRoute: case routing::RouterResultCode::InconsistentMWMandRoute:
case routing::RouterResultCode::RouteNotFound: case routing::RouterResultCode::RouteNotFound:
case routing::RouterResultCode::RouteFileNotExist: case routing::RouterResultCode::RouteFileNotExist:
alert.titleLabel.text = L(@"dialog_routing_download_files"); alert.titleLabel.text = L(@"dialog_routing_download_files");
alert.messageLabel.text = L(@"dialog_routing_download_and_update_all"); alert.messageLabel.text = L(@"dialog_routing_download_and_update_all");
break; break;
case routing::RouterResultCode::FileTooOld: case routing::RouterResultCode::FileTooOld:
alert.titleLabel.text = L(@"dialog_routing_download_files"); alert.titleLabel.text = L(@"dialog_routing_download_files");
alert.messageLabel.text = L(@"dialog_routing_download_and_update_maps"); alert.messageLabel.text = L(@"dialog_routing_download_and_update_maps");
break; break;
case routing::RouterResultCode::NeedMoreMaps: case routing::RouterResultCode::NeedMoreMaps:
alert.titleLabel.text = L(@"dialog_routing_download_and_build_cross_route"); alert.titleLabel.text = L(@"dialog_routing_download_and_build_cross_route");
alert.messageLabel.text = L(@"dialog_routing_download_cross_route"); alert.messageLabel.text = L(@"dialog_routing_download_cross_route");
break; break;
default: default: NSAssert(false, @"Incorrect code!"); break;
NSAssert(false, @"Incorrect code!");
break;
} }
alert.cancelBlock = cancelBlock; alert.cancelBlock = cancelBlock;
alert.downloadBlock = downloadBlock; alert.downloadBlock = downloadBlock;
@@ -90,8 +91,7 @@ CGFloat const kAnimationDuration = .05;
{ {
NSAssert(!countries.empty(), @"countries can not be empty."); NSAssert(!countries.empty(), @"countries can not be empty.");
MWMDownloadTransitMapAlert * alert = MWMDownloadTransitMapAlert * alert =
[NSBundle.mainBundle loadNibNamed:kDownloadTransitMapAlertNibName owner:nil options:nil] [NSBundle.mainBundle loadNibNamed:kDownloadTransitMapAlertNibName owner:nil options:nil].firstObject;
.firstObject;
alert->m_countries = storage::CountriesVec(countries.begin(), countries.end()); alert->m_countries = storage::CountriesVec(countries.begin(), countries.end());
[alert configure]; [alert configure];
@@ -113,10 +113,9 @@ CGFloat const kAnimationDuration = .05;
- (void)updateCountriesList - (void)updateCountriesList
{ {
auto const & s = GetFramework().GetStorage(); auto const & s = GetFramework().GetStorage();
m_countries.erase( m_countries.erase(remove_if(m_countries.begin(), m_countries.end(),
remove_if(m_countries.begin(), m_countries.end(), [&s](storage::CountryId const & countryId) { return s.HasLatestVersion(countryId); }),
[&s](storage::CountryId const & countryId) { return s.HasLatestVersion(countryId); }), m_countries.end());
m_countries.end());
NSMutableArray<NSString *> * titles = [@[] mutableCopy]; NSMutableArray<NSString *> * titles = [@[] mutableCopy];
MwmSize totalSize = 0; MwmSize totalSize = 0;
for (auto const & countryId : m_countries) for (auto const & countryId : m_countries)
@@ -170,16 +169,13 @@ CGFloat const kAnimationDuration = .05;
} }
} }
- (void)processCountry:(NSString *)countryId - (void)processCountry:(NSString *)countryId downloadedBytes:(uint64_t)downloadedBytes totalBytes:(uint64_t)totalBytes
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes
{ {
if (!self.rightButton.hidden || if (!self.rightButton.hidden ||
find(m_countries.begin(), m_countries.end(), countryId.UTF8String) == m_countries.end()) find(m_countries.begin(), m_countries.end(), countryId.UTF8String) == m_countries.end())
return; return;
auto const overallProgress = GetFramework().GetStorage().GetOverallProgress(m_countries); auto const overallProgress = GetFramework().GetStorage().GetOverallProgress(m_countries);
CGFloat const progressValue = CGFloat const progressValue = static_cast<CGFloat>(overallProgress.m_bytesDownloaded) / overallProgress.m_bytesTotal;
static_cast<CGFloat>(overallProgress.m_bytesDownloaded) / overallProgress.m_bytesTotal;
self.progress.progress = progressValue; self.progress.progress = progressValue;
self.titleLabel.text = [NSString stringWithFormat:@"%@%@%%", L(@"downloading"), @(floor(progressValue * 100))]; self.titleLabel.text = [NSString stringWithFormat:@"%@%@%%", L(@"downloading"), @(floor(progressValue * 100))];
} }
@@ -210,10 +206,7 @@ CGFloat const kAnimationDuration = .05;
self.rightButton.hidden = YES; self.rightButton.hidden = YES;
self.dialogsBottomOffset.priority = UILayoutPriorityDefaultHigh; self.dialogsBottomOffset.priority = UILayoutPriorityDefaultHigh;
self.progressWrapperBottomOffset.priority = UILayoutPriorityDefaultHigh; self.progressWrapperBottomOffset.priority = UILayoutPriorityDefaultHigh;
[UIView animateWithDuration:kAnimationDuration [UIView animateWithDuration:kAnimationDuration animations:^{ [self layoutSubviews]; }];
animations:^{
[self layoutSubviews];
}];
}); });
} }
@@ -226,12 +219,9 @@ CGFloat const kAnimationDuration = .05;
{ {
_listExpanded = listExpanded; _listExpanded = listExpanded;
[self layoutIfNeeded]; [self layoutIfNeeded];
auto const updateCells = ^(BOOL show) auto const updateCells = ^(BOOL show) {
{
for (MWMDownloaderDialogCell * cell in self.dialogsTableView.visibleCells) for (MWMDownloaderDialogCell * cell in self.dialogsTableView.visibleCells)
{
cell.titleLabel.alpha = show ? 1. : 0.; cell.titleLabel.alpha = show ? 1. : 0.;
}
[self.dialogsTableView refresh]; [self.dialogsTableView refresh];
}; };
if (listExpanded) if (listExpanded)
@@ -240,11 +230,11 @@ CGFloat const kAnimationDuration = .05;
CGFloat const height = [self bounded:actualHeight withHeight:self.superview.height]; CGFloat const height = [self bounded:actualHeight withHeight:self.superview.height];
self.tableViewHeight.constant = height; self.tableViewHeight.constant = height;
self.dialogsTableView.scrollEnabled = actualHeight > self.tableViewHeight.constant; self.dialogsTableView.scrollEnabled = actualHeight > self.tableViewHeight.constant;
[UIView animateWithDuration:kAnimationDuration animations:^{ [self layoutSubviews]; } [UIView animateWithDuration:kAnimationDuration
completion:^(BOOL finished) animations:^{ [self layoutSubviews]; }
{ completion:^(BOOL finished) {
[UIView animateWithDuration:kDefaultAnimationDuration animations:^{ updateCells(YES); }]; [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ updateCells(YES); }];
}]; }];
} }
else else
{ {
@@ -279,7 +269,9 @@ CGFloat const kAnimationDuration = .05;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{ {
CGFloat const height = UIInterfaceOrientationIsLandscape(orientation) ? MIN(self.superview.width, self.superview.height) : MAX(self.superview.width, self.superview.height); CGFloat const height = UIInterfaceOrientationIsLandscape(orientation)
? MIN(self.superview.width, self.superview.height)
: MAX(self.superview.width, self.superview.height);
[self invalidateTableConstraintWithHeight:height]; [self invalidateTableConstraintWithHeight:height];
} }
@@ -321,8 +313,8 @@ CGFloat const kAnimationDuration = .05;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
Class cls = [MWMDownloaderDialogCell class]; Class cls = [MWMDownloaderDialogCell class];
auto cell = static_cast<MWMDownloaderDialogCell *>( auto cell = static_cast<MWMDownloaderDialogCell *>([tableView dequeueReusableCellWithCellClass:cls
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]); indexPath:indexPath]);
cell.titleLabel.text = self.countriesNames[indexPath.row]; cell.titleLabel.text = self.countriesNames[indexPath.row];
return cell; return cell;
} }

View File

@@ -5,12 +5,12 @@ static NSString * const kDownloaderDialogHeaderNibName = @"MWMDownloaderDialogHe
@interface MWMDownloaderDialogHeader () @interface MWMDownloaderDialogHeader ()
@property (weak, nonatomic) IBOutlet UILabel * title; @property(weak, nonatomic) IBOutlet UILabel * title;
@property (weak, nonatomic) IBOutlet UILabel * size; @property(weak, nonatomic) IBOutlet UILabel * size;
@property (weak, nonatomic) IBOutlet UIView * dividerView; @property(weak, nonatomic) IBOutlet UIView * dividerView;
@property (weak, nonatomic) MWMDownloadTransitMapAlert * ownerAlert; @property(weak, nonatomic) MWMDownloadTransitMapAlert * ownerAlert;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * sizeTrailing; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * sizeTrailing;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * titleLeading; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * titleLeading;
@end @end
@@ -19,8 +19,7 @@ static NSString * const kDownloaderDialogHeaderNibName = @"MWMDownloaderDialogHe
+ (instancetype)headerForOwnerAlert:(MWMDownloadTransitMapAlert *)alert + (instancetype)headerForOwnerAlert:(MWMDownloadTransitMapAlert *)alert
{ {
MWMDownloaderDialogHeader * header = MWMDownloaderDialogHeader * header =
[NSBundle.mainBundle loadNibNamed:kDownloaderDialogHeaderNibName owner:nil options:nil] [NSBundle.mainBundle loadNibNamed:kDownloaderDialogHeaderNibName owner:nil options:nil].firstObject;
.firstObject;
header.ownerAlert = alert; header.ownerAlert = alert;
return header; return header;
} }
@@ -30,10 +29,11 @@ static NSString * const kDownloaderDialogHeaderNibName = @"MWMDownloaderDialogHe
BOOL const currentState = sender.selected; BOOL const currentState = sender.selected;
sender.selected = !currentState; sender.selected = !currentState;
self.dividerView.hidden = currentState; self.dividerView.hidden = currentState;
[UIView animateWithDuration:kDefaultAnimationDuration animations:^ [UIView animateWithDuration:kDefaultAnimationDuration
{ animations:^{
self.expandImage.transform = sender.selected ? CGAffineTransformMakeRotation(M_PI) : CGAffineTransformIdentity; self.expandImage.transform =
}]; sender.selected ? CGAffineTransformMakeRotation(M_PI) : CGAffineTransformIdentity;
}];
[self.ownerAlert showDownloadDetail:sender]; [self.ownerAlert showDownloadDetail:sender];
} }

View File

@@ -2,12 +2,12 @@
#import "MWMAddPlaceNavigationBar.h" #import "MWMAddPlaceNavigationBar.h"
#import "MWMMapDownloadDialog.h" #import "MWMMapDownloadDialog.h"
#import "MWMMapViewControlsManager+AddPlace.h" #import "MWMMapViewControlsManager+AddPlace.h"
#import "MWMMapWidgetsHelper.h"
#import "MWMNetworkPolicy+UI.h" #import "MWMNetworkPolicy+UI.h"
#import "MWMPlacePageManager.h" #import "MWMPlacePageManager.h"
#import "MWMPlacePageProtocol.h" #import "MWMPlacePageProtocol.h"
#import "MWMSideButtons.h" #import "MWMSideButtons.h"
#import "MWMTrafficButtonViewController.h" #import "MWMTrafficButtonViewController.h"
#import "MWMMapWidgetsHelper.h"
#import "MapViewController.h" #import "MapViewController.h"
#import "MapsAppDelegate.h" #import "MapsAppDelegate.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
@@ -22,8 +22,9 @@
#include "map/place_page_info.hpp" #include "map/place_page_info.hpp"
namespace { namespace
NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue"; {
NSString * const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
} // namespace } // namespace
@interface MWMMapViewControlsManager () <BottomMenuDelegate> @interface MWMMapViewControlsManager () <BottomMenuDelegate>
@@ -45,11 +46,13 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
@implementation MWMMapViewControlsManager @implementation MWMMapViewControlsManager
+ (MWMMapViewControlsManager *)manager { + (MWMMapViewControlsManager *)manager
{
return [MapViewController sharedController].controlsManager; return [MapViewController sharedController].controlsManager;
} }
- (instancetype)initWithParentController:(MapViewController *)controller { - (instancetype)initWithParentController:(MapViewController *)controller
{
if (!controller) if (!controller)
return nil; return nil;
self = [super init]; self = [super init];
@@ -67,29 +70,31 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
return self; return self;
} }
- (UIStatusBarStyle)preferredStatusBarStyle { - (UIStatusBarStyle)preferredStatusBarStyle
{
BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden && BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden &&
self.navigationManager.state != MWMNavigationDashboardStateNavigation; self.navigationManager.state != MWMNavigationDashboardStateNavigation;
BOOL const isMenuViewUnderStatusBar = self.menuState == MWMBottomMenuStateActive; BOOL const isMenuViewUnderStatusBar = self.menuState == MWMBottomMenuStateActive;
BOOL const isDirectionViewUnderStatusBar = !self.isDirectionViewHidden; BOOL const isDirectionViewUnderStatusBar = !self.isDirectionViewHidden;
BOOL const isAddPlaceUnderStatusBar = BOOL const isAddPlaceUnderStatusBar =
[self.ownerController.view hasSubviewWithViewClass:[MWMAddPlaceNavigationBar class]]; [self.ownerController.view hasSubviewWithViewClass:[MWMAddPlaceNavigationBar class]];
BOOL const isNightMode = [UIColor isNightMode]; BOOL const isNightMode = [UIColor isNightMode];
BOOL const isSomethingUnderStatusBar = isNavigationUnderStatusBar || BOOL const isSomethingUnderStatusBar = isNavigationUnderStatusBar || isDirectionViewUnderStatusBar ||
isDirectionViewUnderStatusBar || isMenuViewUnderStatusBar || isMenuViewUnderStatusBar || isAddPlaceUnderStatusBar;
isAddPlaceUnderStatusBar;
return isSomethingUnderStatusBar || isNightMode ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault; return isSomethingUnderStatusBar || isNightMode ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault;
} }
#pragma mark - Layout #pragma mark - Layout
- (UIView *)anchorView { - (UIView *)anchorView
{
return self.tabBarController.view; return self.tabBarController.view;
} }
- (void)viewWillTransitionToSize:(CGSize)size - (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[self.trafficButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.trafficButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self.trackRecordingButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.trackRecordingButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self.tabBarController viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.tabBarController viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
@@ -97,14 +102,16 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
#pragma mark - MWMPlacePageViewManager #pragma mark - MWMPlacePageViewManager
- (void)searchOnMap:(SearchQuery *)query { - (void)searchOnMap:(SearchQuery *)query
{
if (![self search:query]) if (![self search:query])
return; return;
[self.searchManager startSearchingWithIsRouting:NO]; [self.searchManager startSearchingWithIsRouting:NO];
} }
- (BOOL)search:(SearchQuery *)query { - (BOOL)search:(SearchQuery *)query
{
if (query.text.length == 0) if (query.text.length == 0)
return NO; return NO;
@@ -114,22 +121,26 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
} }
#pragma mark - BottomMenu #pragma mark - BottomMenu
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode { - (void)actionDownloadMaps:(MWMMapDownloaderMode)mode
{
[self.ownerController openMapsDownloader:mode]; [self.ownerController openMapsDownloader:mode];
} }
- (void)didFinishAddingPlace { - (void)didFinishAddingPlace
{
self.isAddingPlace = NO; self.isAddingPlace = NO;
self.trafficButtonHidden = NO; self.trafficButtonHidden = NO;
self.menuState = MWMBottomMenuStateInactive; self.menuState = MWMBottomMenuStateInactive;
} }
- (void)addPlace { - (void)addPlace
{
[self addPlace:NO position:nullptr]; [self addPlace:NO position:nullptr];
} }
- (void)addPlace:(BOOL)isBusiness position:(m2::PointD const *)optionalPosition { - (void)addPlace:(BOOL)isBusiness position:(m2::PointD const *)optionalPosition
MapViewController *ownerController = self.ownerController; {
MapViewController * ownerController = self.ownerController;
self.isAddingPlace = YES; self.isAddingPlace = YES;
[self.searchManager close]; [self.searchManager close];
@@ -139,25 +150,24 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
[ownerController dismissPlacePage]; [ownerController dismissPlacePage];
[MWMAddPlaceNavigationBar showInSuperview:ownerController.view [MWMAddPlaceNavigationBar showInSuperview:ownerController.view
isBusiness:isBusiness isBusiness:isBusiness
position:optionalPosition position:optionalPosition
doneBlock:^{ doneBlock:^{
if ([MWMFrameworkHelper canEditMapAtViewportCenter]) if ([MWMFrameworkHelper canEditMapAtViewportCenter])
[ownerController performSegueWithIdentifier:kMapToCategorySelectorSegue sender:nil]; [ownerController performSegueWithIdentifier:kMapToCategorySelectorSegue sender:nil];
else else
[ownerController.alertController presentIncorrectFeauturePositionAlert]; [ownerController.alertController presentIncorrectFeauturePositionAlert];
[self didFinishAddingPlace]; [self didFinishAddingPlace];
} }
cancelBlock:^{ cancelBlock:^{ [self didFinishAddingPlace]; }];
[self didFinishAddingPlace];
}];
[ownerController setNeedsStatusBarAppearanceUpdate]; [ownerController setNeedsStatusBarAppearanceUpdate];
} }
#pragma mark - MWMNavigationDashboardManager #pragma mark - MWMNavigationDashboardManager
- (void)setDisableStandbyOnRouteFollowing:(BOOL)disableStandbyOnRouteFollowing { - (void)setDisableStandbyOnRouteFollowing:(BOOL)disableStandbyOnRouteFollowing
{
if (_disableStandbyOnRouteFollowing == disableStandbyOnRouteFollowing) if (_disableStandbyOnRouteFollowing == disableStandbyOnRouteFollowing)
return; return;
_disableStandbyOnRouteFollowing = disableStandbyOnRouteFollowing; _disableStandbyOnRouteFollowing = disableStandbyOnRouteFollowing;
@@ -169,7 +179,8 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
#pragma mark - Routing #pragma mark - Routing
- (void)onRoutePrepare { - (void)onRoutePrepare
{
auto nm = self.navigationManager; auto nm = self.navigationManager;
[nm onRoutePrepare]; [nm onRoutePrepare];
[nm onRoutePointsUpdated]; [nm onRoutePointsUpdated];
@@ -177,18 +188,21 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
self.promoButton.hidden = YES; self.promoButton.hidden = YES;
} }
- (void)onRouteRebuild { - (void)onRouteRebuild
{
[self.ownerController.bookmarksCoordinator close]; [self.ownerController.bookmarksCoordinator close];
[self.navigationManager onRoutePlanning]; [self.navigationManager onRoutePlanning];
self.promoButton.hidden = YES; self.promoButton.hidden = YES;
} }
- (void)onRouteReady:(BOOL)hasWarnings { - (void)onRouteReady:(BOOL)hasWarnings
{
[self.navigationManager onRouteReady:hasWarnings]; [self.navigationManager onRouteReady:hasWarnings];
self.promoButton.hidden = YES; self.promoButton.hidden = YES;
} }
- (void)onRouteStart { - (void)onRouteStart
{
self.hidden = NO; self.hidden = NO;
self.sideButtons.zoomHidden = self.zoomHidden; self.sideButtons.zoomHidden = self.zoomHidden;
self.sideButtonsHidden = NO; self.sideButtonsHidden = NO;
@@ -198,7 +212,8 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
self.promoButton.hidden = YES; self.promoButton.hidden = YES;
} }
- (void)onRouteStop { - (void)onRouteStop
{
self.sideButtons.zoomHidden = self.zoomHidden; self.sideButtons.zoomHidden = self.zoomHidden;
[self.navigationManager onRouteStop]; [self.navigationManager onRouteStop];
self.disableStandbyOnRouteFollowing = NO; self.disableStandbyOnRouteFollowing = NO;
@@ -208,20 +223,24 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
#pragma mark - Properties #pragma mark - Properties
- (MWMSideButtons *)sideButtons { - (MWMSideButtons *)sideButtons
{
if (!_sideButtons) if (!_sideButtons)
_sideButtons = [[MWMSideButtons alloc] initWithParentView:self.ownerController.controlsView]; _sideButtons = [[MWMSideButtons alloc] initWithParentView:self.ownerController.controlsView];
return _sideButtons; return _sideButtons;
} }
- (MWMTrafficButtonViewController *)trafficButton { - (MWMTrafficButtonViewController *)trafficButton
{
if (!_trafficButton) if (!_trafficButton)
_trafficButton = [[MWMTrafficButtonViewController alloc] init]; _trafficButton = [[MWMTrafficButtonViewController alloc] init];
return _trafficButton; return _trafficButton;
} }
- (BottomTabBarViewController *)tabBarController { - (BottomTabBarViewController *)tabBarController
if (!_tabBarController) { {
if (!_tabBarController)
{
MapViewController * ownerController = _ownerController; MapViewController * ownerController = _ownerController;
_tabBarController = [BottomTabBarBuilder buildWithMapViewController:ownerController controlsManager:self]; _tabBarController = [BottomTabBarBuilder buildWithMapViewController:ownerController controlsManager:self];
[ownerController addChildViewController:_tabBarController]; [ownerController addChildViewController:_tabBarController];
@@ -232,13 +251,15 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
return _tabBarController; return _tabBarController;
} }
- (id<MWMPlacePageProtocol>)placePageManager { - (id<MWMPlacePageProtocol>)placePageManager
{
if (!_placePageManager) if (!_placePageManager)
_placePageManager = [[MWMPlacePageManager alloc] init]; _placePageManager = [[MWMPlacePageManager alloc] init];
return _placePageManager; return _placePageManager;
} }
- (MWMNavigationDashboardManager *)navigationManager { - (MWMNavigationDashboardManager *)navigationManager
{
if (!_navigationManager) if (!_navigationManager)
_navigationManager = [[MWMNavigationDashboardManager alloc] initWithParentView:self.ownerController.controlsView]; _navigationManager = [[MWMNavigationDashboardManager alloc] initWithParentView:self.ownerController.controlsView];
return _navigationManager; return _navigationManager;
@@ -246,7 +267,8 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
@synthesize menuState = _menuState; @synthesize menuState = _menuState;
- (void)setHidden:(BOOL)hidden { - (void)setHidden:(BOOL)hidden
{
if (_hidden == hidden) if (_hidden == hidden)
return; return;
// Do not hide the controls view during the place adding process. // Do not hide the controls view during the place adding process.
@@ -257,77 +279,84 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
self.menuState = hidden ? MWMBottomMenuStateHidden : MWMBottomMenuStateInactive; self.menuState = hidden ? MWMBottomMenuStateHidden : MWMBottomMenuStateInactive;
} }
- (void)setZoomHidden:(BOOL)zoomHidden { - (void)setZoomHidden:(BOOL)zoomHidden
{
_zoomHidden = zoomHidden; _zoomHidden = zoomHidden;
self.sideButtons.zoomHidden = zoomHidden; self.sideButtons.zoomHidden = zoomHidden;
} }
- (void)setSideButtonsHidden:(BOOL)sideButtonsHidden { - (void)setSideButtonsHidden:(BOOL)sideButtonsHidden
{
_sideButtonsHidden = sideButtonsHidden; _sideButtonsHidden = sideButtonsHidden;
self.sideButtons.hidden = self.hidden || sideButtonsHidden; self.sideButtons.hidden = self.hidden || sideButtonsHidden;
} }
- (void)setTrafficButtonHidden:(BOOL)trafficButtonHidden { - (void)setTrafficButtonHidden:(BOOL)trafficButtonHidden
{
BOOL const isNavigation = self.navigationManager.state == MWMNavigationDashboardStateNavigation; BOOL const isNavigation = self.navigationManager.state == MWMNavigationDashboardStateNavigation;
_trafficButtonHidden = isNavigation || trafficButtonHidden; _trafficButtonHidden = isNavigation || trafficButtonHidden;
self.trafficButton.hidden = self.hidden || _trafficButtonHidden; self.trafficButton.hidden = self.hidden || _trafficButtonHidden;
} }
- (void)setTrackRecordingButtonState:(TrackRecordingButtonState)state { - (void)setTrackRecordingButtonState:(TrackRecordingButtonState)state
if (!_trackRecordingButton) { {
if (!_trackRecordingButton)
_trackRecordingButton = [[TrackRecordingButtonViewController alloc] init]; _trackRecordingButton = [[TrackRecordingButtonViewController alloc] init];
} [self.trackRecordingButton setState:state completion:^{ [MWMMapWidgetsHelper updateLayoutForAvailableArea]; }];
[self.trackRecordingButton setState:state completion:^{
[MWMMapWidgetsHelper updateLayoutForAvailableArea];
}];
if (state == TrackRecordingButtonStateClosed) if (state == TrackRecordingButtonStateClosed)
_trackRecordingButton = nil; _trackRecordingButton = nil;
} }
- (void)setMenuState:(MWMBottomMenuState)menuState { - (void)setMenuState:(MWMBottomMenuState)menuState
{
_menuState = menuState; _menuState = menuState;
MapViewController * ownerController = _ownerController; MapViewController * ownerController = _ownerController;
switch (_menuState) { switch (_menuState)
case MWMBottomMenuStateActive: {
_tabBarController.isHidden = NO; case MWMBottomMenuStateActive:
if (_menuController == nil) { _tabBarController.isHidden = NO;
_menuController = [BottomMenuBuilder buildMenuWithMapViewController:ownerController if (_menuController == nil)
{
_menuController = [BottomMenuBuilder buildMenuWithMapViewController:ownerController
controlsManager:self
delegate:self];
[ownerController presentViewController:_menuController animated:YES completion:nil];
}
break;
case MWMBottomMenuStateLayers:
_tabBarController.isHidden = NO;
if (_menuController == nil)
{
_menuController = [BottomMenuBuilder buildLayersWithMapViewController:ownerController
controlsManager:self controlsManager:self
delegate:self]; delegate:self];
[ownerController presentViewController:_menuController animated:YES completion:nil]; [ownerController presentViewController:_menuController animated:YES completion:nil];
} }
break; break;
case MWMBottomMenuStateLayers: case MWMBottomMenuStateInactive:
_tabBarController.isHidden = NO; _tabBarController.isHidden = NO;
if (_menuController == nil) { if (_menuController != nil)
_menuController = [BottomMenuBuilder buildLayersWithMapViewController:ownerController {
controlsManager:self [_menuController dismissViewControllerAnimated:YES completion:nil];
delegate:self]; _menuController = nil;
[ownerController presentViewController:_menuController animated:YES completion:nil]; }
} break;
break; case MWMBottomMenuStateHidden:
case MWMBottomMenuStateInactive: _tabBarController.isHidden = YES;
_tabBarController.isHidden = NO; if (_menuController != nil)
if (_menuController != nil) { {
[_menuController dismissViewControllerAnimated:YES completion:nil]; [_menuController dismissViewControllerAnimated:YES completion:nil];
_menuController = nil; _menuController = nil;
} }
break; break;
case MWMBottomMenuStateHidden: default: break;
_tabBarController.isHidden = YES;
if (_menuController != nil) {
[_menuController dismissViewControllerAnimated:YES completion:nil];
_menuController = nil;
}
break;
default:
break;
} }
} }
#pragma mark - MWMFeatureHolder #pragma mark - MWMFeatureHolder
- (id<MWMFeatureHolder>)featureHolder { - (id<MWMFeatureHolder>)featureHolder
{
return self.placePageManager; return self.placePageManager;
} }

View File

@@ -37,11 +37,15 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
@implementation MWMSideButtons @implementation MWMSideButtons
- (UIView *)view { - (UIView *)view
{
return self.sideView; return self.sideView;
} }
+ (MWMSideButtons *)buttons { return [MWMMapViewControlsManager manager].sideButtons; } + (MWMSideButtons *)buttons
{
return [MWMMapViewControlsManager manager].sideButtons;
}
- (instancetype)initWithParentView:(UIView *)view - (instancetype)initWithParentView:(UIView *)view
{ {
self = [super init]; self = [super init];
@@ -56,7 +60,10 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
return self; return self;
} }
+ (void)updateAvailableArea:(CGRect)frame { [[self buttons].sideView updateAvailableArea:frame]; } + (void)updateAvailableArea:(CGRect)frame
{
[[self buttons].sideView updateAvailableArea:frame];
}
- (void)zoomIn - (void)zoomIn
{ {
@@ -82,22 +89,25 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
[locBtn.imageView stopRotation]; [locBtn.imageView stopRotation];
switch (state) switch (state)
{ {
case MWMMyPositionModePendingPosition: case MWMMyPositionModePendingPosition:
{ {
[locBtn setStyleNameAndApply: @"ButtonPending"]; [locBtn setStyleNameAndApply:@"ButtonPending"];
[locBtn.imageView startRotation:1]; [locBtn.imageView startRotation:1];
break; break;
} }
case MWMMyPositionModeNotFollow: case MWMMyPositionModeNotFollow:
case MWMMyPositionModeNotFollowNoPosition: [locBtn setStyleNameAndApply: @"ButtonGetPosition"]; break; case MWMMyPositionModeNotFollowNoPosition: [locBtn setStyleNameAndApply:@"ButtonGetPosition"]; break;
case MWMMyPositionModeFollow: [locBtn setStyleNameAndApply: @"ButtonFollow"]; break; case MWMMyPositionModeFollow: [locBtn setStyleNameAndApply:@"ButtonFollow"]; break;
case MWMMyPositionModeFollowAndRotate: [locBtn setStyleNameAndApply: @"ButtonFollowAndRotate"]; break; case MWMMyPositionModeFollowAndRotate: [locBtn setStyleNameAndApply:@"ButtonFollowAndRotate"]; break;
} }
} }
#pragma mark - Actions #pragma mark - Actions
- (IBAction)zoomTouchDown:(UIButton *)sender { self.zoomSwipeEnabled = YES; } - (IBAction)zoomTouchDown:(UIButton *)sender
{
self.zoomSwipeEnabled = YES;
}
- (IBAction)zoomTouchUpInside:(UIButton *)sender - (IBAction)zoomTouchUpInside:(UIButton *)sender
{ {
self.zoomSwipeEnabled = NO; self.zoomSwipeEnabled = NO;
@@ -107,14 +117,16 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
[self zoomOut]; [self zoomOut];
} }
- (IBAction)zoomTouchUpOutside:(UIButton *)sender { self.zoomSwipeEnabled = NO; } - (IBAction)zoomTouchUpOutside:(UIButton *)sender
{
self.zoomSwipeEnabled = NO;
}
- (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender - (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender
{ {
if (!self.zoomSwipeEnabled) if (!self.zoomSwipeEnabled)
return; return;
UIView * const superview = self.sideView.superview; UIView * const superview = self.sideView.superview;
CGFloat const translation = CGFloat const translation = -[sender translationInView:superview].y / superview.bounds.size.height;
-[sender translationInView:superview].y / superview.bounds.size.height;
CGFloat const scaleFactor = exp(translation); CGFloat const scaleFactor = exp(translation);
GetFramework().Scale(scaleFactor, false); GetFramework().Scale(scaleFactor, false);
@@ -128,7 +140,10 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
#pragma mark - Properties #pragma mark - Properties
- (BOOL)zoomHidden { return self.sideView.zoomHidden; } - (BOOL)zoomHidden
{
return self.sideView.zoomHidden;
}
- (void)setZoomHidden:(BOOL)zoomHidden - (void)setZoomHidden:(BOOL)zoomHidden
{ {
if ([MWMRouter isRoutingActive]) if ([MWMRouter isRoutingActive])
@@ -137,8 +152,11 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
self.sideView.zoomHidden = [MWMSettings zoomButtonsEnabled] ? zoomHidden : YES; self.sideView.zoomHidden = [MWMSettings zoomButtonsEnabled] ? zoomHidden : YES;
} }
- (BOOL)hidden { return self.sideView.hidden; } - (BOOL)hidden
- (void)setHidden:(BOOL)hidden {
return self.sideView.hidden;
}
- (void)setHidden:(BOOL)hidden
{ {
if (!self.hidden && hidden) if (!self.hidden && hidden)
[Toast showWithText:L(@"long_tap_toast")]; [Toast showWithText:L(@"long_tap_toast")];

View File

@@ -1,11 +1,12 @@
#import "MWMSideButtonsView.h" #import "MWMSideButtonsView.h"
#import "MWMButton.h" #import "MWMButton.h"
#import "MWMRouter.h"
#import "MWMMapViewControlsCommon.h" #import "MWMMapViewControlsCommon.h"
#import "MWMRouter.h"
#include "base/math.hpp" #include "base/math.hpp"
namespace { namespace
{
CGFloat const kLocationButtonSpacingMax = 52; CGFloat const kLocationButtonSpacingMax = 52;
CGFloat const kLocationButtonSpacingMin = 8; CGFloat const kLocationButtonSpacingMin = 8;
CGFloat const kButtonsTopOffset = 6; CGFloat const kButtonsTopOffset = 6;
@@ -14,9 +15,9 @@ CGFloat const kButtonsBottomOffset = 6;
@interface MWMSideButtonsView () @interface MWMSideButtonsView ()
@property(weak, nonatomic) IBOutlet MWMButton *zoomIn; @property(weak, nonatomic) IBOutlet MWMButton * zoomIn;
@property(weak, nonatomic) IBOutlet MWMButton *zoomOut; @property(weak, nonatomic) IBOutlet MWMButton * zoomOut;
@property(weak, nonatomic) IBOutlet MWMButton *location; @property(weak, nonatomic) IBOutlet MWMButton * location;
@property(nonatomic) CGRect availableArea; @property(nonatomic) CGRect availableArea;
@@ -24,19 +25,25 @@ CGFloat const kButtonsBottomOffset = 6;
@implementation MWMSideButtonsView @implementation MWMSideButtonsView
- (void)awakeFromNib { - (void)awakeFromNib
{
[super awakeFromNib]; [super awakeFromNib];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
} }
- (void)layoutSubviews { - (void)layoutSubviews
{
CGFloat spacing = self.availableHeight - self.zoomOut.maxY - self.location.height; CGFloat spacing = self.availableHeight - self.zoomOut.maxY - self.location.height;
spacing = math::Clamp(spacing, kLocationButtonSpacingMin, kLocationButtonSpacingMax); spacing = math::Clamp(spacing, kLocationButtonSpacingMin, kLocationButtonSpacingMax);
if (!IPAD && (UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeLeft || UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeRight) && [MWMRouter isRoutingActive]) { if (!IPAD &&
(UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeLeft ||
UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeRight) &&
[MWMRouter isRoutingActive])
{
spacing = spacing - 36; spacing = spacing - 36;
} }
self.location.minY = self.zoomOut.maxY + spacing; self.location.minY = self.zoomOut.maxY + spacing;
self.bounds = {{}, {self.zoomOut.width, self.location.maxY}}; self.bounds = {{}, {self.zoomOut.width, self.location.maxY}};
if (self.zoomHidden) if (self.zoomHidden)
@@ -47,14 +54,18 @@ CGFloat const kButtonsBottomOffset = 6;
[super layoutSubviews]; [super layoutSubviews];
} }
- (void)layoutXPosition:(BOOL)hidden { - (void)layoutXPosition:(BOOL)hidden
if (UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) { {
if (UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft)
{
if (hidden) if (hidden)
self.maxX = 0; self.maxX = 0;
else else
self.minX = self.availableArea.origin.x + kViewControlsOffsetToBounds; self.minX = self.availableArea.origin.x + kViewControlsOffsetToBounds;
} else { }
const auto availableAreaMaxX = self.availableArea.origin.x + self.availableArea.size.width; else
{
auto const availableAreaMaxX = self.availableArea.origin.x + self.availableArea.size.width;
if (hidden) if (hidden)
self.minX = self.superview.width; self.minX = self.superview.width;
else else
@@ -62,80 +73,84 @@ CGFloat const kButtonsBottomOffset = 6;
} }
} }
- (void)layoutYPosition { - (void)layoutYPosition
{
CGFloat const centerShift = (self.height - self.zoomIn.midY - self.zoomOut.midY) / 2; CGFloat const centerShift = (self.height - self.zoomIn.midY - self.zoomOut.midY) / 2;
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{
self.midY = centerShift + self.superview.height / 2; self.midY = centerShift + self.superview.height / 2;
if ([MWMRouter isRoutingActive]) { if ([MWMRouter isRoutingActive])
self.midY = self.midY - 18; self.midY = self.midY - 18;
} if (self.maxY > self.bottomBound)
if (self.maxY > self.bottomBound) self.maxY = self.bottomBound;
self.maxY = self.bottomBound; }];
}];
} }
- (void)fadeZoomButtonsShow:(BOOL)show { - (void)fadeZoomButtonsShow:(BOOL)show
{
CGFloat const alpha = show ? 1.0 : 0.0; CGFloat const alpha = show ? 1.0 : 0.0;
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{
self.zoomIn.alpha = alpha; self.zoomIn.alpha = alpha;
self.zoomOut.alpha = alpha; self.zoomOut.alpha = alpha;
}]; }];
} }
- (void)fadeLocationButtonShow:(BOOL)show { - (void)fadeLocationButtonShow:(BOOL)show
[UIView animateWithDuration:kDefaultAnimationDuration {
animations:^{ [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ self.location.alpha = show ? 1.0 : 0.0; }];
self.location.alpha = show ? 1.0 : 0.0;
}];
} }
// Show/hide zoom and location buttons depending on available vertical space. // Show/hide zoom and location buttons depending on available vertical space.
- (void)animate { - (void)animate
{
[self layoutYPosition]; [self layoutYPosition];
BOOL const isZoomHidden = self.zoomIn.alpha == 0.0; BOOL const isZoomHidden = self.zoomIn.alpha == 0.0;
BOOL const willZoomHide = (self.location.maxY > self.availableHeight); BOOL const willZoomHide = (self.location.maxY > self.availableHeight);
if (willZoomHide != isZoomHidden) if (willZoomHide != isZoomHidden)
[self fadeZoomButtonsShow: !willZoomHide]; [self fadeZoomButtonsShow:!willZoomHide];
BOOL const isLocationHidden = self.location.alpha == 0.0; BOOL const isLocationHidden = self.location.alpha == 0.0;
BOOL const willLocationHide = (self.location.height > self.availableHeight); BOOL const willLocationHide = (self.location.height > self.availableHeight);
if (willLocationHide != isLocationHidden) if (willLocationHide != isLocationHidden)
[self fadeLocationButtonShow: !willLocationHide]; [self fadeLocationButtonShow:!willLocationHide];
} }
#pragma mark - Properties #pragma mark - Properties
- (void)setZoomHidden:(BOOL)zoomHidden { - (void)setZoomHidden:(BOOL)zoomHidden
{
_zoomHidden = zoomHidden; _zoomHidden = zoomHidden;
self.zoomIn.hidden = zoomHidden; self.zoomIn.hidden = zoomHidden;
self.zoomOut.hidden = zoomHidden; self.zoomOut.hidden = zoomHidden;
[self setNeedsLayout]; [self setNeedsLayout];
} }
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated { - (void)setHidden:(BOOL)hidden animated:(BOOL)animated
if (animated) { {
if (animated)
{
if (self.hidden == hidden) if (self.hidden == hidden)
return; return;
// Side buttons should be visible during any our show/hide anamation. // Side buttons should be visible during any our show/hide anamation.
// Visibility should be detemined by alpha, not self.hidden. // Visibility should be detemined by alpha, not self.hidden.
self.hidden = NO; self.hidden = NO;
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{
self.alpha = hidden ? 0.0 : 1.0; self.alpha = hidden ? 0.0 : 1.0;
[self layoutXPosition:hidden]; [self layoutXPosition:hidden];
} }
completion:^(BOOL finished) { completion:^(BOOL finished) { self.hidden = hidden; }];
self.hidden = hidden; }
}]; else
} else { {
self.hidden = hidden; self.hidden = hidden;
} }
} }
- (void)updateAvailableArea:(CGRect)frame { - (void)updateAvailableArea:(CGRect)frame
{
if (CGRectEqualToRect(self.availableArea, frame)) if (CGRectEqualToRect(self.availableArea, frame))
return; return;
// If during our show/hide animation position is changed it is corrupted. // If during our show/hide animation position is changed it is corrupted.
@@ -155,14 +170,17 @@ CGFloat const kButtonsBottomOffset = 6;
[self setNeedsLayout]; [self setNeedsLayout];
} }
- (CGFloat)availableHeight { - (CGFloat)availableHeight
{
return self.availableArea.size.height - kButtonsTopOffset - kButtonsBottomOffset; return self.availableArea.size.height - kButtonsTopOffset - kButtonsBottomOffset;
} }
- (CGFloat)topBound { - (CGFloat)topBound
{
return self.availableArea.origin.y + kButtonsTopOffset; return self.availableArea.origin.y + kButtonsTopOffset;
} }
- (CGFloat)bottomBound { - (CGFloat)bottomBound
{
auto const area = self.availableArea; auto const area = self.availableArea;
return area.origin.y + area.size.height - kButtonsBottomOffset; return area.origin.y + area.size.height - kButtonsBottomOffset;
} }

View File

@@ -2,22 +2,20 @@
#import "MWMZoomButtonsView.h" #import "MWMZoomButtonsView.h"
#import "Statistics.h" #import "Statistics.h"
#include "Framework.h" #include "Framework.h"
#include "platform/settings.hpp"
#include "indexer/scales.hpp" #include "indexer/scales.hpp"
#include "platform/settings.hpp"
static NSString * const kMWMZoomButtonsViewNibName = @"MWMZoomButtonsView"; static NSString * const kMWMZoomButtonsViewNibName = @"MWMZoomButtonsView";
@interface MWMZoomButtons ()
@interface MWMZoomButtons() @property(nonatomic) IBOutlet MWMZoomButtonsView * zoomView;
@property(weak, nonatomic) IBOutlet UIButton * zoomInButton;
@property(weak, nonatomic) IBOutlet UIButton * zoomOutButton;
@property (nonatomic) IBOutlet MWMZoomButtonsView * zoomView; @property(nonatomic) BOOL zoomSwipeEnabled;
@property (weak, nonatomic) IBOutlet UIButton * zoomInButton; @property(nonatomic, readonly) BOOL isZoomEnabled;
@property (weak, nonatomic) IBOutlet UIButton * zoomOutButton;
@property (nonatomic) BOOL zoomSwipeEnabled;
@property (nonatomic, readonly) BOOL isZoomEnabled;
@end @end

View File

@@ -1,5 +1,5 @@
#import "Common.h"
#import "MWMZoomButtonsView.h" #import "MWMZoomButtonsView.h"
#import "Common.h"
#import "MWMMapViewControlsCommon.h" #import "MWMMapViewControlsCommon.h"
static CGFloat const kZoomViewOffsetToTopBound = 12.0; static CGFloat const kZoomViewOffsetToTopBound = 12.0;
@@ -7,9 +7,9 @@ static CGFloat const kZoomViewOffsetToBottomBound = 40.0;
static CGFloat const kZoomViewOffsetToFrameBound = 294.0; static CGFloat const kZoomViewOffsetToFrameBound = 294.0;
static CGFloat const kZoomViewHideBoundPercent = 0.4; static CGFloat const kZoomViewHideBoundPercent = 0.4;
@interface MWMZoomButtonsView() @interface MWMZoomButtonsView ()
@property (nonatomic) CGRect defaultBounds; @property(nonatomic) CGRect defaultBounds;
@end @end
@@ -39,7 +39,8 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
- (void)layoutYPosition - (void)layoutYPosition
{ {
CGFloat const maxY = MIN(self.superview.height - kZoomViewOffsetToFrameBound, self.bottomBound - kZoomViewOffsetToBottomBound); CGFloat const maxY =
MIN(self.superview.height - kZoomViewOffsetToFrameBound, self.bottomBound - kZoomViewOffsetToBottomBound);
self.minY = MAX(maxY - self.height, self.topBound + kZoomViewOffsetToTopBound); self.minY = MAX(maxY - self.height, self.topBound + kZoomViewOffsetToTopBound);
} }
@@ -59,7 +60,8 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
{ {
CGFloat const hideBound = kZoomViewHideBoundPercent * self.superview.height; CGFloat const hideBound = kZoomViewHideBoundPercent * self.superview.height;
BOOL const isHidden = self.alpha == 0.0; BOOL const isHidden = self.alpha == 0.0;
BOOL const willHide = (self.bottomBound < hideBound) || (self.defaultBounds.size.height > self.bottomBound - self.topBound); BOOL const willHide =
(self.bottomBound < hideBound) || (self.defaultBounds.size.height > self.bottomBound - self.topBound);
if (willHide) if (willHide)
{ {
if (!isHidden) if (!isHidden)
@@ -84,15 +86,12 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
if (!hidden) if (!hidden)
self.hidden = NO; self.hidden = NO;
[self layoutXPosition:!hidden]; [self layoutXPosition:!hidden];
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^ [UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount)
{ animations:^{ [self layoutXPosition:hidden]; }
[self layoutXPosition:hidden]; completion:^(BOOL finished) {
} if (hidden)
completion:^(BOOL finished) self.hidden = YES;
{ }];
if (hidden)
self.hidden = YES;
}];
} }
else else
{ {

View File

@@ -10,16 +10,19 @@
#import "SwiftBridge.h" #import "SwiftBridge.h"
#import "base/assert.hpp" #import "base/assert.hpp"
namespace { namespace
{
CGFloat const kTopOffset = 6; CGFloat const kTopOffset = 6;
NSArray<UIImage *> *imagesWithName(NSString *name) { NSArray<UIImage *> * imagesWithName(NSString * name)
{
NSUInteger const imagesCount = 3; NSUInteger const imagesCount = 3;
NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:imagesCount]; NSMutableArray<UIImage *> * images = [NSMutableArray arrayWithCapacity:imagesCount];
NSString *mode = [UIColor isNightMode] ? @"dark" : @"light"; NSString * mode = [UIColor isNightMode] ? @"dark" : @"light";
for (NSUInteger i = 1; i <= imagesCount; i += 1) { for (NSUInteger i = 1; i <= imagesCount; i += 1)
NSString *imageName = [NSString stringWithFormat:@"%@_%@_%@", name, mode, @(i).stringValue]; {
[images addObject:static_cast<UIImage *_Nonnull>([UIImage imageNamed:imageName])]; NSString * imageName = [NSString stringWithFormat:@"%@_%@_%@", name, mode, @(i).stringValue];
[images addObject:static_cast<UIImage * _Nonnull>([UIImage imageNamed:imageName])];
} }
return [images copy]; return [images copy];
} }
@@ -27,28 +30,31 @@ NSArray<UIImage *> *imagesWithName(NSString *name) {
@interface MWMMapViewControlsManager () @interface MWMMapViewControlsManager ()
@property(nonatomic) MWMTrafficButtonViewController *trafficButton; @property(nonatomic) MWMTrafficButtonViewController * trafficButton;
@end @end
@interface MWMTrafficButtonViewController () <MWMMapOverlayManagerObserver, ThemeListener> @interface MWMTrafficButtonViewController () <MWMMapOverlayManagerObserver, ThemeListener>
@property(nonatomic) NSLayoutConstraint *topOffset; @property(nonatomic) NSLayoutConstraint * topOffset;
@property(nonatomic) NSLayoutConstraint *leftOffset; @property(nonatomic) NSLayoutConstraint * leftOffset;
@property(nonatomic) CGRect availableArea; @property(nonatomic) CGRect availableArea;
@end @end
@implementation MWMTrafficButtonViewController @implementation MWMTrafficButtonViewController
+ (MWMTrafficButtonViewController *)controller { + (MWMTrafficButtonViewController *)controller
{
return [MWMMapViewControlsManager manager].trafficButton; return [MWMMapViewControlsManager manager].trafficButton;
} }
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
MapViewController *ovc = [MapViewController sharedController]; {
MapViewController * ovc = [MapViewController sharedController];
[ovc addChildViewController:self]; [ovc addChildViewController:self];
[ovc.controlsView addSubview:self.view]; [ovc.controlsView addSubview:self.view];
[self configLayout]; [self configLayout];
@@ -59,18 +65,21 @@ NSArray<UIImage *> *imagesWithName(NSString *name) {
return self; return self;
} }
- (void)dealloc { - (void)dealloc
{
[StyleManager.shared removeListener:self]; [StyleManager.shared removeListener:self];
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[Toast hideAll]; [Toast hideAll];
} }
- (void)configLayout { - (void)configLayout
UIView *sv = self.view; {
UIView *ov = sv.superview; UIView * sv = self.view;
UIView * ov = sv.superview;
self.topOffset = [sv.topAnchor constraintEqualToAnchor:ov.topAnchor constant:kTopOffset]; self.topOffset = [sv.topAnchor constraintEqualToAnchor:ov.topAnchor constant:kTopOffset];
self.topOffset.active = YES; self.topOffset.active = YES;
@@ -78,12 +87,14 @@ NSArray<UIImage *> *imagesWithName(NSString *name) {
self.leftOffset.active = YES; self.leftOffset.active = YES;
} }
- (void)setHidden:(BOOL)hidden { - (void)setHidden:(BOOL)hidden
{
_hidden = hidden; _hidden = hidden;
[self refreshLayout]; [self refreshLayout];
} }
- (void)refreshLayout { - (void)refreshLayout
{
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
auto const availableArea = self.availableArea; auto const availableArea = self.availableArea;
auto const fitInAvailableArea = CGRectGetMaxY(self.view.frame) < CGRectGetMaxY(availableArea) + kTopOffset; auto const fitInAvailableArea = CGRectGetMaxY(self.view.frame) < CGRectGetMaxY(availableArea) + kTopOffset;
@@ -97,102 +108,111 @@ NSArray<UIImage *> *imagesWithName(NSString *name) {
}); });
} }
- (void)handleTrafficState:(MWMMapOverlayTrafficState)state { - (void)handleTrafficState:(MWMMapOverlayTrafficState)state
MWMButton *btn = (MWMButton *)self.view; {
UIImageView *iv = btn.imageView; MWMButton * btn = (MWMButton *)self.view;
switch (state) { UIImageView * iv = btn.imageView;
case MWMMapOverlayTrafficStateDisabled: switch (state)
CHECK(false, ("Incorrect traffic manager state.")); {
break; case MWMMapOverlayTrafficStateDisabled: CHECK(false, ("Incorrect traffic manager state.")); break;
case MWMMapOverlayTrafficStateEnabled: case MWMMapOverlayTrafficStateEnabled: btn.imageName = @"btn_traffic_on"; break;
btn.imageName = @"btn_traffic_on"; case MWMMapOverlayTrafficStateWaitingData:
break; iv.animationImages = imagesWithName(@"btn_traffic_update");
case MWMMapOverlayTrafficStateWaitingData: iv.animationDuration = 0.8;
iv.animationImages = imagesWithName(@"btn_traffic_update"); [iv startAnimating];
iv.animationDuration = 0.8; break;
[iv startAnimating]; case MWMMapOverlayTrafficStateOutdated: btn.imageName = @"btn_traffic_outdated"; break;
break; case MWMMapOverlayTrafficStateNoData:
case MWMMapOverlayTrafficStateOutdated: btn.imageName = @"btn_traffic_on";
btn.imageName = @"btn_traffic_outdated"; [Toast showWithText:L(@"traffic_data_unavailable")];
break; break;
case MWMMapOverlayTrafficStateNoData: case MWMMapOverlayTrafficStateNetworkError:
btn.imageName = @"btn_traffic_on"; [MWMMapOverlayManager setTrafficEnabled:NO];
[Toast showWithText:L(@"traffic_data_unavailable")]; [[MWMAlertViewController activeAlertController] presentNoConnectionAlert];
break; break;
case MWMMapOverlayTrafficStateNetworkError: case MWMMapOverlayTrafficStateExpiredData:
[MWMMapOverlayManager setTrafficEnabled:NO]; btn.imageName = @"btn_traffic_outdated";
[[MWMAlertViewController activeAlertController] presentNoConnectionAlert]; [Toast showWithText:L(@"traffic_update_maps_text")];
break; break;
case MWMMapOverlayTrafficStateExpiredData: case MWMMapOverlayTrafficStateExpiredApp:
btn.imageName = @"btn_traffic_outdated"; btn.imageName = @"btn_traffic_outdated";
[Toast showWithText:L(@"traffic_update_maps_text")]; [Toast showWithText:L(@"traffic_update_app_message")];
break; break;
case MWMMapOverlayTrafficStateExpiredApp:
btn.imageName = @"btn_traffic_outdated";
[Toast showWithText:L(@"traffic_update_app_message")];
break;
} }
} }
- (void)handleIsolinesState:(MWMMapOverlayIsolinesState)state { - (void)handleIsolinesState:(MWMMapOverlayIsolinesState)state
switch (state) { {
case MWMMapOverlayIsolinesStateDisabled: switch (state)
break; {
case MWMMapOverlayIsolinesStateEnabled: case MWMMapOverlayIsolinesStateDisabled: break;
if (![MWMMapOverlayManager isolinesVisible]) case MWMMapOverlayIsolinesStateEnabled:
[Toast showWithText:L(@"isolines_toast_zooms_1_10")]; if (![MWMMapOverlayManager isolinesVisible])
break; [Toast showWithText:L(@"isolines_toast_zooms_1_10")];
case MWMMapOverlayIsolinesStateExpiredData: break;
[MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_activation_error_dialog")]; case MWMMapOverlayIsolinesStateExpiredData:
[MWMMapOverlayManager setIsoLinesEnabled:NO]; [MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_activation_error_dialog")];
break; [MWMMapOverlayManager setIsoLinesEnabled:NO];
case MWMMapOverlayIsolinesStateNoData: break;
[MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_location_error_dialog")]; case MWMMapOverlayIsolinesStateNoData:
[MWMMapOverlayManager setIsoLinesEnabled:NO]; [MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_location_error_dialog")];
break; [MWMMapOverlayManager setIsoLinesEnabled:NO];
break;
} }
} }
- (void)applyTheme { - (void)applyTheme
MWMButton *btn = static_cast<MWMButton *>(self.view); {
UIImageView *iv = btn.imageView; MWMButton * btn = static_cast<MWMButton *>(self.view);
UIImageView * iv = btn.imageView;
// Traffic state machine: https://confluence.mail.ru/pages/viewpage.action?pageId=103680959 // Traffic state machine: https://confluence.mail.ru/pages/viewpage.action?pageId=103680959
[iv stopAnimating]; [iv stopAnimating];
if ([MWMMapOverlayManager trafficEnabled]) { if ([MWMMapOverlayManager trafficEnabled])
{
[self handleTrafficState:[MWMMapOverlayManager trafficState]]; [self handleTrafficState:[MWMMapOverlayManager trafficState]];
} else if ([MWMMapOverlayManager transitEnabled]) { }
else if ([MWMMapOverlayManager transitEnabled])
{
btn.imageName = @"btn_subway_on"; btn.imageName = @"btn_subway_on";
if ([MWMMapOverlayManager transitState] == MWMMapOverlayTransitStateNoData) if ([MWMMapOverlayManager transitState] == MWMMapOverlayTransitStateNoData)
[Toast showWithText:L(@"subway_data_unavailable")]; [Toast showWithText:L(@"subway_data_unavailable")];
} else if ([MWMMapOverlayManager isoLinesEnabled]) { }
else if ([MWMMapOverlayManager isoLinesEnabled])
{
btn.imageName = @"btn_isoMap_on"; btn.imageName = @"btn_isoMap_on";
[self handleIsolinesState:[MWMMapOverlayManager isolinesState]]; [self handleIsolinesState:[MWMMapOverlayManager isolinesState]];
} else if ([MWMMapOverlayManager outdoorEnabled]) { }
else if ([MWMMapOverlayManager outdoorEnabled])
{
btn.imageName = @"btn_isoMap_on"; btn.imageName = @"btn_isoMap_on";
} else { }
else
{
btn.imageName = @"btn_layers"; btn.imageName = @"btn_layers";
} }
} }
- (IBAction)buttonTouchUpInside { - (IBAction)buttonTouchUpInside
BOOL needsToDisableMapLayer = {
[MWMMapOverlayManager trafficEnabled] || BOOL needsToDisableMapLayer = [MWMMapOverlayManager trafficEnabled] || [MWMMapOverlayManager transitEnabled] ||
[MWMMapOverlayManager transitEnabled] || [MWMMapOverlayManager isoLinesEnabled] || [MWMMapOverlayManager outdoorEnabled];
[MWMMapOverlayManager isoLinesEnabled] ||
[MWMMapOverlayManager outdoorEnabled];
if (needsToDisableMapLayer) { if (needsToDisableMapLayer)
{
[MWMMapOverlayManager setTrafficEnabled:NO]; [MWMMapOverlayManager setTrafficEnabled:NO];
[MWMMapOverlayManager setTransitEnabled:NO]; [MWMMapOverlayManager setTransitEnabled:NO];
[MWMMapOverlayManager setIsoLinesEnabled:NO]; [MWMMapOverlayManager setIsoLinesEnabled:NO];
[MWMMapOverlayManager setOutdoorEnabled:NO]; [MWMMapOverlayManager setOutdoorEnabled:NO];
} else { }
else
{
MWMMapViewControlsManager.manager.menuState = MWMBottomMenuStateLayers; MWMMapViewControlsManager.manager.menuState = MWMBottomMenuStateLayers;
} }
} }
+ (void)updateAvailableArea:(CGRect)frame { + (void)updateAvailableArea:(CGRect)frame
{
auto controller = [self controller]; auto controller = [self controller];
if (CGRectEqualToRect(controller.availableArea, frame)) if (CGRectEqualToRect(controller.availableArea, frame))
return; return;
@@ -202,16 +222,20 @@ NSArray<UIImage *> *imagesWithName(NSString *name) {
#pragma mark - MWMMapOverlayManagerObserver #pragma mark - MWMMapOverlayManagerObserver
- (void)onTrafficStateUpdated { - (void)onTrafficStateUpdated
{
[self applyTheme]; [self applyTheme];
} }
- (void)onTransitStateUpdated { - (void)onTransitStateUpdated
{
[self applyTheme]; [self applyTheme];
} }
- (void)onIsoLinesStateUpdated { - (void)onIsoLinesStateUpdated
{
[self applyTheme]; [self applyTheme];
} }
- (void)onOutdoorStateUpdated { - (void)onOutdoorStateUpdated
{
[self applyTheme]; [self applyTheme];
} }

View File

@@ -6,8 +6,8 @@
#import "SwiftBridge.h" #import "SwiftBridge.h"
#import <AudioToolbox/AudioServices.h> #import <AudioToolbox/AudioServices.h>
#import <CoreApi/Framework.h>
#import <CoreApi/DurationFormatter.h> #import <CoreApi/DurationFormatter.h>
#import <CoreApi/Framework.h>
#include "routing/following_info.hpp" #include "routing/following_info.hpp"
#include "routing/turns.hpp" #include "routing/turns.hpp"
@@ -18,75 +18,83 @@
#include "geometry/distance_on_sphere.hpp" #include "geometry/distance_on_sphere.hpp"
namespace { namespace
UIImage * image(routing::turns::CarDirection t, bool isNextTurn) { {
UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
{
if (![MWMLocationManager lastLocation]) if (![MWMLocationManager lastLocation])
return nil; return nil;
using namespace routing::turns; using namespace routing::turns;
NSString * imageName; NSString * imageName;
switch (t) { switch (t)
case CarDirection::ExitHighwayToRight: imageName = @"ic_exit_highway_to_right"; break; {
case CarDirection::TurnSlightRight: imageName = @"slight_right"; break; case CarDirection::ExitHighwayToRight: imageName = @"ic_exit_highway_to_right"; break;
case CarDirection::TurnRight: imageName = @"simple_right"; break; case CarDirection::TurnSlightRight: imageName = @"slight_right"; break;
case CarDirection::TurnSharpRight: imageName = @"sharp_right"; break; case CarDirection::TurnRight: imageName = @"simple_right"; break;
case CarDirection::ExitHighwayToLeft: imageName = @"ic_exit_highway_to_left"; break; case CarDirection::TurnSharpRight: imageName = @"sharp_right"; break;
case CarDirection::TurnSlightLeft: imageName = @"slight_left"; break; case CarDirection::ExitHighwayToLeft: imageName = @"ic_exit_highway_to_left"; break;
case CarDirection::TurnLeft: imageName = @"simple_left"; break; case CarDirection::TurnSlightLeft: imageName = @"slight_left"; break;
case CarDirection::TurnSharpLeft: imageName = @"sharp_left"; break; case CarDirection::TurnLeft: imageName = @"simple_left"; break;
case CarDirection::UTurnLeft: imageName = @"uturn_left"; break; case CarDirection::TurnSharpLeft: imageName = @"sharp_left"; break;
case CarDirection::UTurnRight: imageName = @"uturn_right"; break; case CarDirection::UTurnLeft: imageName = @"uturn_left"; break;
case CarDirection::ReachedYourDestination: imageName = @"finish_point"; break; case CarDirection::UTurnRight: imageName = @"uturn_right"; break;
case CarDirection::LeaveRoundAbout: case CarDirection::ReachedYourDestination: imageName = @"finish_point"; break;
case CarDirection::EnterRoundAbout: imageName = @"round"; break; case CarDirection::LeaveRoundAbout:
case CarDirection::GoStraight: imageName = @"straight"; break; case CarDirection::EnterRoundAbout: imageName = @"round"; break;
case CarDirection::StartAtEndOfStreet: case CarDirection::GoStraight: imageName = @"straight"; break;
case CarDirection::StayOnRoundAbout: case CarDirection::StartAtEndOfStreet:
case CarDirection::Count: case CarDirection::StayOnRoundAbout:
case CarDirection::None: imageName = isNextTurn ? nil : @"straight"; break; case CarDirection::Count:
case CarDirection::None: imageName = isNextTurn ? nil : @"straight"; break;
} }
if (!imageName) if (!imageName)
return nil; return nil;
return [UIImage imageNamed:isNextTurn ? [imageName stringByAppendingString:@"_then"] : imageName]; return [UIImage imageNamed:isNextTurn ? [imageName stringByAppendingString:@"_then"] : imageName];
} }
UIImage * image(routing::turns::PedestrianDirection t) { UIImage * image(routing::turns::PedestrianDirection t)
{
if (![MWMLocationManager lastLocation]) if (![MWMLocationManager lastLocation])
return nil; return nil;
using namespace routing::turns; using namespace routing::turns;
NSString * imageName; NSString * imageName;
switch (t) { switch (t)
case PedestrianDirection::TurnRight: imageName = @"simple_right"; break; {
case PedestrianDirection::TurnLeft: imageName = @"simple_left"; break; case PedestrianDirection::TurnRight: imageName = @"simple_right"; break;
case PedestrianDirection::ReachedYourDestination: imageName = @"finish_point"; break; case PedestrianDirection::TurnLeft: imageName = @"simple_left"; break;
case PedestrianDirection::GoStraight: case PedestrianDirection::ReachedYourDestination: imageName = @"finish_point"; break;
case PedestrianDirection::Count: case PedestrianDirection::GoStraight:
case PedestrianDirection::None: imageName = @"straight"; break; case PedestrianDirection::Count:
case PedestrianDirection::None: imageName = @"straight"; break;
} }
if (!imageName) if (!imageName)
return nil; return nil;
return [UIImage imageNamed:imageName]; return [UIImage imageNamed:imageName];
} }
NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoint *> *points) { NSArray<MWMRouterTransitStepInfo *> * buildRouteTransitSteps(NSArray<MWMRoutePoint *> * points)
{
// Generate step info in format: (Segment 1 distance) (1) (Segment 2 distance) (2) ... (n-1) (Segment N distance). // Generate step info in format: (Segment 1 distance) (1) (Segment 2 distance) (2) ... (n-1) (Segment N distance).
NSMutableArray<MWMRouterTransitStepInfo *> * steps = [NSMutableArray arrayWithCapacity:[points count] * 2 - 1]; NSMutableArray<MWMRouterTransitStepInfo *> * steps = [NSMutableArray arrayWithCapacity:[points count] * 2 - 1];
auto const numPoints = [points count]; auto const numPoints = [points count];
for (int i = 0; i < numPoints - 1; i++) { for (int i = 0; i < numPoints - 1; i++)
MWMRoutePoint* segmentStart = points[i]; {
MWMRoutePoint* segmentEnd = points[i + 1]; MWMRoutePoint * segmentStart = points[i];
MWMRoutePoint * segmentEnd = points[i + 1];
auto const distance = platform::Distance::CreateFormatted( auto const distance = platform::Distance::CreateFormatted(
ms::DistanceOnEarth(segmentStart.latitude, segmentStart.longitude, segmentEnd.latitude, segmentEnd.longitude)); ms::DistanceOnEarth(segmentStart.latitude, segmentStart.longitude, segmentEnd.latitude, segmentEnd.longitude));
MWMRouterTransitStepInfo* segmentInfo = [[MWMRouterTransitStepInfo alloc] init]; MWMRouterTransitStepInfo * segmentInfo = [[MWMRouterTransitStepInfo alloc] init];
segmentInfo.type = MWMRouterTransitTypeRuler; segmentInfo.type = MWMRouterTransitTypeRuler;
segmentInfo.distance = @(distance.GetDistanceString().c_str()); segmentInfo.distance = @(distance.GetDistanceString().c_str());
segmentInfo.distanceUnits = @(distance.GetUnitsString().c_str()); segmentInfo.distanceUnits = @(distance.GetUnitsString().c_str());
steps[i * 2] = segmentInfo; steps[i * 2] = segmentInfo;
if (i < numPoints - 2) { if (i < numPoints - 2)
MWMRouterTransitStepInfo* stopInfo = [[MWMRouterTransitStepInfo alloc] init]; {
MWMRouterTransitStepInfo * stopInfo = [[MWMRouterTransitStepInfo alloc] init];
stopInfo.type = MWMRouterTransitTypeIntermediatePoint; stopInfo.type = MWMRouterTransitTypeIntermediatePoint;
stopInfo.intermediateIndex = i; stopInfo.intermediateIndex = i;
steps[i * 2 + 1] = stopInfo; steps[i * 2 + 1] = stopInfo;
@@ -129,25 +137,28 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
+ (NSAttributedString *)estimateDot + (NSAttributedString *)estimateDot
{ {
auto attributes = @{ auto attributes =
NSForegroundColorAttributeName: [UIColor blackSecondaryText], @{NSForegroundColorAttributeName: [UIColor blackSecondaryText], NSFontAttributeName: [UIFont medium17]};
NSFontAttributeName: [UIFont medium17]
};
return [[NSAttributedString alloc] initWithString:@" • " attributes:attributes]; return [[NSAttributedString alloc] initWithString:@" • " attributes:attributes];
} }
- (NSAttributedString *)estimate { - (NSAttributedString *)estimate
NSDictionary * primaryAttributes = @{NSForegroundColorAttributeName: [UIColor blackPrimaryText], NSFontAttributeName: [UIFont medium17]}; {
NSDictionary * secondaryAttributes = @{NSForegroundColorAttributeName: [UIColor blackSecondaryText], NSFontAttributeName: [UIFont medium17]}; NSDictionary * primaryAttributes =
@{NSForegroundColorAttributeName: [UIColor blackPrimaryText], NSFontAttributeName: [UIFont medium17]};
NSDictionary * secondaryAttributes =
@{NSForegroundColorAttributeName: [UIColor blackSecondaryText], NSFontAttributeName: [UIFont medium17]};
auto result = [[NSMutableAttributedString alloc] initWithString:@""]; auto result = [[NSMutableAttributedString alloc] initWithString:@""];
if (self.showEta) { if (self.showEta)
{
NSString * eta = [DurationFormatter durationStringFromTimeInterval:self.timeToTarget]; NSString * eta = [DurationFormatter durationStringFromTimeInterval:self.timeToTarget];
[result appendAttributedString:[[NSMutableAttributedString alloc] initWithString:eta attributes:primaryAttributes]]; [result appendAttributedString:[[NSMutableAttributedString alloc] initWithString:eta attributes:primaryAttributes]];
[result appendAttributedString:MWMNavigationDashboardEntity.estimateDot]; [result appendAttributedString:MWMNavigationDashboardEntity.estimateDot];
} }
if (self.isWalk) { if (self.isWalk)
{
UIFont * font = primaryAttributes[NSFontAttributeName]; UIFont * font = primaryAttributes[NSFontAttributeName];
auto textAttachment = [[NSTextAttachment alloc] init]; auto textAttachment = [[NSTextAttachment alloc] init];
auto image = [UIImage imageNamed:@"ic_walk"]; auto image = [UIImage imageNamed:@"ic_walk"];
@@ -158,7 +169,7 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
textAttachment.bounds = CGRectIntegral({{0, y}, {width, height}}); textAttachment.bounds = CGRectIntegral({{0, y}, {width, height}});
NSMutableAttributedString * attrStringWithImage = NSMutableAttributedString * attrStringWithImage =
[NSAttributedString attributedStringWithAttachment:textAttachment].mutableCopy; [NSAttributedString attributedStringWithAttachment:textAttachment].mutableCopy;
[attrStringWithImage addAttributes:secondaryAttributes range:NSMakeRange(0, attrStringWithImage.length)]; [attrStringWithImage addAttributes:secondaryAttributes range:NSMakeRange(0, attrStringWithImage.length)];
[result appendAttributedString:attrStringWithImage]; [result appendAttributedString:attrStringWithImage];
} }
@@ -189,16 +200,21 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
@implementation MWMNavigationDashboardManager (Entity) @implementation MWMNavigationDashboardManager (Entity)
- (void)updateFollowingInfo:(routing::FollowingInfo const &)info routePoints:(NSArray<MWMRoutePoint *> *)points type:(MWMRouterType)type { - (void)updateFollowingInfo:(routing::FollowingInfo const &)info
if ([MWMRouter isRouteFinished]) { routePoints:(NSArray<MWMRoutePoint *> *)points
type:(MWMRouterType)type
{
if ([MWMRouter isRouteFinished])
{
[MWMRouter stopRouting]; [MWMRouter stopRouting];
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
return; return;
} }
if (auto entity = self.entity) { if (auto entity = self.entity)
{
BOOL const showEta = (type != MWMRouterTypeRuler); BOOL const showEta = (type != MWMRouterTypeRuler);
entity.isValid = YES; entity.isValid = YES;
entity.timeToTarget = info.m_time; entity.timeToTarget = info.m_time;
entity.targetDistance = @(info.m_distToTarget.GetDistanceString().c_str()); entity.targetDistance = @(info.m_distToTarget.GetDistanceString().c_str());
@@ -217,9 +233,12 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
else else
entity.transitSteps = [[NSArray alloc] init]; entity.transitSteps = [[NSArray alloc] init];
if (type == MWMRouterTypePedestrian) { if (type == MWMRouterTypePedestrian)
{
entity.turnImage = image(info.m_pedestrianTurn); entity.turnImage = image(info.m_pedestrianTurn);
} else { }
else
{
using namespace routing::turns; using namespace routing::turns;
CarDirection const turn = info.m_turn; CarDirection const turn = info.m_turn;
entity.turnImage = image(turn, false); entity.turnImage = image(turn, false);
@@ -236,8 +255,10 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
[self onNavigationInfoUpdated]; [self onNavigationInfoUpdated];
} }
- (void)updateTransitInfo:(TransitRouteInfo const &)info { - (void)updateTransitInfo:(TransitRouteInfo const &)info
if (auto entity = self.entity) { {
if (auto entity = self.entity)
{
entity.timeToTarget = info.m_totalTimeInSec; entity.timeToTarget = info.m_totalTimeInSec;
entity.targetDistance = @(info.m_totalPedestrianDistanceStr.c_str()); entity.targetDistance = @(info.m_totalPedestrianDistanceStr.c_str());
entity.targetUnits = @(info.m_totalPedestrianUnitsSuffix.c_str()); entity.targetUnits = @(info.m_totalPedestrianUnitsSuffix.c_str());
@@ -245,7 +266,7 @@ NSArray<MWMRouterTransitStepInfo *> *buildRouteTransitSteps(NSArray<MWMRoutePoin
entity.isWalk = YES; entity.isWalk = YES;
entity.showEta = YES; entity.showEta = YES;
NSMutableArray<MWMRouterTransitStepInfo *> * transitSteps = [NSMutableArray new]; NSMutableArray<MWMRouterTransitStepInfo *> * transitSteps = [NSMutableArray new];
for (auto const &stepInfo : info.m_steps) for (auto const & stepInfo : info.m_steps)
[transitSteps addObject:[[MWMRouterTransitStepInfo alloc] initWithStepInfo:stepInfo]]; [transitSteps addObject:[[MWMRouterTransitStepInfo alloc] initWithStepInfo:stepInfo]];
entity.transitSteps = transitSteps; entity.transitSteps = transitSteps;
} }

View File

@@ -7,56 +7,60 @@
#import "SwiftBridge.h" #import "SwiftBridge.h"
namespace { namespace
NSString *const kRoutePreviewIPhoneXibName = @"MWMiPhoneRoutePreview"; {
NSString *const kNavigationInfoViewXibName = @"MWMNavigationInfoView"; NSString * const kRoutePreviewIPhoneXibName = @"MWMiPhoneRoutePreview";
NSString *const kNavigationControlViewXibName = @"NavigationControlView"; NSString * const kNavigationInfoViewXibName = @"MWMNavigationInfoView";
NSString * const kNavigationControlViewXibName = @"NavigationControlView";
} // namespace } // namespace
@interface MWMMapViewControlsManager () @interface MWMMapViewControlsManager ()
@property(nonatomic) MWMNavigationDashboardManager *navigationManager; @property(nonatomic) MWMNavigationDashboardManager * navigationManager;
@end @end
@interface MWMNavigationDashboardManager () <SearchOnMapManagerObserver, MWMRoutePreviewDelegate> @interface MWMNavigationDashboardManager () <SearchOnMapManagerObserver, MWMRoutePreviewDelegate>
@property(copy, nonatomic) NSDictionary *etaAttributes; @property(copy, nonatomic) NSDictionary * etaAttributes;
@property(copy, nonatomic) NSDictionary *etaSecondaryAttributes; @property(copy, nonatomic) NSDictionary * etaSecondaryAttributes;
@property(copy, nonatomic) NSString *errorMessage; @property(copy, nonatomic) NSString * errorMessage;
@property(nonatomic) IBOutlet MWMBaseRoutePreviewStatus *baseRoutePreviewStatus; @property(nonatomic) IBOutlet MWMBaseRoutePreviewStatus * baseRoutePreviewStatus;
@property(nonatomic) IBOutlet MWMNavigationControlView *navigationControlView; @property(nonatomic) IBOutlet MWMNavigationControlView * navigationControlView;
@property(nonatomic) IBOutlet MWMNavigationInfoView *navigationInfoView; @property(nonatomic) IBOutlet MWMNavigationInfoView * navigationInfoView;
@property(nonatomic) IBOutlet MWMRoutePreview *routePreview; @property(nonatomic) IBOutlet MWMRoutePreview * routePreview;
@property(nonatomic) IBOutlet MWMTransportRoutePreviewStatus *transportRoutePreviewStatus; @property(nonatomic) IBOutlet MWMTransportRoutePreviewStatus * transportRoutePreviewStatus;
@property(nonatomic) IBOutletCollection(MWMRouteStartButton) NSArray *goButtons; @property(nonatomic) IBOutletCollection(MWMRouteStartButton) NSArray * goButtons;
@property(nonatomic) MWMNavigationDashboardEntity *entity; @property(nonatomic) MWMNavigationDashboardEntity * entity;
@property(nonatomic) MWMRouteManagerTransitioningManager *routeManagerTransitioningManager; @property(nonatomic) MWMRouteManagerTransitioningManager * routeManagerTransitioningManager;
@property(weak, nonatomic) IBOutlet UIButton *showRouteManagerButton; @property(weak, nonatomic) IBOutlet UIButton * showRouteManagerButton;
@property(weak, nonatomic) IBOutlet UIView *goButtonsContainer; @property(weak, nonatomic) IBOutlet UIView * goButtonsContainer;
@property(weak, nonatomic) UIView *ownerView; @property(weak, nonatomic) UIView * ownerView;
@end @end
@implementation MWMNavigationDashboardManager @implementation MWMNavigationDashboardManager
+ (MWMNavigationDashboardManager *)sharedManager { + (MWMNavigationDashboardManager *)sharedManager
{
return [MWMMapViewControlsManager manager].navigationManager; return [MWMMapViewControlsManager manager].navigationManager;
} }
- (instancetype)initWithParentView:(UIView *)view { - (instancetype)initWithParentView:(UIView *)view
{
self = [super init]; self = [super init];
if (self) { if (self)
_ownerView = view; _ownerView = view;
}
return self; return self;
} }
- (SearchOnMapManager *)searchManager { - (SearchOnMapManager *)searchManager
{
return [[MapViewController sharedController] searchManager]; return [[MapViewController sharedController] searchManager];
} }
- (void)loadPreviewWithStatusBoxes { - (void)loadPreviewWithStatusBoxes
{
[NSBundle.mainBundle loadNibNamed:kRoutePreviewIPhoneXibName owner:self options:nil]; [NSBundle.mainBundle loadNibNamed:kRoutePreviewIPhoneXibName owner:self options:nil];
auto ownerView = self.ownerView; auto ownerView = self.ownerView;
_baseRoutePreviewStatus.ownerView = ownerView; _baseRoutePreviewStatus.ownerView = ownerView;
@@ -65,23 +69,27 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - MWMRoutePreview #pragma mark - MWMRoutePreview
- (void)setRouteBuilderProgress:(CGFloat)progress { - (void)setRouteBuilderProgress:(CGFloat)progress
{
[self.routePreview router:[MWMRouter type] setProgress:progress / 100.]; [self.routePreview router:[MWMRouter type] setProgress:progress / 100.];
} }
#pragma mark - MWMNavigationGo #pragma mark - MWMNavigationGo
- (IBAction)routingStartTouchUpInside { - (IBAction)routingStartTouchUpInside
{
[MWMRouter startRouting]; [MWMRouter startRouting];
} }
- (void)updateGoButtonTitle { - (void)updateGoButtonTitle
NSString *title = L(@"p2p_start"); {
NSString * title = L(@"p2p_start");
for (MWMRouteStartButton *button in self.goButtons) for (MWMRouteStartButton * button in self.goButtons)
[button setTitle:title forState:UIControlStateNormal]; [button setTitle:title forState:UIControlStateNormal];
} }
- (void)onNavigationInfoUpdated { - (void)onNavigationInfoUpdated
{
auto entity = self.entity; auto entity = self.entity;
if (!entity.isValid) if (!entity.isValid)
return; return;
@@ -97,34 +105,38 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - On route updates #pragma mark - On route updates
- (void)onRoutePrepare { - (void)onRoutePrepare
{
self.state = MWMNavigationDashboardStatePrepare; self.state = MWMNavigationDashboardStatePrepare;
self.routePreview.drivingOptionsState = MWMDrivingOptionsStateNone; self.routePreview.drivingOptionsState = MWMDrivingOptionsStateNone;
} }
- (void)onRoutePlanning { - (void)onRoutePlanning
{
self.state = MWMNavigationDashboardStatePlanning; self.state = MWMNavigationDashboardStatePlanning;
self.routePreview.drivingOptionsState = MWMDrivingOptionsStateNone; self.routePreview.drivingOptionsState = MWMDrivingOptionsStateNone;
} }
- (void)onRouteError:(NSString *)error { - (void)onRouteError:(NSString *)error
{
self.errorMessage = error; self.errorMessage = error;
self.state = MWMNavigationDashboardStateError; self.state = MWMNavigationDashboardStateError;
self.routePreview.drivingOptionsState = self.routePreview.drivingOptionsState =
[MWMRouter hasActiveDrivingOptions] ? MWMDrivingOptionsStateChange : MWMDrivingOptionsStateNone; [MWMRouter hasActiveDrivingOptions] ? MWMDrivingOptionsStateChange : MWMDrivingOptionsStateNone;
} }
- (void)onRouteReady:(BOOL)hasWarnings { - (void)onRouteReady:(BOOL)hasWarnings
{
if (self.state != MWMNavigationDashboardStateNavigation) if (self.state != MWMNavigationDashboardStateNavigation)
self.state = MWMNavigationDashboardStateReady; self.state = MWMNavigationDashboardStateReady;
if ([MWMRouter hasActiveDrivingOptions]) { if ([MWMRouter hasActiveDrivingOptions])
self.routePreview.drivingOptionsState = MWMDrivingOptionsStateChange; self.routePreview.drivingOptionsState = MWMDrivingOptionsStateChange;
} else { else
self.routePreview.drivingOptionsState = hasWarnings ? MWMDrivingOptionsStateDefine : MWMDrivingOptionsStateNone; self.routePreview.drivingOptionsState = hasWarnings ? MWMDrivingOptionsStateDefine : MWMDrivingOptionsStateNone;
}
} }
- (void)onRoutePointsUpdated { - (void)onRoutePointsUpdated
{
if (self.state == MWMNavigationDashboardStateHidden) if (self.state == MWMNavigationDashboardStateHidden)
self.state = MWMNavigationDashboardStatePrepare; self.state = MWMNavigationDashboardStatePrepare;
[self.navigationInfoView updateToastView]; [self.navigationInfoView updateToastView];
@@ -132,7 +144,8 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - State changes #pragma mark - State changes
- (void)stateHidden { - (void)stateHidden
{
self.routePreview = nil; self.routePreview = nil;
self.navigationInfoView.state = MWMNavigationInfoViewStateHidden; self.navigationInfoView.state = MWMNavigationInfoViewStateHidden;
self.navigationInfoView = nil; self.navigationInfoView = nil;
@@ -143,7 +156,8 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
_transportRoutePreviewStatus = nil; _transportRoutePreviewStatus = nil;
} }
- (void)statePrepare { - (void)statePrepare
{
self.navigationInfoView.state = MWMNavigationInfoViewStatePrepare; self.navigationInfoView.state = MWMNavigationInfoViewStatePrepare;
if (self.searchManager.isSearching) if (self.searchManager.isSearching)
[self.navigationInfoView setSearchState:NavigationSearchState::MinimizedSearch animated:YES]; [self.navigationInfoView setSearchState:NavigationSearchState::MinimizedSearch animated:YES];
@@ -154,17 +168,19 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
[self updateGoButtonTitle]; [self updateGoButtonTitle];
[self.baseRoutePreviewStatus hide]; [self.baseRoutePreviewStatus hide];
[_transportRoutePreviewStatus hide]; [_transportRoutePreviewStatus hide];
for (MWMRouteStartButton *button in self.goButtons) for (MWMRouteStartButton * button in self.goButtons)
[button statePrepare]; [button statePrepare];
} }
- (void)statePlanning { - (void)statePlanning
{
[self statePrepare]; [self statePrepare];
[self.routePreview router:[MWMRouter type] setState:MWMCircularProgressStateSpinner]; [self.routePreview router:[MWMRouter type] setState:MWMCircularProgressStateSpinner];
[self setRouteBuilderProgress:0.]; [self setRouteBuilderProgress:0.];
} }
- (void)stateError { - (void)stateError
{
if (_state == MWMNavigationDashboardStateReady) if (_state == MWMNavigationDashboardStateReady)
return; return;
@@ -173,14 +189,17 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
[routePreview router:[MWMRouter type] setState:MWMCircularProgressStateFailed]; [routePreview router:[MWMRouter type] setState:MWMCircularProgressStateFailed];
[self updateGoButtonTitle]; [self updateGoButtonTitle];
[self.baseRoutePreviewStatus showErrorWithMessage:self.errorMessage]; [self.baseRoutePreviewStatus showErrorWithMessage:self.errorMessage];
for (MWMRouteStartButton *button in self.goButtons) for (MWMRouteStartButton * button in self.goButtons)
[button stateError]; [button stateError];
} }
- (void)stateReady { - (void)stateReady
// TODO: Here assert sometimes fires with _state = MWMNavigationDashboardStateReady, if app was stopped while navigating and then restarted. {
// Also in ruler mode when new point is added by single tap on the map state MWMNavigationDashboardStatePlanning is skipped and we get _state = MWMNavigationDashboardStateReady. // TODO: Here assert sometimes fires with _state = MWMNavigationDashboardStateReady, if app was stopped while
NSAssert(_state == MWMNavigationDashboardStatePlanning || _state == MWMNavigationDashboardStateReady, @"Invalid state change (ready)"); // navigating and then restarted. Also in ruler mode when new point is added by single tap on the map state
// MWMNavigationDashboardStatePlanning is skipped and we get _state = MWMNavigationDashboardStateReady.
NSAssert(_state == MWMNavigationDashboardStatePlanning || _state == MWMNavigationDashboardStateReady,
@"Invalid state change (ready)");
[self setRouteBuilderProgress:100.]; [self setRouteBuilderProgress:100.];
[self updateGoButtonTitle]; [self updateGoButtonTitle];
bool const isTransport = ([MWMRouter type] == MWMRouterTypePublicTransport); bool const isTransport = ([MWMRouter type] == MWMRouterTypePublicTransport);
@@ -190,24 +209,25 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
else else
[self.baseRoutePreviewStatus showReady]; [self.baseRoutePreviewStatus showReady];
self.goButtonsContainer.hidden = isTransport || isRuler; self.goButtonsContainer.hidden = isTransport || isRuler;
for (MWMRouteStartButton *button in self.goButtons) for (MWMRouteStartButton * button in self.goButtons)
{
if (isRuler) if (isRuler)
[button stateHidden]; [button stateHidden];
else else
[button stateReady]; [button stateReady];
}
} }
- (void)onRouteStart { - (void)onRouteStart
{
[MWMSearch clear]; [MWMSearch clear];
[self.searchManager close]; [self.searchManager close];
self.state = MWMNavigationDashboardStateNavigation; self.state = MWMNavigationDashboardStateNavigation;
} }
- (void)onRouteStop { - (void)onRouteStop
{
self.state = MWMNavigationDashboardStateHidden; self.state = MWMNavigationDashboardStateHidden;
} }
- (void)stateNavigation { - (void)stateNavigation
{
self.routePreview = nil; self.routePreview = nil;
self.navigationInfoView.state = MWMNavigationInfoViewStateNavigation; self.navigationInfoView.state = MWMNavigationInfoViewStateNavigation;
self.navigationControlView.isVisible = YES; self.navigationControlView.isVisible = YES;
@@ -219,7 +239,8 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - MWMRoutePreviewStatus #pragma mark - MWMRoutePreviewStatus
- (IBAction)showRouteManager { - (IBAction)showRouteManager
{
auto routeManagerViewModel = [[MWMRouteManagerViewModel alloc] init]; auto routeManagerViewModel = [[MWMRouteManagerViewModel alloc] init];
auto routeManager = [[MWMRouteManagerViewController alloc] initWithViewModel:routeManagerViewModel]; auto routeManager = [[MWMRouteManagerViewController alloc] initWithViewModel:routeManagerViewModel];
routeManager.modalPresentationStyle = UIModalPresentationCustom; routeManager.modalPresentationStyle = UIModalPresentationCustom;
@@ -230,23 +251,27 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
[[MapViewController sharedController] presentViewController:routeManager animated:YES completion:nil]; [[MapViewController sharedController] presentViewController:routeManager animated:YES completion:nil];
} }
- (IBAction)saveRouteAsTrack:(id)sender { - (IBAction)saveRouteAsTrack:(id)sender
{
[MWMFrameworkHelper saveRouteAsTrack]; [MWMFrameworkHelper saveRouteAsTrack];
[self.baseRoutePreviewStatus setRouteSaved:YES]; [self.baseRoutePreviewStatus setRouteSaved:YES];
} }
#pragma mark - MWMNavigationControlView #pragma mark - MWMNavigationControlView
- (IBAction)ttsButtonAction { - (IBAction)ttsButtonAction
{
BOOL const isEnabled = [MWMTextToSpeech tts].active; BOOL const isEnabled = [MWMTextToSpeech tts].active;
[MWMTextToSpeech tts].active = !isEnabled; [MWMTextToSpeech tts].active = !isEnabled;
} }
- (IBAction)settingsButtonAction { - (IBAction)settingsButtonAction
{
[[MapViewController sharedController] openSettings]; [[MapViewController sharedController] openSettings];
} }
- (IBAction)stopRoutingButtonAction { - (IBAction)stopRoutingButtonAction
{
[MWMSearch clear]; [MWMSearch clear];
[MWMRouter stopRouting]; [MWMRouter stopRouting];
[self.searchManager close]; [self.searchManager close];
@@ -254,53 +279,47 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - SearchOnMapManagerObserver #pragma mark - SearchOnMapManagerObserver
- (void)searchManagerWithDidChangeState:(SearchOnMapState)state { - (void)searchManagerWithDidChangeState:(SearchOnMapState)state
switch (state) { {
case SearchOnMapStateClosed: switch (state)
[self.navigationInfoView setSearchState:NavigationSearchState::MinimizedNormal animated:YES]; {
break; case SearchOnMapStateClosed:
case SearchOnMapStateHidden: [self.navigationInfoView setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
case SearchOnMapStateSearching: break;
[self.navigationInfoView setSearchState:NavigationSearchState::MinimizedSearch animated:YES]; case SearchOnMapStateHidden:
break; case SearchOnMapStateSearching:
[self.navigationInfoView setSearchState:NavigationSearchState::MinimizedSearch animated:YES];
break;
} }
} }
#pragma mark - Available area #pragma mark - Available area
+ (void)updateNavigationInfoAvailableArea:(CGRect)frame { + (void)updateNavigationInfoAvailableArea:(CGRect)frame
{
[[self sharedManager] updateNavigationInfoAvailableArea:frame]; [[self sharedManager] updateNavigationInfoAvailableArea:frame];
} }
- (void)updateNavigationInfoAvailableArea:(CGRect)frame { - (void)updateNavigationInfoAvailableArea:(CGRect)frame
{
_navigationInfoView.availableArea = frame; _navigationInfoView.availableArea = frame;
} }
#pragma mark - Properties #pragma mark - Properties
- (void)setState:(MWMNavigationDashboardState)state { - (void)setState:(MWMNavigationDashboardState)state
{
if (state == MWMNavigationDashboardStateHidden) if (state == MWMNavigationDashboardStateHidden)
[self.searchManager removeObserver:self]; [self.searchManager removeObserver:self];
else else
[self.searchManager addObserver:self]; [self.searchManager addObserver:self];
switch (state) { switch (state)
case MWMNavigationDashboardStateHidden: {
[self stateHidden]; case MWMNavigationDashboardStateHidden: [self stateHidden]; break;
break; case MWMNavigationDashboardStatePrepare: [self statePrepare]; break;
case MWMNavigationDashboardStatePrepare: case MWMNavigationDashboardStatePlanning: [self statePlanning]; break;
[self statePrepare]; case MWMNavigationDashboardStateError: [self stateError]; break;
break; case MWMNavigationDashboardStateReady: [self stateReady]; break;
case MWMNavigationDashboardStatePlanning: case MWMNavigationDashboardStateNavigation: [self stateNavigation]; break;
[self statePlanning];
break;
case MWMNavigationDashboardStateError:
[self stateError];
break;
case MWMNavigationDashboardStateReady:
[self stateReady];
break;
case MWMNavigationDashboardStateNavigation:
[self stateNavigation];
break;
} }
_state = state; _state = state;
[[MapViewController sharedController] updateStatusBarStyle]; [[MapViewController sharedController] updateStatusBarStyle];
@@ -310,13 +329,15 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
} }
@synthesize routePreview = _routePreview; @synthesize routePreview = _routePreview;
- (MWMRoutePreview *)routePreview { - (MWMRoutePreview *)routePreview
{
if (!_routePreview) if (!_routePreview)
[self loadPreviewWithStatusBoxes]; [self loadPreviewWithStatusBoxes];
return _routePreview; return _routePreview;
} }
- (void)setRoutePreview:(MWMRoutePreview *)routePreview { - (void)setRoutePreview:(MWMRoutePreview *)routePreview
{
if (routePreview == _routePreview) if (routePreview == _routePreview)
return; return;
[_routePreview remove]; [_routePreview remove];
@@ -324,20 +345,24 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
_routePreview.delegate = self; _routePreview.delegate = self;
} }
- (MWMBaseRoutePreviewStatus *)baseRoutePreviewStatus { - (MWMBaseRoutePreviewStatus *)baseRoutePreviewStatus
{
if (!_baseRoutePreviewStatus) if (!_baseRoutePreviewStatus)
[self loadPreviewWithStatusBoxes]; [self loadPreviewWithStatusBoxes];
return _baseRoutePreviewStatus; return _baseRoutePreviewStatus;
} }
- (MWMTransportRoutePreviewStatus *)transportRoutePreviewStatus { - (MWMTransportRoutePreviewStatus *)transportRoutePreviewStatus
{
if (!_transportRoutePreviewStatus) if (!_transportRoutePreviewStatus)
[self loadPreviewWithStatusBoxes]; [self loadPreviewWithStatusBoxes];
return _transportRoutePreviewStatus; return _transportRoutePreviewStatus;
} }
- (MWMNavigationInfoView *)navigationInfoView { - (MWMNavigationInfoView *)navigationInfoView
if (!_navigationInfoView) { {
if (!_navigationInfoView)
{
[NSBundle.mainBundle loadNibNamed:kNavigationInfoViewXibName owner:self options:nil]; [NSBundle.mainBundle loadNibNamed:kNavigationInfoViewXibName owner:self options:nil];
_navigationInfoView.state = MWMNavigationInfoViewStateHidden; _navigationInfoView.state = MWMNavigationInfoViewStateHidden;
_navigationInfoView.ownerView = self.ownerView; _navigationInfoView.ownerView = self.ownerView;
@@ -345,15 +370,18 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
return _navigationInfoView; return _navigationInfoView;
} }
- (MWMNavigationControlView *)navigationControlView { - (MWMNavigationControlView *)navigationControlView
if (!_navigationControlView) { {
if (!_navigationControlView)
{
[NSBundle.mainBundle loadNibNamed:kNavigationControlViewXibName owner:self options:nil]; [NSBundle.mainBundle loadNibNamed:kNavigationControlViewXibName owner:self options:nil];
_navigationControlView.ownerView = self.ownerView; _navigationControlView.ownerView = self.ownerView;
} }
return _navigationControlView; return _navigationControlView;
} }
- (MWMNavigationDashboardEntity *)entity { - (MWMNavigationDashboardEntity *)entity
{
if (!_entity) if (!_entity)
_entity = [[MWMNavigationDashboardEntity alloc] init]; _entity = [[MWMNavigationDashboardEntity alloc] init];
return _entity; return _entity;
@@ -361,7 +389,8 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
#pragma mark - MWMRoutePreviewDelegate #pragma mark - MWMRoutePreviewDelegate
- (void)routePreviewDidPressDrivingOptions:(MWMRoutePreview *)routePreview { - (void)routePreviewDidPressDrivingOptions:(MWMRoutePreview *)routePreview
{
[[MapViewController sharedController] openDrivingOptions]; [[MapViewController sharedController] openDrivingOptions];
} }

View File

@@ -28,24 +28,25 @@ CGFloat constexpr kShiftedTurnsTopOffset = 8;
NSTimeInterval constexpr kCollapseSearchTimeout = 5.0; NSTimeInterval constexpr kCollapseSearchTimeout = 5.0;
std::map<NavigationSearchState, NSString *> const kSearchStateButtonImageNames{ std::map<NavigationSearchState, NSString *> const kSearchStateButtonImageNames{
{NavigationSearchState::Maximized, @"ic_routing_search"}, {NavigationSearchState::Maximized, @"ic_routing_search"},
{NavigationSearchState::MinimizedNormal, @"ic_routing_search"}, {NavigationSearchState::MinimizedNormal, @"ic_routing_search"},
{NavigationSearchState::MinimizedSearch, @"ic_routing_search_off"}, {NavigationSearchState::MinimizedSearch, @"ic_routing_search_off"},
{NavigationSearchState::MinimizedGas, @"ic_routing_fuel_off"}, {NavigationSearchState::MinimizedGas, @"ic_routing_fuel_off"},
{NavigationSearchState::MinimizedParking, @"ic_routing_parking_off"}, {NavigationSearchState::MinimizedParking, @"ic_routing_parking_off"},
{NavigationSearchState::MinimizedEat, @"ic_routing_eat_off"}, {NavigationSearchState::MinimizedEat, @"ic_routing_eat_off"},
{NavigationSearchState::MinimizedFood, @"ic_routing_food_off"}, {NavigationSearchState::MinimizedFood, @"ic_routing_food_off"},
{NavigationSearchState::MinimizedATM, @"ic_routing_atm_off"}}; {NavigationSearchState::MinimizedATM, @"ic_routing_atm_off"}};
std::map<NavigationSearchState, NSString *> const kSearchButtonRequest{ std::map<NavigationSearchState, NSString *> const kSearchButtonRequest{
{NavigationSearchState::MinimizedGas, L(@"category_fuel")}, {NavigationSearchState::MinimizedGas, L(@"category_fuel")},
{NavigationSearchState::MinimizedParking, L(@"category_parking")}, {NavigationSearchState::MinimizedParking, L(@"category_parking")},
{NavigationSearchState::MinimizedEat, L(@"category_eat")}, {NavigationSearchState::MinimizedEat, L(@"category_eat")},
{NavigationSearchState::MinimizedFood, L(@"category_food")}, {NavigationSearchState::MinimizedFood, L(@"category_food")},
{NavigationSearchState::MinimizedATM, L(@"category_atm")}}; {NavigationSearchState::MinimizedATM, L(@"category_atm")}};
BOOL defaultOrientation(CGSize const &size) { BOOL defaultOrientation(CGSize const & size)
CGSize const &mapViewSize = [MapViewController sharedController].view.frame.size; {
CGSize const & mapViewSize = [MapViewController sharedController].view.frame.size;
CGFloat const minWidth = MIN(mapViewSize.width, mapViewSize.height); CGFloat const minWidth = MIN(mapViewSize.width, mapViewSize.height);
return IPAD || (size.height > size.width && size.width >= minWidth); return IPAD || (size.height > size.width && size.width >= minWidth);
} }
@@ -53,54 +54,55 @@ BOOL defaultOrientation(CGSize const &size) {
@interface MWMNavigationInfoView () <MWMLocationObserver> @interface MWMNavigationInfoView () <MWMLocationObserver>
@property(weak, nonatomic) IBOutlet UIView *streetNameView; @property(weak, nonatomic) IBOutlet UIView * streetNameView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *streetNameTopOffsetConstraint; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * streetNameTopOffsetConstraint;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *streetNameViewHideOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * streetNameViewHideOffset;
@property(weak, nonatomic) IBOutlet UILabel *streetNameLabel; @property(weak, nonatomic) IBOutlet UILabel * streetNameLabel;
@property(weak, nonatomic) IBOutlet UIView *turnsView; @property(weak, nonatomic) IBOutlet UIView * turnsView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *turnsViewHideOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * turnsViewHideOffset;
@property(weak, nonatomic) IBOutlet UIImageView *nextTurnImageView; @property(weak, nonatomic) IBOutlet UIImageView * nextTurnImageView;
@property(weak, nonatomic) IBOutlet UILabel *roundTurnLabel; @property(weak, nonatomic) IBOutlet UILabel * roundTurnLabel;
@property(weak, nonatomic) IBOutlet UILabel *distanceToNextTurnLabel; @property(weak, nonatomic) IBOutlet UILabel * distanceToNextTurnLabel;
@property(weak, nonatomic) IBOutlet UIView *secondTurnView; @property(weak, nonatomic) IBOutlet UIView * secondTurnView;
@property(weak, nonatomic) IBOutlet UIImageView *secondTurnImageView; @property(weak, nonatomic) IBOutlet UIImageView * secondTurnImageView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *turnsWidth; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * turnsWidth;
@property(weak, nonatomic) IBOutlet UIView *searchButtonsView; @property(weak, nonatomic) IBOutlet UIView * searchButtonsView;
@property(weak, nonatomic) IBOutlet MWMButton *searchMainButton; @property(weak, nonatomic) IBOutlet MWMButton * searchMainButton;
@property(weak, nonatomic) IBOutlet MWMButton *bookmarksButton; @property(weak, nonatomic) IBOutlet MWMButton * bookmarksButton;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *searchButtonsViewHeight; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * searchButtonsViewHeight;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *searchButtonsViewWidth; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * searchButtonsViewWidth;
@property(nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *searchLandscapeConstraints; @property(nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray * searchLandscapeConstraints;
@property(nonatomic) IBOutletCollection(UIButton) NSArray *searchButtons; @property(nonatomic) IBOutletCollection(UIButton) NSArray * searchButtons;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *searchButtonsSideSize; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * searchButtonsSideSize;
@property(weak, nonatomic) IBOutlet MWMButton *searchGasButton; @property(weak, nonatomic) IBOutlet MWMButton * searchGasButton;
@property(weak, nonatomic) IBOutlet MWMButton *searchParkingButton; @property(weak, nonatomic) IBOutlet MWMButton * searchParkingButton;
@property(weak, nonatomic) IBOutlet MWMButton *searchEatButton; @property(weak, nonatomic) IBOutlet MWMButton * searchEatButton;
@property(weak, nonatomic) IBOutlet MWMButton *searchFoodButton; @property(weak, nonatomic) IBOutlet MWMButton * searchFoodButton;
@property(weak, nonatomic) IBOutlet MWMButton *searchATMButton; @property(weak, nonatomic) IBOutlet MWMButton * searchATMButton;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *turnsTopOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * turnsTopOffset;
@property(weak, nonatomic) IBOutlet MWMNavigationAddPointToastView *toastView; @property(weak, nonatomic) IBOutlet MWMNavigationAddPointToastView * toastView;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *toastViewHideOffset; @property(weak, nonatomic) IBOutlet NSLayoutConstraint * toastViewHideOffset;
@property(nonatomic, readwrite) NavigationSearchState searchState; @property(nonatomic, readwrite) NavigationSearchState searchState;
@property(nonatomic) BOOL isVisible; @property(nonatomic) BOOL isVisible;
@property(weak, nonatomic) MWMNavigationDashboardEntity *navigationInfo; @property(weak, nonatomic) MWMNavigationDashboardEntity * navigationInfo;
@property(nonatomic) BOOL hasLocation; @property(nonatomic) BOOL hasLocation;
@property(nonatomic) NSLayoutConstraint *topConstraint; @property(nonatomic) NSLayoutConstraint * topConstraint;
@property(nonatomic) NSLayoutConstraint *leftConstraint; @property(nonatomic) NSLayoutConstraint * leftConstraint;
@property(nonatomic) NSLayoutConstraint *widthConstraint; @property(nonatomic) NSLayoutConstraint * widthConstraint;
@property(nonatomic) NSLayoutConstraint *heightConstraint; @property(nonatomic) NSLayoutConstraint * heightConstraint;
@end @end
@implementation MWMNavigationInfoView @implementation MWMNavigationInfoView
- (void)updateToastView { - (void)updateToastView
{
// -S-F-L -> Start // -S-F-L -> Start
// -S-F+L -> Finish // -S-F+L -> Finish
// -S+F-L -> Start // -S+F-L -> Start
@@ -114,7 +116,8 @@ BOOL defaultOrientation(CGSize const &size) {
BOOL const hasFinish = ([MWMRouter finishPoint] != nil); BOOL const hasFinish = ([MWMRouter finishPoint] != nil);
self.hasLocation = ([MWMLocationManager lastLocation] != nil); self.hasLocation = ([MWMLocationManager lastLocation] != nil);
if (hasStart && hasFinish) { if (hasStart && hasFinish)
{
[self setToastViewHidden:YES]; [self setToastViewHidden:YES];
return; return;
} }
@@ -123,12 +126,14 @@ BOOL defaultOrientation(CGSize const &size) {
auto toastView = self.toastView; auto toastView = self.toastView;
if (hasStart) { if (hasStart)
{
[toastView configWithIsStart:NO withLocationButton:NO]; [toastView configWithIsStart:NO withLocationButton:NO];
return; return;
} }
if (hasFinish) { if (hasFinish)
{
[toastView configWithIsStart:YES withLocationButton:self.hasLocation]; [toastView configWithIsStart:YES withLocationButton:self.hasLocation];
return; return;
} }
@@ -139,19 +144,22 @@ BOOL defaultOrientation(CGSize const &size) {
[toastView configWithIsStart:YES withLocationButton:NO]; [toastView configWithIsStart:YES withLocationButton:NO];
} }
- (SearchOnMapManager *)searchManager { - (SearchOnMapManager *)searchManager
{
return [MapViewController sharedController].searchManager; return [MapViewController sharedController].searchManager;
} }
- (IBAction)openSearch { - (IBAction)openSearch
{
BOOL const isStart = self.toastView.isStart; BOOL const isStart = self.toastView.isStart;
[self.searchManager setRoutingTooltip: [self.searchManager
isStart ? SearchOnMapRoutingTooltipSearchStart : SearchOnMapRoutingTooltipSearchFinish ]; setRoutingTooltip:isStart ? SearchOnMapRoutingTooltipSearchStart : SearchOnMapRoutingTooltipSearchFinish];
[self.searchManager startSearchingWithIsRouting:YES]; [self.searchManager startSearchingWithIsRouting:YES];
} }
- (IBAction)addLocationRoutePoint { - (IBAction)addLocationRoutePoint
{
NSAssert(![MWMRouter startPoint], @"Action button is active while start point is available"); NSAssert(![MWMRouter startPoint], @"Action button is active while start point is available");
NSAssert([MWMLocationManager lastLocation], @"Action button is active while my location is not available"); NSAssert([MWMLocationManager lastLocation], @"Action button is active while my location is not available");
@@ -162,33 +170,35 @@ BOOL defaultOrientation(CGSize const &size) {
#pragma mark - Search #pragma mark - Search
- (IBAction)searchMainButtonTouchUpInside { - (IBAction)searchMainButtonTouchUpInside
switch (self.searchState) { {
case NavigationSearchState::Maximized: switch (self.searchState)
{
case NavigationSearchState::Maximized:
[self.searchManager startSearchingWithIsRouting:YES];
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
break;
case NavigationSearchState::MinimizedNormal:
if (self.state == MWMNavigationInfoViewStatePrepare)
[self.searchManager startSearchingWithIsRouting:YES]; [self.searchManager startSearchingWithIsRouting:YES];
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES]; else
break; [self setSearchState:NavigationSearchState::Maximized animated:YES];
case NavigationSearchState::MinimizedNormal: break;
if (self.state == MWMNavigationInfoViewStatePrepare) { case NavigationSearchState::MinimizedSearch:
[self.searchManager startSearchingWithIsRouting:YES]; case NavigationSearchState::MinimizedGas:
} else { case NavigationSearchState::MinimizedParking:
[self setSearchState:NavigationSearchState::Maximized animated:YES]; case NavigationSearchState::MinimizedEat:
} case NavigationSearchState::MinimizedFood:
break; case NavigationSearchState::MinimizedATM:
case NavigationSearchState::MinimizedSearch: [MWMSearch clear];
case NavigationSearchState::MinimizedGas: [self.searchManager hide];
case NavigationSearchState::MinimizedParking: [self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
case NavigationSearchState::MinimizedEat: break;
case NavigationSearchState::MinimizedFood:
case NavigationSearchState::MinimizedATM:
[MWMSearch clear];
[self.searchManager hide];
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
break;
} }
} }
- (IBAction)searchButtonTouchUpInside:(MWMButton *)sender { - (IBAction)searchButtonTouchUpInside:(MWMButton *)sender
{
auto const body = ^(NavigationSearchState state) { auto const body = ^(NavigationSearchState state) {
NSString * text = [kSearchButtonRequest.at(state) stringByAppendingString:@" "]; NSString * text = [kSearchButtonRequest.at(state) stringByAppendingString:@" "];
NSString * locale = [[AppInfo sharedInfo] languageId]; NSString * locale = [[AppInfo sharedInfo] languageId];
@@ -210,78 +220,99 @@ BOOL defaultOrientation(CGSize const &size) {
body(NavigationSearchState::MinimizedATM); body(NavigationSearchState::MinimizedATM);
} }
- (IBAction)bookmarksButtonTouchUpInside { - (IBAction)bookmarksButtonTouchUpInside
{
[[MapViewController sharedController].bookmarksCoordinator open]; [[MapViewController sharedController].bookmarksCoordinator open];
} }
- (void)collapseSearchOnTimer { - (void)collapseSearchOnTimer
{
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES]; [self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
} }
- (void)layoutSearch { - (void)layoutSearch
{
BOOL const defaultView = defaultOrientation(self.availableArea.size); BOOL const defaultView = defaultOrientation(self.availableArea.size);
CGFloat alpha = 0; CGFloat alpha = 0;
CGFloat searchButtonsSideSize = 0; CGFloat searchButtonsSideSize = 0;
self.searchButtonsViewWidth.constant = 0; self.searchButtonsViewWidth.constant = 0;
self.searchButtonsViewHeight.constant = 0; self.searchButtonsViewHeight.constant = 0;
if (self.searchState == NavigationSearchState::Maximized) { if (self.searchState == NavigationSearchState::Maximized)
{
alpha = 1; alpha = 1;
searchButtonsSideSize = kSearchButtonsSideSize; searchButtonsSideSize = kSearchButtonsSideSize;
self.searchButtonsViewWidth.constant = self.searchButtonsViewWidth.constant =
defaultView ? kSearchButtonsViewWidthPortrait : kSearchButtonsViewWidthLandscape; defaultView ? kSearchButtonsViewWidthPortrait : kSearchButtonsViewWidthLandscape;
self.searchButtonsViewHeight.constant = self.searchButtonsViewHeight.constant =
defaultView ? kSearchButtonsViewHeightPortrait : kSearchButtonsViewHeightLandscape; defaultView ? kSearchButtonsViewHeightPortrait : kSearchButtonsViewHeightLandscape;
} }
for (UIButton *searchButton in self.searchButtons) for (UIButton * searchButton in self.searchButtons)
searchButton.alpha = alpha; searchButton.alpha = alpha;
UILayoutPriority const priority = (defaultView ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh); UILayoutPriority const priority = (defaultView ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh);
for (NSLayoutConstraint *constraint in self.searchLandscapeConstraints) for (NSLayoutConstraint * constraint in self.searchLandscapeConstraints)
constraint.priority = priority; constraint.priority = priority;
self.searchButtonsSideSize.constant = searchButtonsSideSize; self.searchButtonsSideSize.constant = searchButtonsSideSize;
} }
#pragma mark - MWMNavigationDashboardManager #pragma mark - MWMNavigationDashboardManager
- (void)onNavigationInfoUpdated:(MWMNavigationDashboardEntity *)info { - (void)onNavigationInfoUpdated:(MWMNavigationDashboardEntity *)info
{
self.navigationInfo = info; self.navigationInfo = info;
if (self.state != MWMNavigationInfoViewStateNavigation) if (self.state != MWMNavigationInfoViewStateNavigation)
return; return;
if (info.streetName.length != 0) { if (info.streetName.length != 0)
{
[self setStreetNameVisible:YES]; [self setStreetNameVisible:YES];
self.streetNameLabel.text = info.streetName; self.streetNameLabel.text = info.streetName;
} else { }
else
{
[self setStreetNameVisible:NO]; [self setStreetNameVisible:NO];
} }
if (info.turnImage) { if (info.turnImage)
{
[self setTurnsViewVisible:YES]; [self setTurnsViewVisible:YES];
self.nextTurnImageView.image = info.turnImage; self.nextTurnImageView.image = info.turnImage;
if (info.roundExitNumber == 0) { if (info.roundExitNumber == 0)
{
self.roundTurnLabel.hidden = YES; self.roundTurnLabel.hidden = YES;
} else { }
else
{
self.roundTurnLabel.hidden = NO; self.roundTurnLabel.hidden = NO;
self.roundTurnLabel.text = @(info.roundExitNumber).stringValue; self.roundTurnLabel.text = @(info.roundExitNumber).stringValue;
} }
NSDictionary *turnNumberAttributes = NSDictionary * turnNumberAttributes = @{
@{NSForegroundColorAttributeName: [UIColor white], NSFontAttributeName: IPAD ? [UIFont bold36] : [UIFont bold28]}; NSForegroundColorAttributeName: [UIColor white],
NSDictionary *turnLegendAttributes = NSFontAttributeName: IPAD ? [UIFont bold36] : [UIFont bold28]
@{NSForegroundColorAttributeName: [UIColor white], NSFontAttributeName: IPAD ? [UIFont bold24] : [UIFont bold16]}; };
NSDictionary * turnLegendAttributes = @{
NSForegroundColorAttributeName: [UIColor white],
NSFontAttributeName: IPAD ? [UIFont bold24] : [UIFont bold16]
};
NSMutableAttributedString *distance = [[NSMutableAttributedString alloc] initWithString:info.distanceToTurn NSMutableAttributedString * distance = [[NSMutableAttributedString alloc] initWithString:info.distanceToTurn
attributes:turnNumberAttributes]; attributes:turnNumberAttributes];
[distance appendAttributedString:[[NSAttributedString alloc] [distance appendAttributedString:[[NSAttributedString alloc]
initWithString:[NSString stringWithFormat:@" %@", info.turnUnits] initWithString:[NSString stringWithFormat:@" %@", info.turnUnits]
attributes:turnLegendAttributes]]; attributes:turnLegendAttributes]];
self.distanceToNextTurnLabel.attributedText = distance; self.distanceToNextTurnLabel.attributedText = distance;
if (info.nextTurnImage) { if (info.nextTurnImage)
{
self.secondTurnView.hidden = NO; self.secondTurnView.hidden = NO;
self.secondTurnImageView.image = info.nextTurnImage; self.secondTurnImageView.image = info.nextTurnImage;
} else { }
else
{
self.secondTurnView.hidden = YES; self.secondTurnView.hidden = YES;
} }
} else { }
else
{
[self setTurnsViewVisible:NO]; [self setTurnsViewVisible:NO];
} }
[self setNeedsLayout]; [self setNeedsLayout];
@@ -289,7 +320,8 @@ BOOL defaultOrientation(CGSize const &size) {
#pragma mark - MWMLocationObserver #pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(CLLocation *)location { - (void)onLocationUpdate:(CLLocation *)location
{
BOOL const hasLocation = ([MWMLocationManager lastLocation] != nil); BOOL const hasLocation = ([MWMLocationManager lastLocation] != nil);
if (self.hasLocation != hasLocation) if (self.hasLocation != hasLocation)
[self updateToastView]; [self updateToastView];
@@ -297,34 +329,39 @@ BOOL defaultOrientation(CGSize const &size) {
#pragma mark - SolidTouchView #pragma mark - SolidTouchView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.searchState == NavigationSearchState::Maximized) if (self.searchState == NavigationSearchState::Maximized)
return; return;
[super touchesBegan:touches withEvent:event]; [super touchesBegan:touches withEvent:event];
} }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.searchState == NavigationSearchState::Maximized) if (self.searchState == NavigationSearchState::Maximized)
return; return;
[super touchesMoved:touches withEvent:event]; [super touchesMoved:touches withEvent:event];
} }
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.searchState == NavigationSearchState::Maximized) if (self.searchState == NavigationSearchState::Maximized)
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES]; [self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
else else
[super touchesEnded:touches withEvent:event]; [super touchesEnded:touches withEvent:event];
} }
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.searchState == NavigationSearchState::Maximized) if (self.searchState == NavigationSearchState::Maximized)
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES]; [self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
else else
[super touchesCancelled:touches withEvent:event]; [super touchesCancelled:touches withEvent:event];
} }
- (void)configLayout { - (void)configLayout
UIView *ov = self.superview; {
UIView * ov = self.superview;
self.translatesAutoresizingMaskIntoConstraints = NO; self.translatesAutoresizingMaskIntoConstraints = NO;
self.topConstraint = [self.topAnchor constraintEqualToAnchor:ov.topAnchor]; self.topConstraint = [self.topAnchor constraintEqualToAnchor:ov.topAnchor];
@@ -339,11 +376,14 @@ BOOL defaultOrientation(CGSize const &size) {
} }
// Additional spacing for devices with a small top safe area (such as SE or when the device is in landscape mode). // Additional spacing for devices with a small top safe area (such as SE or when the device is in landscape mode).
- (CGFloat)additionalStreetNameTopOffset { - (CGFloat)additionalStreetNameTopOffset
return MapsAppDelegate.theApp.window.safeAreaInsets.top <= 20 ? 10 : 0;; {
return MapsAppDelegate.theApp.window.safeAreaInsets.top <= 20 ? 10 : 0;
;
} }
- (void)refreshLayout { - (void)refreshLayout
{
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
self.streetNameLabel.numberOfLines = 1; self.streetNameLabel.numberOfLines = 1;
@@ -360,12 +400,11 @@ BOOL defaultOrientation(CGSize const &size) {
[self layoutSearch]; [self layoutSearch];
self.turnsTopOffset.constant = availableArea.origin.y > 0 ? kShiftedTurnsTopOffset : kBaseTurnsTopOffset; self.turnsTopOffset.constant = availableArea.origin.y > 0 ? kShiftedTurnsTopOffset : kBaseTurnsTopOffset;
self.searchButtonsView.layer.cornerRadius = self.searchButtonsView.layer.cornerRadius =
(defaultOrientation(availableArea.size) ? kSearchButtonsViewHeightPortrait (defaultOrientation(availableArea.size) ? kSearchButtonsViewHeightPortrait
: kSearchButtonsViewHeightLandscape) / : kSearchButtonsViewHeightLandscape) /
2; 2;
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *))
self.searchButtonsView.layer.cornerCurve = kCACornerCurveContinuous; self.searchButtonsView.layer.cornerCurve = kCACornerCurveContinuous;
}
self.streetNameTopOffsetConstraint.constant = self.additionalStreetNameTopOffset; self.streetNameTopOffsetConstraint.constant = self.additionalStreetNameTopOffset;
}]; }];
}); });
@@ -373,85 +412,100 @@ BOOL defaultOrientation(CGSize const &size) {
#pragma mark - Properties #pragma mark - Properties
- (void)setAvailableArea:(CGRect)availableArea { - (void)setAvailableArea:(CGRect)availableArea
{
if (CGRectEqualToRect(_availableArea, availableArea)) if (CGRectEqualToRect(_availableArea, availableArea))
return; return;
_availableArea = availableArea; _availableArea = availableArea;
[self refreshLayout]; [self refreshLayout];
} }
- (void)setSearchState:(NavigationSearchState)searchState animated:(BOOL)animated { - (void)setSearchState:(NavigationSearchState)searchState animated:(BOOL)animated
{
self.searchState = searchState; self.searchState = searchState;
auto block = ^{ auto block = ^{
[self layoutSearch]; [self layoutSearch];
[self layoutIfNeeded]; [self layoutIfNeeded];
}; };
if (animated) { if (animated)
{
[self layoutIfNeeded]; [self layoutIfNeeded];
[UIView animateWithDuration:kDefaultAnimationDuration animations:block]; [UIView animateWithDuration:kDefaultAnimationDuration animations:block];
} else { }
else
{
block(); block();
} }
SEL const collapseSelector = @selector(collapseSearchOnTimer); SEL const collapseSelector = @selector(collapseSearchOnTimer);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:collapseSelector object:self]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:collapseSelector object:self];
if (self.searchState == NavigationSearchState::Maximized) { if (self.searchState == NavigationSearchState::Maximized)
{
[self.superview bringSubviewToFront:self]; [self.superview bringSubviewToFront:self];
[self performSelector:collapseSelector withObject:self afterDelay:kCollapseSearchTimeout]; [self performSelector:collapseSelector withObject:self afterDelay:kCollapseSearchTimeout];
} else { }
else
{
[self.superview sendSubviewToBack:self]; [self.superview sendSubviewToBack:self];
} }
} }
- (void)setSearchState:(NavigationSearchState)searchState { - (void)setSearchState:(NavigationSearchState)searchState
{
_searchState = searchState; _searchState = searchState;
self.searchMainButton.imageName = kSearchStateButtonImageNames.at(searchState); self.searchMainButton.imageName = kSearchStateButtonImageNames.at(searchState);
} }
- (void)setState:(MWMNavigationInfoViewState)state { - (void)setState:(MWMNavigationInfoViewState)state
{
if (_state == state) if (_state == state)
return; return;
_state = state; _state = state;
switch (state) { switch (state)
case MWMNavigationInfoViewStateHidden: {
self.isVisible = NO; case MWMNavigationInfoViewStateHidden:
[self setToastViewHidden:YES]; self.isVisible = NO;
[MWMLocationManager removeObserver:self]; [self setToastViewHidden:YES];
break; [MWMLocationManager removeObserver:self];
case MWMNavigationInfoViewStateNavigation: break;
self.isVisible = YES; case MWMNavigationInfoViewStateNavigation:
if ([MWMRouter type] == MWMRouterTypePedestrian) self.isVisible = YES;
[MWMLocationManager addObserver:self]; if ([MWMRouter type] == MWMRouterTypePedestrian)
else
[MWMLocationManager removeObserver:self];
break;
case MWMNavigationInfoViewStatePrepare:
self.isVisible = YES;
[self setStreetNameVisible:NO];
[self setTurnsViewVisible:NO];
[MWMLocationManager addObserver:self]; [MWMLocationManager addObserver:self];
break; else
[MWMLocationManager removeObserver:self];
break;
case MWMNavigationInfoViewStatePrepare:
self.isVisible = YES;
[self setStreetNameVisible:NO];
[self setTurnsViewVisible:NO];
[MWMLocationManager addObserver:self];
break;
} }
} }
- (void)setStreetNameVisible:(BOOL)isVisible { - (void)setStreetNameVisible:(BOOL)isVisible
{
self.streetNameView.hidden = !isVisible; self.streetNameView.hidden = !isVisible;
self.streetNameViewHideOffset.priority = isVisible ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh; self.streetNameViewHideOffset.priority = isVisible ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh;
} }
- (void)setTurnsViewVisible:(BOOL)isVisible { - (void)setTurnsViewVisible:(BOOL)isVisible
{
self.turnsView.hidden = !isVisible; self.turnsView.hidden = !isVisible;
self.turnsViewHideOffset.priority = isVisible ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh; self.turnsViewHideOffset.priority = isVisible ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh;
} }
- (void)setIsVisible:(BOOL)isVisible { - (void)setIsVisible:(BOOL)isVisible
{
if (_isVisible == isVisible) if (_isVisible == isVisible)
return; return;
_isVisible = isVisible; _isVisible = isVisible;
[self setNeedsLayout]; [self setNeedsLayout];
if (isVisible) { if (isVisible)
{
[self setSearchState:NavigationSearchState::MinimizedNormal animated:NO]; [self setSearchState:NavigationSearchState::MinimizedNormal animated:NO];
self.turnsWidth.constant = IPAD ? kTurnsiPadWidth : kTurnsiPhoneWidth; self.turnsWidth.constant = IPAD ? kTurnsiPadWidth : kTurnsiPhoneWidth;
UIView *sv = self.ownerView; UIView * sv = self.ownerView;
NSAssert(sv != nil, @"Superview can't be nil"); NSAssert(sv != nil, @"Superview can't be nil");
if ([sv.subviews containsObject:self]) if ([sv.subviews containsObject:self])
return; return;
@@ -459,32 +513,30 @@ BOOL defaultOrientation(CGSize const &size) {
[self configLayout]; [self configLayout];
} }
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{ [self layoutIfNeeded]; }
[self layoutIfNeeded]; completion:^(BOOL finished) {
} if (!isVisible)
completion:^(BOOL finished) { [self removeFromSuperview];
if (!isVisible) }];
[self removeFromSuperview];
}];
} }
- (void)setToastViewHidden:(BOOL)hidden { - (void)setToastViewHidden:(BOOL)hidden
{
if (!hidden) if (!hidden)
self.toastView.hidden = NO; self.toastView.hidden = NO;
[self setNeedsLayout]; [self setNeedsLayout];
self.toastViewHideOffset.priority = (hidden ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow); self.toastViewHideOffset.priority = (hidden ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow);
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{ [self layoutIfNeeded]; }
[self layoutIfNeeded]; completion:^(BOOL finished) {
} if (hidden)
completion:^(BOOL finished) { self.toastView.hidden = YES;
if (hidden) }];
self.toastView.hidden = YES;
}];
} }
// MARK: Update Theme // MARK: Update Theme
- (void)applyTheme { - (void)applyTheme
{
[self setSearchState:_searchState]; [self setSearchState:_searchState];
} }
@end @end

View File

@@ -2,15 +2,15 @@
#import "MWMCircularProgress.h" #import "MWMCircularProgress.h"
#import "MWMLocationManager.h" #import "MWMLocationManager.h"
#import "MWMRouter.h" #import "MWMRouter.h"
#import "SwiftBridge.h"
#import "UIButton+Orientation.h" #import "UIButton+Orientation.h"
#import "UIImageView+Coloring.h" #import "UIImageView+Coloring.h"
#import "SwiftBridge.h"
#include "platform/platform.hpp" #include "platform/platform.hpp"
static CGFloat const kDrivingOptionsHeight = 48; static CGFloat const kDrivingOptionsHeight = 48;
@interface MWMRoutePreview ()<MWMCircularProgressProtocol> @interface MWMRoutePreview () <MWMCircularProgressProtocol>
@property(nonatomic) BOOL isVisible; @property(nonatomic) BOOL isVisible;
@property(nonatomic) BOOL actualVisibilityValue; @property(nonatomic) BOOL actualVisibilityValue;
@@ -42,7 +42,8 @@ static CGFloat const kDrivingOptionsHeight = 48;
[self applyContentViewShadow]; [self applyContentViewShadow];
} }
- (void)applyContentViewShadow { - (void)applyContentViewShadow
{
self.contentView.layer.shadowOffset = CGSizeZero; self.contentView.layer.shadowOffset = CGSizeZero;
self.contentView.layer.shadowRadius = 2.0; self.contentView.layer.shadowRadius = 2.0;
self.contentView.layer.shadowOpacity = 0.7; self.contentView.layer.shadowOpacity = 0.7;
@@ -50,49 +51,48 @@ static CGFloat const kDrivingOptionsHeight = 48;
[self resizeShadow]; [self resizeShadow];
} }
- (void)layoutSubviews { - (void)layoutSubviews
{
[super layoutSubviews]; [super layoutSubviews];
[self.vehicle setNeedsLayout]; [self.vehicle setNeedsLayout];
[self resizeShadow]; [self resizeShadow];
} }
- (void)resizeShadow { - (void)resizeShadow
{
CGFloat shadowSize = 1.0; CGFloat shadowSize = 1.0;
CGRect contentFrame = self.contentView.bounds; CGRect contentFrame = self.contentView.bounds;
CGRect shadowFrame = CGRectMake(contentFrame.origin.x - shadowSize, CGRect shadowFrame = CGRectMake(contentFrame.origin.x - shadowSize, contentFrame.size.height,
contentFrame.size.height, contentFrame.size.width + (2 * shadowSize), shadowSize);
contentFrame.size.width + (2 * shadowSize), self.contentView.layer.shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
shadowSize);
self.contentView.layer.shadowPath = [UIBezierPath bezierPathWithRect: shadowFrame].CGPath;
} }
- (void)setupProgresses - (void)setupProgresses
{ {
[self addProgress:self.vehicle imageName:@"ic_car" routerType:MWMRouterTypeVehicle]; [self addProgress:self.vehicle imageName:@"ic_car" routerType:MWMRouterTypeVehicle];
[self addProgress:self.pedestrian imageName:@"ic_pedestrian" routerType:MWMRouterTypePedestrian]; [self addProgress:self.pedestrian imageName:@"ic_pedestrian" routerType:MWMRouterTypePedestrian];
[self addProgress:self.publicTransport [self addProgress:self.publicTransport imageName:@"ic_train" routerType:MWMRouterTypePublicTransport];
imageName:@"ic_train"
routerType:MWMRouterTypePublicTransport];
[self addProgress:self.bicycle imageName:@"ic_bike" routerType:MWMRouterTypeBicycle]; [self addProgress:self.bicycle imageName:@"ic_bike" routerType:MWMRouterTypeBicycle];
[self addProgress:self.ruler imageName:@"ic_ruler_route" routerType:MWMRouterTypeRuler]; [self addProgress:self.ruler imageName:@"ic_ruler_route" routerType:MWMRouterTypeRuler];
} }
- (void)addProgress:(UIView *)parentView - (void)addProgress:(UIView *)parentView imageName:(NSString *)imageName routerType:(MWMRouterType)routerType
imageName:(NSString *)imageName
routerType:(MWMRouterType)routerType
{ {
MWMCircularProgress * progress = [[MWMCircularProgress alloc] initWithParentView:parentView]; MWMCircularProgress * progress = [[MWMCircularProgress alloc] initWithParentView:parentView];
MWMCircularProgressStateVec imageStates = @[@(MWMCircularProgressStateNormal), MWMCircularProgressStateVec imageStates =
@(MWMCircularProgressStateProgress), @(MWMCircularProgressStateSpinner)]; @[@(MWMCircularProgressStateNormal), @(MWMCircularProgressStateProgress), @(MWMCircularProgressStateSpinner)];
[progress setImageName:imageName forStates:imageStates]; [progress setImageName:imageName forStates:imageStates];
[progress setImageName:[imageName stringByAppendingString:@"_selected"] forStates:@[@(MWMCircularProgressStateSelected), @(MWMCircularProgressStateCompleted)]]; [progress setImageName:[imageName stringByAppendingString:@"_selected"]
forStates:@[@(MWMCircularProgressStateSelected), @(MWMCircularProgressStateCompleted)]];
[progress setImageName:@"ic_error" forStates:@[@(MWMCircularProgressStateFailed)]]; [progress setImageName:@"ic_error" forStates:@[@(MWMCircularProgressStateFailed)]];
[progress setColoring:MWMButtonColoringWhiteText [progress
forStates:@[@(MWMCircularProgressStateFailed), @(MWMCircularProgressStateSelected), setColoring:MWMButtonColoringWhiteText
@(MWMCircularProgressStateProgress), @(MWMCircularProgressStateSpinner), forStates:@[
@(MWMCircularProgressStateCompleted)]]; @(MWMCircularProgressStateFailed), @(MWMCircularProgressStateSelected), @(MWMCircularProgressStateProgress),
@(MWMCircularProgressStateSpinner), @(MWMCircularProgressStateCompleted)
]];
[progress setSpinnerBackgroundColor:UIColor.clearColor]; [progress setSpinnerBackgroundColor:UIColor.clearColor];
[progress setColor:UIColor.whiteColor [progress setColor:UIColor.whiteColor
@@ -125,7 +125,8 @@ static CGFloat const kDrivingOptionsHeight = 48;
m_progresses[routerType].progress = progress; m_progresses[routerType].progress = progress;
} }
- (IBAction)onDrivingOptions:(UIButton *)sender { - (IBAction)onDrivingOptions:(UIButton *)sender
{
[self.delegate routePreviewDidPressDrivingOptions:self]; [self.delegate routePreviewDidPressDrivingOptions:self];
} }
@@ -158,39 +159,36 @@ static CGFloat const kDrivingOptionsHeight = 48;
[superview addSubview:self]; [superview addSubview:self];
[self setupConstraints]; [self setupConstraints];
self.actualVisibilityValue = YES; self.actualVisibilityValue = YES;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ self.isVisible = YES; });
self.isVisible = YES;
});
} }
- (void)remove { - (void)remove
{
self.actualVisibilityValue = NO; self.actualVisibilityValue = NO;
self.isVisible = NO; self.isVisible = NO;
} }
- (void)setupConstraints {} - (void)setupConstraints
{}
- (void)setDrivingOptionsState:(MWMDrivingOptionsState)state { - (void)setDrivingOptionsState:(MWMDrivingOptionsState)state
{
_drivingOptionsState = state; _drivingOptionsState = state;
[self layoutIfNeeded]; [self layoutIfNeeded];
self.drivingOptionHeightConstraint.constant = self.drivingOptionHeightConstraint.constant = (state == MWMDrivingOptionsStateNone) ? -kDrivingOptionsHeight : 0;
(state == MWMDrivingOptionsStateNone) ? -kDrivingOptionsHeight : 0; [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ [self layoutIfNeeded]; }];
[UIView animateWithDuration:kDefaultAnimationDuration animations:^{
[self layoutIfNeeded];
}];
if (state == MWMDrivingOptionsStateDefine) { if (state == MWMDrivingOptionsStateDefine)
{
[self.drivingOptionsButton setImagePadding:0.0]; [self.drivingOptionsButton setImagePadding:0.0];
[self.drivingOptionsButton setImage:nil [self.drivingOptionsButton setImage:nil forState:UIControlStateNormal];
forState:UIControlStateNormal]; [self.drivingOptionsButton setTitle:L(@"define_to_avoid_btn").uppercaseString forState:UIControlStateNormal];
[self.drivingOptionsButton setTitle:L(@"define_to_avoid_btn").uppercaseString }
forState:UIControlStateNormal]; else if (state == MWMDrivingOptionsStateChange)
} else if (state == MWMDrivingOptionsStateChange) { {
[self.drivingOptionsButton setImagePadding:5.0]; [self.drivingOptionsButton setImagePadding:5.0];
[self.drivingOptionsButton setImage:[UIImage imageNamed:@"ic_options_warning"] [self.drivingOptionsButton setImage:[UIImage imageNamed:@"ic_options_warning"] forState:UIControlStateNormal];
forState:UIControlStateNormal]; [self.drivingOptionsButton setTitle:L(@"change_driving_options_btn").uppercaseString forState:UIControlStateNormal];
[self.drivingOptionsButton setTitle:L(@"change_driving_options_btn").uppercaseString
forState:UIControlStateNormal];
} }
} }
@@ -198,14 +196,13 @@ static CGFloat const kDrivingOptionsHeight = 48;
- (void)setIsVisible:(BOOL)isVisible - (void)setIsVisible:(BOOL)isVisible
{ {
if (isVisible != self.actualVisibilityValue) { return; } if (isVisible != self.actualVisibilityValue)
return;
_isVisible = isVisible; _isVisible = isVisible;
auto sv = self.superview; auto sv = self.superview;
[sv setNeedsLayout]; [sv setNeedsLayout];
[UIView animateWithDuration:kDefaultAnimationDuration [UIView animateWithDuration:kDefaultAnimationDuration
animations:^{ animations:^{ [sv layoutIfNeeded]; }
[sv layoutIfNeeded];
}
completion:^(BOOL finished) { completion:^(BOOL finished) {
if (!self.isVisible) if (!self.isVisible)
[self removeFromSuperview]; [self removeFromSuperview];

View File

@@ -1,8 +1,7 @@
#import "EAGLView.h" #import "EAGLView.h"
#import "iosOGLContextFactory.h"
#import "MWMMapWidgets.h" #import "MWMMapWidgets.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
#import "iosOGLContextFactory.h"
#include "base/assert.hpp" #include "base/assert.hpp"
#include "base/logging.hpp" #include "base/logging.hpp"
@@ -15,16 +14,16 @@
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
#ifdef OMIM_METAL_AVAILABLE #ifdef OMIM_METAL_AVAILABLE
#import "MetalContextFactory.h"
#import <MetalKit/MetalKit.h> #import <MetalKit/MetalKit.h>
#import "MetalContextFactory.h"
#endif #endif
namespace dp namespace dp
{ {
class GraphicsContextFactory; class GraphicsContextFactory;
} }
@interface EAGLView() @interface EAGLView ()
{ {
dp::ApiVersion m_apiVersion; dp::ApiVersion m_apiVersion;
drape_ptr<dp::GraphicsContextFactory> m_factory; drape_ptr<dp::GraphicsContextFactory> m_factory;
@@ -50,22 +49,19 @@ double getExactDPI(double contentScaleFactor)
switch (UIDevice.currentDevice.userInterfaceIdiom) switch (UIDevice.currentDevice.userInterfaceIdiom)
{ {
case UIUserInterfaceIdiomPhone: case UIUserInterfaceIdiomPhone: return iPhoneDPI * contentScaleFactor;
return iPhoneDPI * contentScaleFactor; case UIUserInterfaceIdiomPad: return iPadDPI * contentScaleFactor;
case UIUserInterfaceIdiomPad: default: return mDPI * contentScaleFactor;
return iPadDPI * contentScaleFactor;
default:
return mDPI * contentScaleFactor;
} }
} }
} // namespace } // namespace
+ (dp::ApiVersion)getSupportedApiVersion + (dp::ApiVersion)getSupportedApiVersion
{ {
static dp::ApiVersion apiVersion = dp::ApiVersion::Invalid; static dp::ApiVersion apiVersion = dp::ApiVersion::Invalid;
if (apiVersion != dp::ApiVersion::Invalid) if (apiVersion != dp::ApiVersion::Invalid)
return apiVersion; return apiVersion;
#ifdef OMIM_METAL_AVAILABLE #ifdef OMIM_METAL_AVAILABLE
if (GetFramework().LoadPreferredGraphicsAPI() == dp::ApiVersion::Metal) if (GetFramework().LoadPreferredGraphicsAPI() == dp::ApiVersion::Metal)
{ {
@@ -74,7 +70,7 @@ double getExactDPI(double contentScaleFactor)
apiVersion = dp::ApiVersion::Metal; apiVersion = dp::ApiVersion::Metal;
} }
#endif #endif
if (apiVersion == dp::ApiVersion::Invalid) if (apiVersion == dp::ApiVersion::Invalid)
{ {
EAGLContext * tempContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; EAGLContext * tempContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
@@ -83,7 +79,7 @@ double getExactDPI(double contentScaleFactor)
else else
CHECK(false, ("OpenGL ES3 is not supported")); CHECK(false, ("OpenGL ES3 is not supported"));
} }
return apiVersion; return apiVersion;
} }
@@ -118,7 +114,7 @@ double getExactDPI(double contentScaleFactor)
// Correct retina display support in renderbuffer. // Correct retina display support in renderbuffer.
self.contentScaleFactor = [[UIScreen mainScreen] nativeScale]; self.contentScaleFactor = [[UIScreen mainScreen] nativeScale];
if (m_apiVersion == dp::ApiVersion::Metal) if (m_apiVersion == dp::ApiVersion::Metal)
{ {
#ifdef OMIM_METAL_AVAILABLE #ifdef OMIM_METAL_AVAILABLE
@@ -132,20 +128,18 @@ double getExactDPI(double contentScaleFactor)
{ {
CAEAGLLayer * layer = (CAEAGLLayer *)self.layer; CAEAGLLayer * layer = (CAEAGLLayer *)self.layer;
layer.opaque = YES; layer.opaque = YES;
layer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO, layer.drawableProperties =
kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8}; @{kEAGLDrawablePropertyRetainedBacking: @NO, kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8};
} }
auto & f = GetFramework(); auto & f = GetFramework();
f.SetGraphicsContextInitializationHandler([self]() { f.SetGraphicsContextInitializationHandler([self]() { self.graphicContextInitialized = YES; });
self.graphicContextInitialized = YES;
});
} }
- (void)createDrapeEngine - (void)createDrapeEngine
{ {
CGSize const objcSize = [self pixelSize]; CGSize const objcSize = [self pixelSize];
m2::PointU const s = m2::PointU(static_cast<uint32_t>(objcSize.width), static_cast<uint32_t>(objcSize.height)); m2::PointU const s = m2::PointU(static_cast<uint32_t>(objcSize.width), static_cast<uint32_t>(objcSize.height));
if (m_apiVersion == dp::ApiVersion::Metal) if (m_apiVersion == dp::ApiVersion::Metal)
{ {
#ifdef OMIM_METAL_AVAILABLE #ifdef OMIM_METAL_AVAILABLE
@@ -155,7 +149,7 @@ double getExactDPI(double contentScaleFactor)
else else
{ {
m_factory = make_unique_dp<dp::ThreadSafeFactory>( m_factory = make_unique_dp<dp::ThreadSafeFactory>(
new iosOGLContextFactory((CAEAGLLayer *)self.layer, m_apiVersion, m_presentAvailable)); new iosOGLContextFactory((CAEAGLLayer *)self.layer, m_apiVersion, m_presentAvailable));
} }
[self createDrapeEngineWithWidth:s.x height:s.y]; [self createDrapeEngineWithWidth:s.x height:s.y];
} }
@@ -164,7 +158,7 @@ double getExactDPI(double contentScaleFactor)
{ {
LOG(LINFO, ("CreateDrapeEngine Started", width, height, m_apiVersion)); LOG(LINFO, ("CreateDrapeEngine Started", width, height, m_apiVersion));
CHECK(m_factory != nullptr, ()); CHECK(m_factory != nullptr, ());
Framework::DrapeCreationParams p; Framework::DrapeCreationParams p;
p.m_apiVersion = m_apiVersion; p.m_apiVersion = m_apiVersion;
p.m_surfaceWidth = width; p.m_surfaceWidth = width;
@@ -183,7 +177,7 @@ double getExactDPI(double contentScaleFactor)
- (CGSize)pixelSize - (CGSize)pixelSize
{ {
CGSize const s = self.bounds.size; CGSize const s = self.bounds.size;
CGFloat const w = s.width * self.contentScaleFactor; CGFloat const w = s.width * self.contentScaleFactor;
CGFloat const h = s.height * self.contentScaleFactor; CGFloat const h = s.height * self.contentScaleFactor;
return CGSizeMake(w, h); return CGSizeMake(w, h);
@@ -221,12 +215,14 @@ double getExactDPI(double contentScaleFactor)
return _widgetsManager; return _widgetsManager;
} }
- (void)updateVisualScaleTo:(CGFloat)visualScale { - (void)updateVisualScaleTo:(CGFloat)visualScale
{
main_visualScale = df::VisualParams::Instance().GetVisualScale(); main_visualScale = df::VisualParams::Instance().GetVisualScale();
GetFramework().UpdateVisualScale(visualScale); GetFramework().UpdateVisualScale(visualScale);
} }
- (void)updateVisualScaleToMain { - (void)updateVisualScaleToMain
{
GetFramework().UpdateVisualScale(main_visualScale); GetFramework().UpdateVisualScale(main_visualScale);
} }

View File

@@ -22,33 +22,34 @@
SOFTWARE. SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#if ! __has_feature(objc_arc) #if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag #error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag
#endif #endif
#import "FirstSession.h" #import "FirstSession.h"
#include <utility> // std::pair
#include <sys/xattr.h> #include <sys/xattr.h>
#include <utility> // std::pair
#import <CoreFoundation/CoreFoundation.h>
#import <CoreFoundation/CFURL.h> #import <CoreFoundation/CFURL.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/NSURL.h> #import <Foundation/NSURL.h>
#if (TARGET_OS_IPHONE > 0) // Works for all iOS devices, including iPad. #if (TARGET_OS_IPHONE > 0) // Works for all iOS devices, including iPad.
#import <UIKit/UIApplication.h>
#import <UIKit/UIDevice.h> #import <UIKit/UIDevice.h>
#import <UIKit/UIScreen.h> #import <UIKit/UIScreen.h>
#import <UIKit/UIApplication.h>
#import <UIKit/UIWebView.h> #import <UIKit/UIWebView.h>
#endif // TARGET_OS_IPHONE #endif // TARGET_OS_IPHONE
#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h> #import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
#import <sys/socket.h>
namespace { namespace
{
// Key for app unique installation id in standardUserDefaults. // Key for app unique installation id in standardUserDefaults.
NSString * const kAlohalyticsInstallationId = @"AlohalyticsInstallationId"; NSString * const kAlohalyticsInstallationId = @"AlohalyticsInstallationId";
} // namespace } // namespace
// Keys for NSUserDefaults. // Keys for NSUserDefaults.
static NSString * const kInstalledVersionKey = @"AlohalyticsInstalledVersion"; static NSString * const kInstalledVersionKey = @"AlohalyticsInstalledVersion";
@@ -64,38 +65,49 @@ static NSString * gInstallationId = nil;
@implementation FirstSession @implementation FirstSession
+ (void)setup:(NSArray *)serverUrls withLaunchOptions:(NSDictionary *)options { + (void)setup:(NSArray *)serverUrls withLaunchOptions:(NSDictionary *)options
{
#if (TARGET_OS_IPHONE > 0) #if (TARGET_OS_IPHONE > 0)
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter]; NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
Class cls = [FirstSession class]; Class cls = [FirstSession class];
[nc addObserver:cls selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [nc addObserver:cls
[nc addObserver:cls selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; selector:@selector(applicationDidEnterBackground:)
#endif // TARGET_OS_IPHONE name:UIApplicationDidEnterBackgroundNotification
object:nil];
[nc addObserver:cls
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
#endif // TARGET_OS_IPHONE
// INIT // INIT
[self installationId]; [self installationId];
} }
#if (TARGET_OS_IPHONE > 0) #if (TARGET_OS_IPHONE > 0)
+ (void)applicationDidEnterBackground:(NSNotification *)notification { + (void)applicationDidEnterBackground:(NSNotification *)notification
if (gIsFirstSession) { {
if (gIsFirstSession)
gIsFirstSession = NO; gIsFirstSession = NO;
}
} }
+ (void)applicationWillTerminate:(NSNotification *)notification { + (void)applicationWillTerminate:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
} }
#endif // TARGET_OS_IPHONE #endif // TARGET_OS_IPHONE
#pragma mark Utility methods #pragma mark Utility methods
+ (BOOL)isFirstSession { + (BOOL)isFirstSession
{
return [self installationId] != nil && gIsFirstSession; return [self installationId] != nil && gIsFirstSession;
} }
+ (NSDate *)firstLaunchDate { + (NSDate *)firstLaunchDate
{
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
NSDate * date = [ud objectForKey:kFirstLaunchDateKey]; NSDate * date = [ud objectForKey:kFirstLaunchDateKey];
if (!date) { if (!date)
{
// Non-standard situation: this method is called before calling setup. Return current date. // Non-standard situation: this method is called before calling setup. Return current date.
date = [NSDate date]; date = [NSDate date];
[ud setObject:date forKey:kFirstLaunchDateKey]; [ud setObject:date forKey:kFirstLaunchDateKey];
@@ -103,42 +115,51 @@ static NSString * gInstallationId = nil;
return date; return date;
} }
+ (NSInteger)totalSecondsSpentInTheApp { + (NSInteger)totalSecondsSpentInTheApp
{
NSInteger seconds = [[NSUserDefaults standardUserDefaults] integerForKey:kTotalSecondsInTheApp]; NSInteger seconds = [[NSUserDefaults standardUserDefaults] integerForKey:kTotalSecondsInTheApp];
// Take into an account currently active session. // Take into an account currently active session.
if (gSessionStartTime) { if (gSessionStartTime)
seconds += static_cast<NSInteger>(-gSessionStartTime.timeIntervalSinceNow); seconds += static_cast<NSInteger>(-gSessionStartTime.timeIntervalSinceNow);
}
return seconds; return seconds;
} }
// Internal helper, returns nil for invalid paths. // Internal helper, returns nil for invalid paths.
+ (NSDate *)fileCreationDate:(NSString *)fullPath { + (NSDate *)fileCreationDate:(NSString *)fullPath
{
NSDictionary * attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:nil]; NSDictionary * attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:nil];
return attributes ? [attributes objectForKey:NSFileCreationDate] : nil; return attributes ? [attributes objectForKey:NSFileCreationDate] : nil;
} }
+ (NSDate *)installDate { + (NSDate *)installDate
return [FirstSession fileCreationDate:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]]; {
return [FirstSession
fileCreationDate:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
} }
+ (NSDate *)updateDate { + (NSDate *)updateDate
{
return [FirstSession fileCreationDate:[[NSBundle mainBundle] resourcePath]]; return [FirstSession fileCreationDate:[[NSBundle mainBundle] resourcePath]];
} }
+ (NSDate *)buildDate { + (NSDate *)buildDate
{
return [FirstSession fileCreationDate:[[NSBundle mainBundle] executablePath]]; return [FirstSession fileCreationDate:[[NSBundle mainBundle] executablePath]];
} }
+ (NSString *)installationId { + (NSString *)installationId
if (gInstallationId == nil) { {
if (gInstallationId == nil)
{
gIsFirstSession = NO; gIsFirstSession = NO;
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults]; NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
gInstallationId = [ud stringForKey:kAlohalyticsInstallationId]; gInstallationId = [ud stringForKey:kAlohalyticsInstallationId];
if (gInstallationId == nil) { if (gInstallationId == nil)
{
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
// All iOS IDs start with I: // All iOS IDs start with I:
gInstallationId = [@"I:" stringByAppendingString:(NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid))]; gInstallationId =
[@"I:" stringByAppendingString:(NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid))];
CFRelease(uuid); CFRelease(uuid);
[ud setValue:gInstallationId forKey:kAlohalyticsInstallationId]; [ud setValue:gInstallationId forKey:kAlohalyticsInstallationId];
gIsFirstSession = YES; gIsFirstSession = YES;

View File

@@ -9,15 +9,15 @@ std::string bcp47ToTwineLanguage(NSString const * bcp47)
// Update this array if new bcp47 languages are added into data/strings/sound.txt // Update this array if new bcp47 languages are added into data/strings/sound.txt
if ([@[@"pt-BR", @"es-MX"] containsObject:bcp47]) if ([@[@"pt-BR", @"es-MX"] containsObject:bcp47])
return bcp47.UTF8String; // Unchanged original bcp47 string return bcp47.UTF8String; // Unchanged original bcp47 string
if ([@[@"zh-CN", @"zh-CHS", @"zh-SG"] containsObject:bcp47]) if ([@[@"zh-CN", @"zh-CHS", @"zh-SG"] containsObject:bcp47])
return "zh-Hans"; // Chinese simplified return "zh-Hans"; // Chinese simplified
if ([bcp47 hasPrefix:@"zh"]) if ([bcp47 hasPrefix:@"zh"])
return "zh-Hant"; // Chinese traditional return "zh-Hant"; // Chinese traditional
// Taking two first symbols of a language name. For example ru-RU -> ru // Taking two first symbols of a language name. For example ru-RU -> ru
return [bcp47 substringToIndex:2].UTF8String; return [bcp47 substringToIndex:2].UTF8String;
} }
} // namespace locale_translator } // namespace locale_translator

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@
#import "NSDate+TimeDistance.h" #import "NSDate+TimeDistance.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
#import <CarPlay/CarPlay.h> #import <CarPlay/CarPlay.h>
#import <CoreSpotlight/CoreSpotlight.h> #import <CoreSpotlight/CoreSpotlight.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h> #import <CoreTelephony/CTTelephonyNetworkInfo.h>
@@ -34,19 +33,21 @@
// If you have a "missing header error" here, then please run configure.sh script in the root repo // If you have a "missing header error" here, then please run configure.sh script in the root repo
// folder. // folder.
namespace { namespace
NSString *const kUDLastLaunchDateKey = @"LastLaunchDate"; {
NSString *const kUDSessionsCountKey = @"SessionsCount"; NSString * const kUDLastLaunchDateKey = @"LastLaunchDate";
NSString *const kUDFirstVersionKey = @"FirstVersion"; NSString * const kUDSessionsCountKey = @"SessionsCount";
NSString *const kUDLastShareRequstDate = @"LastShareRequestDate"; NSString * const kUDFirstVersionKey = @"FirstVersion";
NSString *const kUDAutoNightModeOff = @"AutoNightModeOff"; NSString * const kUDLastShareRequstDate = @"LastShareRequestDate";
NSString *const kIOSIDFA = @"IFA"; NSString * const kUDAutoNightModeOff = @"AutoNightModeOff";
NSString *const kBundleVersion = @"BundleVersion"; NSString * const kIOSIDFA = @"IFA";
NSString * const kBundleVersion = @"BundleVersion";
/// Adds needed localized strings to C++ code /// Adds needed localized strings to C++ code
/// @TODO Refactor localization mechanism to make it simpler /// @TODO Refactor localization mechanism to make it simpler
void InitLocalizedStrings() { void InitLocalizedStrings()
Framework &f = GetFramework(); {
Framework & f = GetFramework();
f.AddString("core_entrance", L(@"core_entrance").UTF8String); f.AddString("core_entrance", L(@"core_entrance").UTF8String);
f.AddString("core_exit", L(@"core_exit").UTF8String); f.AddString("core_exit", L(@"core_exit").UTF8String);
@@ -57,30 +58,30 @@ void InitLocalizedStrings() {
} }
} // namespace } // namespace
@interface MapsAppDelegate () <MWMStorageObserver, CPApplicationDelegate>
@interface MapsAppDelegate () <MWMStorageObserver,
CPApplicationDelegate>
@property(nonatomic) NSInteger standbyCounter; @property(nonatomic) NSInteger standbyCounter;
@property(nonatomic) MWMBackgroundFetchScheduler *backgroundFetchScheduler; @property(nonatomic) MWMBackgroundFetchScheduler * backgroundFetchScheduler;
@end @end
@implementation MapsAppDelegate @implementation MapsAppDelegate
+ (MapsAppDelegate *)theApp { + (MapsAppDelegate *)theApp
{
return (MapsAppDelegate *)UIApplication.sharedApplication.delegate; return (MapsAppDelegate *)UIApplication.sharedApplication.delegate;
} }
- (BOOL)isDrapeEngineCreated { - (BOOL)isDrapeEngineCreated
{
return self.mapViewController.mapView.drapeEngineCreated; return self.mapViewController.mapView.drapeEngineCreated;
} }
- (void)searchText:(NSString *)searchString { - (void)searchText:(NSString *)searchString
if (!self.isDrapeEngineCreated) { {
dispatch_async(dispatch_get_main_queue(), ^{ if (!self.isDrapeEngineCreated)
[self searchText:searchString]; {
}); dispatch_async(dispatch_get_main_queue(), ^{ [self searchText:searchString]; });
return; return;
} }
SearchQuery * query = [[SearchQuery alloc] init:[searchString stringByAppendingString:@" "] SearchQuery * query = [[SearchQuery alloc] init:[searchString stringByAppendingString:@" "]
@@ -89,7 +90,8 @@ void InitLocalizedStrings() {
[[MWMMapViewControlsManager manager] search:query]; [[MWMMapViewControlsManager manager] search:query];
} }
- (void)commonInit { - (void)commonInit
{
[HttpThreadImpl setDownloadIndicatorProtocol:self]; [HttpThreadImpl setDownloadIndicatorProtocol:self];
InitLocalizedStrings(); InitLocalizedStrings();
GetFramework().SetupMeasurementSystem(); GetFramework().SetupMeasurementSystem();
@@ -103,7 +105,8 @@ void InitLocalizedStrings() {
[TrackRecordingManager.shared setup]; [TrackRecordingManager.shared setup];
} }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"application:didFinishLaunchingWithOptions: %@", launchOptions); NSLog(@"application:didFinishLaunchingWithOptions: %@", launchOptions);
[HttpThreadImpl setDownloadIndicatorProtocol:self]; [HttpThreadImpl setDownloadIndicatorProtocol:self];
@@ -113,30 +116,31 @@ void InitLocalizedStrings() {
[self commonInit]; [self commonInit];
if ([FirstSession isFirstSession]) { if ([FirstSession isFirstSession])
[self firstLaunchSetup]; [self firstLaunchSetup];
} else { else
[self incrementSessionCount]; [self incrementSessionCount];
}
[self enableTTSForTheFirstTime]; [self enableTTSForTheFirstTime];
if (![MapsAppDelegate isTestsEnvironment]) if (![MapsAppDelegate isTestsEnvironment])
[[iCloudSynchronizaionManager shared] start]; [[iCloudSynchronizaionManager shared] start];
[[DeepLinkHandler shared] applicationDidFinishLaunching:launchOptions]; [[DeepLinkHandler shared] applicationDidFinishLaunching:launchOptions];
// application:openUrl:options is called later for deep links if YES is returned. // application:openUrl:options is called later for deep links if YES is returned.
return YES; return YES;
} }
- (void)application:(UIApplication *)application - (void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
completionHandler:(void (^)(BOOL))completionHandler { completionHandler:(void (^)(BOOL))completionHandler
{
[self.mapViewController performAction:shortcutItem.type]; [self.mapViewController performAction:shortcutItem.type];
completionHandler(YES); completionHandler(YES);
} }
- (void)runBackgroundTasks:(NSArray<BackgroundFetchTask *> *_Nonnull)tasks - (void)runBackgroundTasks:(NSArray<BackgroundFetchTask *> * _Nonnull)tasks
completionHandler:(void (^_Nullable)(UIBackgroundFetchResult))completionHandler { completionHandler:(void (^_Nullable)(UIBackgroundFetchResult))completionHandler
{
self.backgroundFetchScheduler = [[MWMBackgroundFetchScheduler alloc] initWithTasks:tasks self.backgroundFetchScheduler = [[MWMBackgroundFetchScheduler alloc] initWithTasks:tasks
completionHandler:^(UIBackgroundFetchResult result) { completionHandler:^(UIBackgroundFetchResult result) {
if (completionHandler) if (completionHandler)
@@ -145,16 +149,19 @@ void InitLocalizedStrings() {
[self.backgroundFetchScheduler run]; [self.backgroundFetchScheduler run];
} }
- (void)applicationWillTerminate:(UIApplication *)application { - (void)applicationWillTerminate:(UIApplication *)application
{
[self.mapViewController onTerminate]; [self.mapViewController onTerminate];
// Global cleanup // Global cleanup
DeleteFramework(); DeleteFramework();
} }
- (void)applicationDidEnterBackground:(UIApplication *)application { - (void)applicationDidEnterBackground:(UIApplication *)application
{
LOG(LINFO, ("applicationDidEnterBackground - begin")); LOG(LINFO, ("applicationDidEnterBackground - begin"));
[DeepLinkHandler.shared reset]; [DeepLinkHandler.shared reset];
if (m_activeDownloadsCounter) { if (m_activeDownloadsCounter)
{
m_backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{ m_backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:self->m_backgroundTask]; [application endBackgroundTask:self->m_backgroundTask];
self->m_backgroundTask = UIBackgroundTaskInvalid; self->m_backgroundTask = UIBackgroundTaskInvalid;
@@ -168,16 +175,20 @@ void InitLocalizedStrings() {
LOG(LINFO, ("applicationDidEnterBackground - end")); LOG(LINFO, ("applicationDidEnterBackground - end"));
} }
- (void)applicationWillResignActive:(UIApplication *)application { - (void)applicationWillResignActive:(UIApplication *)application
{
LOG(LINFO, ("applicationWillResignActive - begin")); LOG(LINFO, ("applicationWillResignActive - begin"));
[self.mapViewController onGetFocus:NO]; [self.mapViewController onGetFocus:NO];
auto &f = GetFramework(); auto & f = GetFramework();
// On some devices we have to free all belong-to-graphics memory // On some devices we have to free all belong-to-graphics memory
// because of new OpenGL driver powered by Metal. // because of new OpenGL driver powered by Metal.
if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103) { if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103)
{
f.SetRenderingDisabled(true); f.SetRenderingDisabled(true);
f.OnDestroySurface(); f.OnDestroySurface();
} else { }
else
{
f.SetRenderingDisabled(false); f.SetRenderingDisabled(false);
} }
[MWMLocationManager applicationWillResignActive]; [MWMLocationManager applicationWillResignActive];
@@ -185,28 +196,28 @@ void InitLocalizedStrings() {
LOG(LINFO, ("applicationWillResignActive - end")); LOG(LINFO, ("applicationWillResignActive - end"));
} }
- (void)applicationWillEnterForeground:(UIApplication *)application { - (void)applicationWillEnterForeground:(UIApplication *)application
{
LOG(LINFO, ("applicationWillEnterForeground - begin")); LOG(LINFO, ("applicationWillEnterForeground - begin"));
if (!GpsTracker::Instance().IsEnabled()) if (!GpsTracker::Instance().IsEnabled())
return; return;
MWMViewController *topVc = MWMViewController * topVc =
static_cast<MWMViewController *>(self.mapViewController.navigationController.topViewController); static_cast<MWMViewController *>(self.mapViewController.navigationController.topViewController);
if (![topVc isKindOfClass:[MWMViewController class]]) if (![topVc isKindOfClass:[MWMViewController class]])
return; return;
if ([MWMSettings isTrackWarningAlertShown]) if ([MWMSettings isTrackWarningAlertShown])
return; return;
[topVc.alertController presentTrackWarningAlertWithCancelBlock:^{ [topVc.alertController presentTrackWarningAlertWithCancelBlock:^{ GpsTracker::Instance().SetEnabled(false); }];
GpsTracker::Instance().SetEnabled(false);
}];
[MWMSettings setTrackWarningAlertShown:YES]; [MWMSettings setTrackWarningAlertShown:YES];
LOG(LINFO, ("applicationWillEnterForeground - end")); LOG(LINFO, ("applicationWillEnterForeground - end"));
} }
- (void)applicationDidBecomeActive:(UIApplication *)application { - (void)applicationDidBecomeActive:(UIApplication *)application
{
LOG(LINFO, ("applicationDidBecomeActive - begin")); LOG(LINFO, ("applicationDidBecomeActive - begin"));
auto & f = GetFramework(); auto & f = GetFramework();
@@ -215,7 +226,8 @@ void InitLocalizedStrings() {
f.SetRenderingEnabled(); f.SetRenderingEnabled();
// On some devices we have to free all belong-to-graphics memory // On some devices we have to free all belong-to-graphics memory
// because of new OpenGL driver powered by Metal. // because of new OpenGL driver powered by Metal.
if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103) { if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103)
{
CGSize const objcSize = self.mapViewController.mapView.pixelSize; CGSize const objcSize = self.mapViewController.mapView.pixelSize;
f.OnRecoverSurface(static_cast<int>(objcSize.width), static_cast<int>(objcSize.height), f.OnRecoverSurface(static_cast<int>(objcSize.width), static_cast<int>(objcSize.height),
true /* recreateContextDependentResources */); true /* recreateContextDependentResources */);
@@ -227,8 +239,10 @@ void InitLocalizedStrings() {
LOG(LINFO, ("applicationDidBecomeActive - end")); LOG(LINFO, ("applicationDidBecomeActive - end"));
} }
// TODO: Drape enabling and iCloud sync are skipped during the test run due to the app crashing in teardown. This is a temporary solution. Drape should be properly disabled instead of merely skipping the enabling process. // TODO: Drape enabling and iCloud sync are skipped during the test run due to the app crashing in teardown. This is a
+ (BOOL)isTestsEnvironment { // temporary solution. Drape should be properly disabled instead of merely skipping the enabling process.
+ (BOOL)isTestsEnvironment
{
NSProcessInfo * processInfo = [NSProcessInfo processInfo]; NSProcessInfo * processInfo = [NSProcessInfo processInfo];
NSArray<NSString *> * launchArguments = [processInfo arguments]; NSArray<NSString *> * launchArguments = [processInfo arguments];
BOOL isTests = [launchArguments containsObject:@"-IsTests"]; BOOL isTests = [launchArguments containsObject:@"-IsTests"];
@@ -236,17 +250,21 @@ void InitLocalizedStrings() {
} }
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler { restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
if ([userActivity.activityType isEqualToString:CSSearchableItemActionType]) { {
NSString *searchStringKey = userActivity.userInfo[CSSearchableItemActivityIdentifier]; if ([userActivity.activityType isEqualToString:CSSearchableItemActionType])
NSString *searchString = L(searchStringKey); {
if (searchString) { NSString * searchStringKey = userActivity.userInfo[CSSearchableItemActivityIdentifier];
NSString * searchString = L(searchStringKey);
if (searchString)
{
[self searchText:searchString]; [self searchText:searchString];
return YES; return YES;
} }
} else if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb] && }
userActivity.webpageURL != nil) { else if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb] && userActivity.webpageURL != nil)
{
LOG(LINFO, ("application:continueUserActivity:restorationHandler: %@", userActivity.webpageURL)); LOG(LINFO, ("application:continueUserActivity:restorationHandler: %@", userActivity.webpageURL));
return [DeepLinkHandler.shared applicationDidReceiveUniversalLink:userActivity.webpageURL]; return [DeepLinkHandler.shared applicationDidReceiveUniversalLink:userActivity.webpageURL];
} }
@@ -254,49 +272,58 @@ void InitLocalizedStrings() {
return NO; return NO;
} }
- (void)disableDownloadIndicator { - (void)disableDownloadIndicator
{
--m_activeDownloadsCounter; --m_activeDownloadsCounter;
if (m_activeDownloadsCounter <= 0) { if (m_activeDownloadsCounter <= 0)
{
m_activeDownloadsCounter = 0; m_activeDownloadsCounter = 0;
if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) { if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground)
{
[UIApplication.sharedApplication endBackgroundTask:m_backgroundTask]; [UIApplication.sharedApplication endBackgroundTask:m_backgroundTask];
m_backgroundTask = UIBackgroundTaskInvalid; m_backgroundTask = UIBackgroundTaskInvalid;
} }
} }
} }
- (void)enableDownloadIndicator { - (void)enableDownloadIndicator
{
++m_activeDownloadsCounter; ++m_activeDownloadsCounter;
} }
+ (void)customizeAppearanceForNavigationBar:(UINavigationBar *)navigationBar { + (void)customizeAppearanceForNavigationBar:(UINavigationBar *)navigationBar
{
auto backImage = auto backImage =
[[UIImage imageNamed:@"ic_nav_bar_back_sys"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; [[UIImage imageNamed:@"ic_nav_bar_back_sys"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
navigationBar.backIndicatorImage = backImage; navigationBar.backIndicatorImage = backImage;
navigationBar.backIndicatorTransitionMaskImage = backImage; navigationBar.backIndicatorTransitionMaskImage = backImage;
} }
+ (void)customizeAppearance { + (void)customizeAppearance
{
[UIButton appearance].exclusiveTouch = YES; [UIButton appearance].exclusiveTouch = YES;
[self customizeAppearanceForNavigationBar:[UINavigationBar appearance]]; [self customizeAppearanceForNavigationBar:[UINavigationBar appearance]];
UITextField *textField = [UITextField appearance]; UITextField * textField = [UITextField appearance];
textField.keyboardAppearance = [UIColor isNightMode] ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault; textField.keyboardAppearance = [UIColor isNightMode] ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault;
} }
- (BOOL)application:(UIApplication *)app - (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
NSLog(@"application:openURL: %@ options: %@", url, options); NSLog(@"application:openURL: %@ options: %@", url, options);
return [DeepLinkHandler.shared applicationDidOpenUrl:url]; return [DeepLinkHandler.shared applicationDidOpenUrl:url];
} }
- (void)showMap { - (void)showMap
{
[(UINavigationController *)self.window.rootViewController popToRootViewControllerAnimated:YES]; [(UINavigationController *)self.window.rootViewController popToRootViewControllerAnimated:YES];
} }
- (void)updateApplicationIconBadgeNumber { - (void)updateApplicationIconBadgeNumber
{
auto const number = [self badgeNumber]; auto const number = [self badgeNumber];
// Delay init because BottomTabBarViewController.controller is null here. // Delay init because BottomTabBarViewController.controller is null here.
@@ -306,22 +333,25 @@ void InitLocalizedStrings() {
}); });
} }
- (NSUInteger)badgeNumber { - (NSUInteger)badgeNumber
auto &s = GetFramework().GetStorage(); {
auto & s = GetFramework().GetStorage();
storage::Storage::UpdateInfo updateInfo{}; storage::Storage::UpdateInfo updateInfo{};
s.GetUpdateInfo(s.GetRootId(), updateInfo); s.GetUpdateInfo(s.GetRootId(), updateInfo);
return updateInfo.m_numberOfMwmFilesToUpdate; return updateInfo.m_numberOfMwmFilesToUpdate;
} }
- (void)application:(UIApplication *)application - (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler { completionHandler:(void (^)())completionHandler
{
[BackgroundDownloader sharedBackgroundMapDownloader].backgroundCompletionHandler = completionHandler; [BackgroundDownloader sharedBackgroundMapDownloader].backgroundCompletionHandler = completionHandler;
} }
#pragma mark - MWMStorageObserver #pragma mark - MWMStorageObserver
- (void)processCountryEvent:(NSString *)countryId { - (void)processCountryEvent:(NSString *)countryId
{
// Dispatch this method after delay since there are too many events for group mwms download. // Dispatch this method after delay since there are too many events for group mwms download.
// We do not need to update badge frequently. // We do not need to update badge frequently.
// Update after 1 second delay (after last country event) is sure enough for app badge. // Update after 1 second delay (after last country event) is sure enough for app badge.
@@ -332,60 +362,67 @@ void InitLocalizedStrings() {
#pragma mark - Properties #pragma mark - Properties
- (MapViewController *)mapViewController { - (MapViewController *)mapViewController
for (id vc in [(UINavigationController *)self.window.rootViewController viewControllers]) { {
for (id vc in [(UINavigationController *)self.window.rootViewController viewControllers])
if ([vc isKindOfClass:[MapViewController class]]) if ([vc isKindOfClass:[MapViewController class]])
return vc; return vc;
}
NSAssert(false, @"Please check the logic"); NSAssert(false, @"Please check the logic");
return nil; return nil;
} }
- (MWMCarPlayService *)carplayService { - (MWMCarPlayService *)carplayService
{
return [MWMCarPlayService shared]; return [MWMCarPlayService shared];
} }
#pragma mark - TTS #pragma mark - TTS
- (void)enableTTSForTheFirstTime { - (void)enableTTSForTheFirstTime
{
if (![MWMTextToSpeech savedLanguage].length) if (![MWMTextToSpeech savedLanguage].length)
[MWMTextToSpeech setTTSEnabled:YES]; [MWMTextToSpeech setTTSEnabled:YES];
} }
#pragma mark - Standby #pragma mark - Standby
- (void)enableStandby { - (void)enableStandby
{
self.standbyCounter--; self.standbyCounter--;
} }
- (void)disableStandby { - (void)disableStandby
{
self.standbyCounter++; self.standbyCounter++;
} }
- (void)setStandbyCounter:(NSInteger)standbyCounter { - (void)setStandbyCounter:(NSInteger)standbyCounter
{
_standbyCounter = MAX(0, standbyCounter); _standbyCounter = MAX(0, standbyCounter);
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(),
[UIApplication sharedApplication].idleTimerDisabled = (self.standbyCounter != 0); ^{ [UIApplication sharedApplication].idleTimerDisabled = (self.standbyCounter != 0); });
});
} }
#pragma mark - Alert logic #pragma mark - Alert logic
- (void)firstLaunchSetup { - (void)firstLaunchSetup
NSString *currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; {
NSUserDefaults *standartDefaults = NSUserDefaults.standardUserDefaults; NSString * currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSUserDefaults * standartDefaults = NSUserDefaults.standardUserDefaults;
[standartDefaults setObject:currentVersion forKey:kUDFirstVersionKey]; [standartDefaults setObject:currentVersion forKey:kUDFirstVersionKey];
[standartDefaults setInteger:1 forKey:kUDSessionsCountKey]; [standartDefaults setInteger:1 forKey:kUDSessionsCountKey];
[standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey]; [standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey];
} }
- (void)incrementSessionCount { - (void)incrementSessionCount
NSUserDefaults *standartDefaults = NSUserDefaults.standardUserDefaults; {
NSUserDefaults * standartDefaults = NSUserDefaults.standardUserDefaults;
NSUInteger sessionCount = [standartDefaults integerForKey:kUDSessionsCountKey]; NSUInteger sessionCount = [standartDefaults integerForKey:kUDSessionsCountKey];
NSUInteger const kMaximumSessionCountForShowingShareAlert = 50; NSUInteger const kMaximumSessionCountForShowingShareAlert = 50;
if (sessionCount > kMaximumSessionCountForShowingShareAlert) if (sessionCount > kMaximumSessionCountForShowingShareAlert)
return; return;
NSDate *lastLaunchDate = [standartDefaults objectForKey:kUDLastLaunchDateKey]; NSDate * lastLaunchDate = [standartDefaults objectForKey:kUDLastLaunchDateKey];
if (lastLaunchDate.daysToNow > 0) { if (lastLaunchDate.daysToNow > 0)
{
sessionCount++; sessionCount++;
[standartDefaults setInteger:sessionCount forKey:kUDSessionsCountKey]; [standartDefaults setInteger:sessionCount forKey:kUDSessionsCountKey];
[standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey]; [standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey];
@@ -394,9 +431,10 @@ void InitLocalizedStrings() {
#pragma mark - Rate #pragma mark - Rate
- (BOOL)userIsNew { - (BOOL)userIsNew
NSString *currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; {
NSString *firstVersion = [NSUserDefaults.standardUserDefaults stringForKey:kUDFirstVersionKey]; NSString * currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSString * firstVersion = [NSUserDefaults.standardUserDefaults stringForKey:kUDFirstVersionKey];
if (!firstVersion.length || firstVersionIsLessThanSecond(firstVersion, currentVersion)) if (!firstVersion.length || firstVersionIsLessThanSecond(firstVersion, currentVersion))
return NO; return NO;
@@ -406,14 +444,16 @@ void InitLocalizedStrings() {
#pragma mark - CPApplicationDelegate implementation #pragma mark - CPApplicationDelegate implementation
- (void)application:(UIApplication *)application - (void)application:(UIApplication *)application
didConnectCarInterfaceController:(CPInterfaceController *)interfaceController didConnectCarInterfaceController:(CPInterfaceController *)interfaceController
toWindow:(CPWindow *)window API_AVAILABLE(ios(12.0)) { toWindow:(CPWindow *)window API_AVAILABLE(ios(12.0))
{
[self.carplayService setupWithWindow:window interfaceController:interfaceController]; [self.carplayService setupWithWindow:window interfaceController:interfaceController];
} }
- (void)application:(UIApplication *)application - (void)application:(UIApplication *)application
didDisconnectCarInterfaceController:(CPInterfaceController *)interfaceController didDisconnectCarInterfaceController:(CPInterfaceController *)interfaceController
fromWindow:(CPWindow *)window API_AVAILABLE(ios(12.0)) { fromWindow:(CPWindow *)window API_AVAILABLE(ios(12.0))
{
[self.carplayService destroy]; [self.carplayService destroy];
} }

View File

@@ -8,37 +8,32 @@ class DrawMetalContext : public dp::metal::MetalBaseContext
{ {
public: public:
DrawMetalContext(CAMetalLayer * metalLayer, m2::PointU const & screenSize) DrawMetalContext(CAMetalLayer * metalLayer, m2::PointU const & screenSize)
: dp::metal::MetalBaseContext(metalLayer.device, screenSize, [this]{ return [m_metalLayer nextDrawable]; }) : dp::metal::MetalBaseContext(metalLayer.device, screenSize, [this] { return [m_metalLayer nextDrawable]; })
, m_metalLayer(metalLayer) , m_metalLayer(metalLayer)
{} {}
void Resize(int w, int h) override void Resize(int w, int h) override
{ {
m_metalLayer.drawableSize = CGSize{static_cast<float>(w), static_cast<float>(h)}; m_metalLayer.drawableSize = CGSize{static_cast<float>(w), static_cast<float>(h)};
ResetFrameDrawable(); ResetFrameDrawable();
dp::metal::MetalBaseContext::Resize(w, h); dp::metal::MetalBaseContext::Resize(w, h);
} }
private: private:
CAMetalLayer * m_metalLayer; CAMetalLayer * m_metalLayer;
}; };
class UploadMetalContext : public dp::metal::MetalBaseContext class UploadMetalContext : public dp::metal::MetalBaseContext
{ {
public: public:
explicit UploadMetalContext(id<MTLDevice> device) explicit UploadMetalContext(id<MTLDevice> device) : dp::metal::MetalBaseContext(device, {}, nullptr) {}
: dp::metal::MetalBaseContext(device, {}, nullptr)
{}
void Present() override {} void Present() override {}
void MakeCurrent() override {} void MakeCurrent() override {}
void Resize(int w, int h) override {} void Resize(int w, int h) override {}
void SetFramebuffer(ref_ptr<dp::BaseFramebuffer> framebuffer) override {} void SetFramebuffer(ref_ptr<dp::BaseFramebuffer> framebuffer) override {}
void Init(dp::ApiVersion apiVersion) override void Init(dp::ApiVersion apiVersion) override { CHECK_EQUAL(apiVersion, dp::ApiVersion::Metal, ()); }
{
CHECK_EQUAL(apiVersion, dp::ApiVersion::Metal, ());
}
void SetClearColor(dp::Color const & color) override {} void SetClearColor(dp::Color const & color) override {}
void Clear(uint32_t clearBits, uint32_t storeBits) override {} void Clear(uint32_t clearBits, uint32_t storeBits) override {}
void Flush() override {} void Flush() override {}
@@ -46,8 +41,9 @@ public:
void SetDepthTestFunction(dp::TestFunction depthFunction) override {} void SetDepthTestFunction(dp::TestFunction depthFunction) override {}
void SetStencilTestEnabled(bool enabled) override {} void SetStencilTestEnabled(bool enabled) override {}
void SetStencilFunction(dp::StencilFace face, dp::TestFunction stencilFunction) override {} void SetStencilFunction(dp::StencilFace face, dp::TestFunction stencilFunction) override {}
void SetStencilActions(dp::StencilFace face, dp::StencilAction stencilFailAction, void SetStencilActions(dp::StencilFace face, dp::StencilAction stencilFailAction, dp::StencilAction depthFailAction,
dp::StencilAction depthFailAction, dp::StencilAction passAction) override {} dp::StencilAction passAction) override
{}
}; };
} // namespace } // namespace

View File

@@ -9,7 +9,7 @@
self = [super initWithCoder:coder]; self = [super initWithCoder:coder];
if (self) if (self)
[self initialize]; [self initialize];
NSLog(@"MetalView initWithCoder Ended"); NSLog(@"MetalView initWithCoder Ended");
return self; return self;
} }

View File

@@ -4,18 +4,20 @@
@interface MWMActivityViewController () @interface MWMActivityViewController ()
@property(weak, nonatomic) UIViewController *ownerViewController; @property(weak, nonatomic) UIViewController * ownerViewController;
@property(weak, nonatomic) UIView *anchorView; @property(weak, nonatomic) UIView * anchorView;
@end @end
@implementation MWMActivityViewController @implementation MWMActivityViewController
- (instancetype)initWithActivityItem:(id<UIActivityItemSource>)activityItem { - (instancetype)initWithActivityItem:(id<UIActivityItemSource>)activityItem
{
return [self initWithActivityItems:@[activityItem]]; return [self initWithActivityItems:@[activityItem]];
} }
- (instancetype)initWithActivityItems:(NSArray *)activityItems { - (instancetype)initWithActivityItems:(NSArray *)activityItems
{
self = [super initWithActivityItems:activityItems applicationActivities:nil]; self = [super initWithActivityItems:activityItems applicationActivities:nil];
if (self) if (self)
self.excludedActivityTypes = @[ self.excludedActivityTypes = @[
@@ -25,35 +27,38 @@
return self; return self;
} }
+ (instancetype)shareControllerForMyPosition:(CLLocationCoordinate2D)location { + (instancetype)shareControllerForMyPosition:(CLLocationCoordinate2D)location
MWMShareActivityItem *item = [[MWMShareActivityItem alloc] initForMyPositionAtLocation:location]; {
MWMActivityViewController *shareVC = [[self alloc] initWithActivityItem:item]; MWMShareActivityItem * item = [[MWMShareActivityItem alloc] initForMyPositionAtLocation:location];
MWMActivityViewController * shareVC = [[self alloc] initWithActivityItem:item];
shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypeAirDrop]; shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypeAirDrop];
return shareVC; return shareVC;
} }
+ (instancetype)shareControllerForPlacePage:(PlacePageData *)data { + (instancetype)shareControllerForPlacePage:(PlacePageData *)data
MWMShareActivityItem *item = [[MWMShareActivityItem alloc] initForPlacePage:data]; {
MWMActivityViewController *shareVC = [[self alloc] initWithActivityItem:item]; MWMShareActivityItem * item = [[MWMShareActivityItem alloc] initForPlacePage:data];
MWMActivityViewController * shareVC = [[self alloc] initWithActivityItem:item];
shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypeAirDrop]; shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypeAirDrop];
return shareVC; return shareVC;
} }
+ (instancetype)shareControllerForURL:(NSURL *)url + (instancetype)shareControllerForURL:(NSURL *)url
message:(NSString *)message message:(NSString *)message
completionHandler:(UIActivityViewControllerCompletionWithItemsHandler)completionHandler { completionHandler:(UIActivityViewControllerCompletionWithItemsHandler)completionHandler
NSMutableArray *items = [NSMutableArray arrayWithObject:message]; {
if (url) { NSMutableArray * items = [NSMutableArray arrayWithObject:message];
if (url)
[items addObject:url]; [items addObject:url];
}
MWMActivityViewController *shareVC = [[self alloc] initWithActivityItems:items.copy]; MWMActivityViewController * shareVC = [[self alloc] initWithActivityItems:items.copy];
shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypePostToFacebook]; shareVC.excludedActivityTypes = [shareVC.excludedActivityTypes arrayByAddingObject:UIActivityTypePostToFacebook];
shareVC.completionWithItemsHandler = completionHandler; shareVC.completionWithItemsHandler = completionHandler;
return shareVC; return shareVC;
} }
- (void)presentInParentViewController:(UIViewController *)parentVC anchorView:(UIView *)anchorView { - (void)presentInParentViewController:(UIViewController *)parentVC anchorView:(UIView *)anchorView
{
self.ownerViewController = parentVC; self.ownerViewController = parentVC;
self.anchorView = anchorView; self.anchorView = anchorView;
self.popoverPresentationController.sourceView = anchorView; self.popoverPresentationController.sourceView = anchorView;

View File

@@ -18,8 +18,8 @@
[activityType isEqualToString:@"com.facebook.Facebook.ShareExtension"] || [activityType isEqualToString:@"com.facebook.Facebook.ShareExtension"] ||
[activityType.lowercaseString rangeOfString:@"facebook"].length) [activityType.lowercaseString rangeOfString:@"facebook"].length)
{ {
NSString * url = [NSString stringWithFormat:@"https://comaps.app/fb-editor-v1?lang=%@", NSString * url =
@(languages::GetCurrentNorm().c_str())]; [NSString stringWithFormat:@"https://comaps.app/fb-editor-v1?lang=%@", @(languages::GetCurrentNorm().c_str())];
return [NSURL URLWithString:url]; return [NSURL URLWithString:url];
} }
@@ -27,7 +27,8 @@
if ([activityType isEqualToString:UIActivityTypePostToTwitter] || [activityType isEqualToString:UIActivityTypeMail]) if ([activityType isEqualToString:UIActivityTypePostToTwitter] || [activityType isEqualToString:UIActivityTypeMail])
return [NSString stringWithFormat:@"%@ %@", L(@"whatsnew_editor_message_1"), comapsURL]; return [NSString stringWithFormat:@"%@ %@", L(@"whatsnew_editor_message_1"), comapsURL];
return [NSString stringWithFormat:@"%@.\n%@\n%@", L(@"editor_sharing_title"), L(@"whatsnew_editor_message_1"), comapsURL]; return [NSString
stringWithFormat:@"%@.\n%@\n%@", L(@"editor_sharing_title"), L(@"whatsnew_editor_message_1"), comapsURL];
} }
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController - (NSString *)activityViewController:(UIActivityViewController *)activityViewController

View File

@@ -2,9 +2,9 @@
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
#import <CoreApi/PlacePageData.h> #import <CoreApi/PlacePageData.h>
#import <CoreApi/PlacePagePreviewData.h>
#import <CoreApi/PlacePageInfoData.h> #import <CoreApi/PlacePageInfoData.h>
#import <CoreApi/PlacePagePhone.h> #import <CoreApi/PlacePagePhone.h>
#import <CoreApi/PlacePagePreviewData.h>
#import <LinkPresentation/LPLinkMetadata.h> #import <LinkPresentation/LPLinkMetadata.h>
NSString * httpGe0Url(NSString * shortUrl) NSString * httpGe0Url(NSString * shortUrl)
@@ -15,7 +15,7 @@ NSString * httpGe0Url(NSString * shortUrl)
@interface MWMShareActivityItem () @interface MWMShareActivityItem ()
@property(nonatomic) PlacePageData *data; @property(nonatomic) PlacePageData * data;
@property(nonatomic) CLLocationCoordinate2D location; @property(nonatomic) CLLocationCoordinate2D location;
@property(nonatomic) BOOL isMyPosition; @property(nonatomic) BOOL isMyPosition;
@@ -41,7 +41,8 @@ NSString * httpGe0Url(NSString * shortUrl)
return nil; return nil;
} }
- (instancetype)initForPlacePage:(PlacePageData *)data { - (instancetype)initForPlacePage:(PlacePageData *)data
{
self = [super init]; self = [super init];
if (self) if (self)
{ {
@@ -56,8 +57,7 @@ NSString * httpGe0Url(NSString * shortUrl)
{ {
auto & f = GetFramework(); auto & f = GetFramework();
auto const title = ^NSString *(PlacePageData *data) auto const title = ^NSString *(PlacePageData * data) {
{
if (!data || data.isMyPosition) if (!data || data.isMyPosition)
return L(@"core_my_position"); return L(@"core_my_position");
else if (data.previewData.title.length > 0) else if (data.previewData.title.length > 0)
@@ -70,9 +70,9 @@ NSString * httpGe0Url(NSString * shortUrl)
return @""; return @"";
}; };
ms::LatLon const ll = self.data ? ms::LatLon(self.data.locationCoordinate.latitude, ms::LatLon const ll = self.data
self.data.locationCoordinate.longitude) ? ms::LatLon(self.data.locationCoordinate.latitude, self.data.locationCoordinate.longitude)
: ms::LatLon(self.location.latitude, self.location.longitude); : ms::LatLon(self.location.latitude, self.location.longitude);
std::string const & s = f.CodeGe0url(ll.m_lat, ll.m_lon, f.GetDrawScale(), title(self.data).UTF8String); std::string const & s = f.CodeGe0url(ll.m_lat, ll.m_lon, f.GetDrawScale(), title(self.data).UTF8String);
NSString * url = @(s.c_str()); NSString * url = @(s.c_str());
@@ -104,7 +104,8 @@ NSString * httpGe0Url(NSString * shortUrl)
return [self subjectDefault]; return [self subjectDefault];
} }
- (LPLinkMetadata *)activityViewControllerLinkMetadata:(UIActivityViewController *)activityViewController API_AVAILABLE(ios(13.0)) - (LPLinkMetadata *)activityViewControllerLinkMetadata:(UIActivityViewController *)activityViewController
API_AVAILABLE(ios(13.0))
{ {
LPLinkMetadata * metadata = [[LPLinkMetadata alloc] init]; LPLinkMetadata * metadata = [[LPLinkMetadata alloc] init];
metadata.originalURL = [NSURL URLWithString:httpGe0Url([self url:NO])]; metadata.originalURL = [NSURL URLWithString:httpGe0Url([self url:NO])];
@@ -118,9 +119,9 @@ NSString * httpGe0Url(NSString * shortUrl)
- (NSString *)itemForTwitter - (NSString *)itemForTwitter
{ {
NSString * shortUrl = [self url:YES]; NSString * shortUrl = [self url:YES];
return [NSString stringWithFormat:@"%@\n%@", httpGe0Url(shortUrl), return [NSString
self.isMyPosition ? L(@"my_position_share_email_subject") stringWithFormat:@"%@\n%@", httpGe0Url(shortUrl),
: self.data.previewData.title]; self.isMyPosition ? L(@"my_position_share_email_subject") : self.data.previewData.title];
} }
- (NSString *)itemDefaultWithActivityType:(NSString *)activityType - (NSString *)itemDefaultWithActivityType:(NSString *)activityType
@@ -132,27 +133,21 @@ NSString * httpGe0Url(NSString * shortUrl)
BOOL const hasSubject = [activityType isEqualToString:UIActivityTypeMail]; BOOL const hasSubject = [activityType isEqualToString:UIActivityTypeMail];
if (hasSubject) if (hasSubject)
return url; return url;
return [NSString return [NSString stringWithFormat:@"%@ %@", L(@"my_position_share_email_subject"), url];
stringWithFormat:@"%@ %@", L(@"my_position_share_email_subject"), url];
} }
NSMutableArray *phones = [NSMutableArray new]; NSMutableArray * phones = [NSMutableArray new];
[self.data.infoData.phones enumerateObjectsUsingBlock:^(PlacePagePhone * _Nonnull phone, NSUInteger idx, BOOL * _Nonnull stop) { [self.data.infoData.phones enumerateObjectsUsingBlock:^(PlacePagePhone * _Nonnull phone, NSUInteger idx,
[phones addObject:phone.phone]; BOOL * _Nonnull stop) { [phones addObject:phone.phone]; }];
}];
NSMutableString * result = [L(@"sharing_call_action_look") mutableCopy]; NSMutableString * result = [L(@"sharing_call_action_look") mutableCopy];
std::vector<NSString *> strings{self.data.previewData.title, std::vector<NSString *> strings{self.data.previewData.title, self.data.previewData.subtitle,
self.data.previewData.subtitle, self.data.previewData.secondarySubtitle, [phones componentsJoinedByString:@"; "],
self.data.previewData.secondarySubtitle, url};
[phones componentsJoinedByString:@"; "],
url};
for (auto const & str : strings) for (auto const & str : strings)
{
if (str.length) if (str.length)
[result appendString:[NSString stringWithFormat:@"\n%@", str]]; [result appendString:[NSString stringWithFormat:@"\n%@", str]];
}
return result; return result;
} }
@@ -161,8 +156,7 @@ NSString * httpGe0Url(NSString * shortUrl)
- (NSString *)subjectDefault - (NSString *)subjectDefault
{ {
return self.isMyPosition ? L(@"my_position_share_email_subject") return self.isMyPosition ? L(@"my_position_share_email_subject") : L(@"bookmark_share_email_subject");
: L(@"bookmark_share_email_subject");
} }
@end @end

View File

@@ -17,17 +17,19 @@
#include "base/assert.hpp" #include "base/assert.hpp"
namespace { namespace
{
BOOL canAutoDownload(storage::CountryId const &countryId) { BOOL canAutoDownload(storage::CountryId const & countryId)
{
if (![MWMSettings autoDownloadEnabled]) if (![MWMSettings autoDownloadEnabled])
return NO; return NO;
if (GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_WIFI) if (GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_WIFI)
return NO; return NO;
CLLocation *lastLocation = [MWMLocationManager lastLocation]; CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (!lastLocation) if (!lastLocation)
return NO; return NO;
auto const &countryInfoGetter = GetFramework().GetCountryInfoGetter(); auto const & countryInfoGetter = GetFramework().GetCountryInfoGetter();
if (countryId != countryInfoGetter.GetRegionCountryId(lastLocation.mercator)) if (countryId != countryInfoGetter.GetRegionCountryId(lastLocation.mercator))
return NO; return NO;
return YES; return YES;
@@ -37,46 +39,51 @@ BOOL canAutoDownload(storage::CountryId const &countryId) {
using namespace storage; using namespace storage;
@interface MWMMapDownloadDialog () <MWMStorageObserver, MWMCircularProgressProtocol> @interface MWMMapDownloadDialog () <MWMStorageObserver, MWMCircularProgressProtocol>
@property(strong, nonatomic) IBOutlet UILabel *parentNode; @property(strong, nonatomic) IBOutlet UILabel * parentNode;
@property(strong, nonatomic) IBOutlet UILabel *node; @property(strong, nonatomic) IBOutlet UILabel * node;
@property(strong, nonatomic) IBOutlet UILabel *nodeSize; @property(strong, nonatomic) IBOutlet UILabel * nodeSize;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *nodeTopOffset; @property(strong, nonatomic) IBOutlet NSLayoutConstraint * nodeTopOffset;
@property(strong, nonatomic) IBOutlet UIButton *downloadButton; @property(strong, nonatomic) IBOutlet UIButton * downloadButton;
@property(strong, nonatomic) IBOutlet UIView *progressWrapper; @property(strong, nonatomic) IBOutlet UIView * progressWrapper;
@property(weak, nonatomic) MapViewController *controller; @property(weak, nonatomic) MapViewController * controller;
@property(nonatomic) MWMCircularProgress *progress; @property(nonatomic) MWMCircularProgress * progress;
@property(nonatomic) NSMutableArray<NSDate *> *skipDownloadTimes; @property(nonatomic) NSMutableArray<NSDate *> * skipDownloadTimes;
@property(nonatomic) BOOL isAutoDownloadCancelled; @property(nonatomic) BOOL isAutoDownloadCancelled;
@end @end
@implementation MWMMapDownloadDialog { @implementation MWMMapDownloadDialog
{
CountryId m_countryId; CountryId m_countryId;
CountryId m_autoDownloadCountryId; CountryId m_autoDownloadCountryId;
} }
+ (instancetype)dialogForController:(MapViewController *)controller { + (instancetype)dialogForController:(MapViewController *)controller
MWMMapDownloadDialog *dialog = [NSBundle.mainBundle loadNibNamed:[self className] owner:nil options:nil].firstObject; {
MWMMapDownloadDialog * dialog = [NSBundle.mainBundle loadNibNamed:[self className] owner:nil options:nil].firstObject;
dialog.controller = controller; dialog.controller = controller;
return dialog; return dialog;
} }
- (void)configDialog { - (void)configDialog
auto &f = GetFramework(); {
auto const &s = f.GetStorage(); auto & f = GetFramework();
auto const &p = f.GetDownloadingPolicy(); auto const & s = f.GetStorage();
auto const & p = f.GetDownloadingPolicy();
NodeAttrs nodeAttrs; NodeAttrs nodeAttrs;
s.GetNodeAttrs(m_countryId, nodeAttrs); s.GetNodeAttrs(m_countryId, nodeAttrs);
if (!nodeAttrs.m_present && ![MWMRouter isRoutingActive]) { if (!nodeAttrs.m_present && ![MWMRouter isRoutingActive])
{
BOOL const isMultiParent = nodeAttrs.m_parentInfo.size() > 1; BOOL const isMultiParent = nodeAttrs.m_parentInfo.size() > 1;
BOOL const noParrent = (nodeAttrs.m_parentInfo[0].m_id == s.GetRootId()); BOOL const noParrent = (nodeAttrs.m_parentInfo[0].m_id == s.GetRootId());
BOOL const hideParent = (noParrent || isMultiParent); BOOL const hideParent = (noParrent || isMultiParent);
self.parentNode.hidden = hideParent; self.parentNode.hidden = hideParent;
self.nodeTopOffset.priority = hideParent ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow; self.nodeTopOffset.priority = hideParent ? UILayoutPriorityDefaultHigh : UILayoutPriorityDefaultLow;
if (!hideParent) { if (!hideParent)
{
self.parentNode.text = @(nodeAttrs.m_topmostParentInfo[0].m_localName.c_str()); self.parentNode.text = @(nodeAttrs.m_topmostParentInfo[0].m_localName.c_str());
self.parentNode.textColor = [UIColor blackSecondaryText]; self.parentNode.textColor = [UIColor blackSecondaryText];
} }
@@ -87,47 +94,46 @@ using namespace storage;
self.nodeSize.text = formattedSize(nodeAttrs.m_mwmSize); self.nodeSize.text = formattedSize(nodeAttrs.m_mwmSize);
self.nodeSize.font = [UIFont medium14].monospaced; self.nodeSize.font = [UIFont medium14].monospaced;
switch (nodeAttrs.m_status) { switch (nodeAttrs.m_status)
case NodeStatus::NotDownloaded: {
case NodeStatus::Partly: { case NodeStatus::NotDownloaded:
MapViewController *controller = self.controller; case NodeStatus::Partly:
BOOL const isMapVisible = [controller.navigationController.topViewController isEqual:controller]; {
if (isMapVisible && !self.isAutoDownloadCancelled && canAutoDownload(m_countryId)) { MapViewController * controller = self.controller;
m_autoDownloadCountryId = m_countryId; BOOL const isMapVisible = [controller.navigationController.topViewController isEqual:controller];
[[MWMStorage sharedStorage] downloadNode:@(m_countryId.c_str()) if (isMapVisible && !self.isAutoDownloadCancelled && canAutoDownload(m_countryId))
onSuccess:^{ {
[self showInQueue]; m_autoDownloadCountryId = m_countryId;
}]; [[MWMStorage sharedStorage] downloadNode:@(m_countryId.c_str()) onSuccess:^{ [self showInQueue]; }];
} else {
m_autoDownloadCountryId = kInvalidCountryId;
[self showDownloadRequest];
}
[[MWMCarPlayService shared] showNoMapAlert];
break;
} }
case NodeStatus::Downloading: else
if (nodeAttrs.m_downloadingProgress.m_bytesTotal != 0) {
[self showDownloading:(CGFloat)nodeAttrs.m_downloadingProgress.m_bytesDownloaded / m_autoDownloadCountryId = kInvalidCountryId;
nodeAttrs.m_downloadingProgress.m_bytesTotal]; [self showDownloadRequest];
break; }
case NodeStatus::Applying: [[MWMCarPlayService shared] showNoMapAlert];
case NodeStatus::InQueue: break;
[self showInQueue];
break;
case NodeStatus::Undefined:
case NodeStatus::Error:
if (p.IsAutoRetryDownloadFailed()) {
[self showError:nodeAttrs.m_error];
} else {
[self showInQueue];
}
break;
case NodeStatus::OnDisk:
case NodeStatus::OnDiskOutOfDate:
[self removeFromSuperview];
break;
} }
} else { case NodeStatus::Downloading:
if (nodeAttrs.m_downloadingProgress.m_bytesTotal != 0)
[self showDownloading:(CGFloat)nodeAttrs.m_downloadingProgress.m_bytesDownloaded /
nodeAttrs.m_downloadingProgress.m_bytesTotal];
break;
case NodeStatus::Applying:
case NodeStatus::InQueue: [self showInQueue]; break;
case NodeStatus::Undefined:
case NodeStatus::Error:
if (p.IsAutoRetryDownloadFailed())
[self showError:nodeAttrs.m_error];
else
[self showInQueue];
break;
case NodeStatus::OnDisk:
case NodeStatus::OnDiskOutOfDate: [self removeFromSuperview]; break;
}
}
else
{
[self removeFromSuperview]; [self removeFromSuperview];
} }
@@ -135,10 +141,11 @@ using namespace storage;
[self setNeedsLayout]; [self setNeedsLayout];
} }
- (void)addToSuperview { - (void)addToSuperview
{
if (self.superview) if (self.superview)
return; return;
MapViewController *controller = self.controller; MapViewController * controller = self.controller;
[controller.view insertSubview:self aboveSubview:controller.controlsView]; [controller.view insertSubview:self aboveSubview:controller.controlsView];
[[MWMStorage sharedStorage] addObserver:self]; [[MWMStorage sharedStorage] addObserver:self];
@@ -147,15 +154,16 @@ using namespace storage;
[self.centerYAnchor constraintEqualToAnchor:controller.view.centerYAnchor].active = YES; [self.centerYAnchor constraintEqualToAnchor:controller.view.centerYAnchor].active = YES;
} }
- (void)removeFromSuperview
- (void)removeFromSuperview { {
[[MWMCarPlayService shared] hideNoMapAlert]; [[MWMCarPlayService shared] hideNoMapAlert];
self.progress.state = MWMCircularProgressStateNormal; self.progress.state = MWMCircularProgressStateNormal;
[[MWMStorage sharedStorage] removeObserver:self]; [[MWMStorage sharedStorage] removeObserver:self];
[super removeFromSuperview]; [super removeFromSuperview];
} }
- (void)showError:(NodeErrorCode)errorCode { - (void)showError:(NodeErrorCode)errorCode
{
if (errorCode == NodeErrorCode::NoError) if (errorCode == NodeErrorCode::NoError)
return; return;
self.nodeSize.textColor = [UIColor red]; self.nodeSize.textColor = [UIColor red];
@@ -163,47 +171,45 @@ using namespace storage;
self.downloadButton.hidden = YES; self.downloadButton.hidden = YES;
self.progressWrapper.hidden = NO; self.progressWrapper.hidden = NO;
self.progress.state = MWMCircularProgressStateFailed; self.progress.state = MWMCircularProgressStateFailed;
MWMAlertViewController *avc = self.controller.alertController; MWMAlertViewController * avc = self.controller.alertController;
[self addToSuperview]; [self addToSuperview];
auto const retryBlock = ^{ auto const retryBlock = ^{
[self showInQueue]; [self showInQueue];
[[MWMStorage sharedStorage] retryDownloadNode:@(self->m_countryId.c_str())]; [[MWMStorage sharedStorage] retryDownloadNode:@(self->m_countryId.c_str())];
}; };
auto const cancelBlock = ^{ auto const cancelBlock = ^{ [[MWMStorage sharedStorage] cancelDownloadNode:@(self->m_countryId.c_str())]; };
[[MWMStorage sharedStorage] cancelDownloadNode:@(self->m_countryId.c_str())]; switch (errorCode)
}; {
switch (errorCode) { case NodeErrorCode::NoError: break;
case NodeErrorCode::NoError: case NodeErrorCode::UnknownError:
break; [avc presentDownloaderInternalErrorAlertWithOkBlock:retryBlock cancelBlock:cancelBlock];
case NodeErrorCode::UnknownError: break;
[avc presentDownloaderInternalErrorAlertWithOkBlock:retryBlock cancelBlock:cancelBlock]; case NodeErrorCode::OutOfMemFailed: [avc presentDownloaderNotEnoughSpaceAlert]; break;
break; case NodeErrorCode::NoInetConnection:
case NodeErrorCode::OutOfMemFailed: [avc presentDownloaderNoConnectionAlertWithOkBlock:retryBlock cancelBlock:cancelBlock];
[avc presentDownloaderNotEnoughSpaceAlert]; break;
break;
case NodeErrorCode::NoInetConnection:
[avc presentDownloaderNoConnectionAlertWithOkBlock:retryBlock cancelBlock:cancelBlock];
break;
} }
} }
- (void)showDownloadRequest { - (void)showDownloadRequest
{
self.downloadButton.hidden = NO; self.downloadButton.hidden = NO;
self.progressWrapper.hidden = YES; self.progressWrapper.hidden = YES;
[self addToSuperview]; [self addToSuperview];
} }
- (void)showDownloading:(CGFloat)progress { - (void)showDownloading:(CGFloat)progress
{
self.nodeSize.textColor = [UIColor blackSecondaryText]; self.nodeSize.textColor = [UIColor blackSecondaryText];
self.nodeSize.text = self.nodeSize.text = [NSString stringWithFormat:@"%@ %.0f%%", L(@"downloader_downloading"), progress * 100.f];
[NSString stringWithFormat:@"%@ %.0f%%", L(@"downloader_downloading"), progress * 100.f];
self.downloadButton.hidden = YES; self.downloadButton.hidden = YES;
self.progressWrapper.hidden = NO; self.progressWrapper.hidden = NO;
self.progress.progress = progress; self.progress.progress = progress;
[self addToSuperview]; [self addToSuperview];
} }
- (void)showInQueue { - (void)showInQueue
{
self.nodeSize.textColor = [UIColor blackSecondaryText]; self.nodeSize.textColor = [UIColor blackSecondaryText];
self.nodeSize.text = L(@"downloader_queued"); self.nodeSize.text = L(@"downloader_queued");
self.downloadButton.hidden = YES; self.downloadButton.hidden = YES;
@@ -212,7 +218,8 @@ using namespace storage;
[self addToSuperview]; [self addToSuperview];
} }
- (void)processViewportCountryEvent:(CountryId const &)countryId { - (void)processViewportCountryEvent:(CountryId const &)countryId
{
m_countryId = countryId; m_countryId = countryId;
if (countryId == kInvalidCountryId) if (countryId == kInvalidCountryId)
[self removeFromSuperview]; [self removeFromSuperview];
@@ -222,7 +229,8 @@ using namespace storage;
#pragma mark - MWMStorageObserver #pragma mark - MWMStorageObserver
- (void)processCountryEvent:(NSString *)countryId { - (void)processCountryEvent:(NSString *)countryId
{
if (m_countryId != countryId.UTF8String) if (m_countryId != countryId.UTF8String)
return; return;
if (self.superview) if (self.superview)
@@ -231,20 +239,23 @@ using namespace storage;
[self removeFromSuperview]; [self removeFromSuperview];
} }
- (void)processCountry:(NSString *)countryId - (void)processCountry:(NSString *)countryId downloadedBytes:(uint64_t)downloadedBytes totalBytes:(uint64_t)totalBytes
downloadedBytes:(uint64_t)downloadedBytes {
totalBytes:(uint64_t)totalBytes {
if (self.superview && m_countryId == countryId.UTF8String) if (self.superview && m_countryId == countryId.UTF8String)
[self showDownloading:(CGFloat)downloadedBytes / totalBytes]; [self showDownloading:(CGFloat)downloadedBytes / totalBytes];
} }
#pragma mark - MWMCircularProgressDelegate #pragma mark - MWMCircularProgressDelegate
- (void)progressButtonPressed:(nonnull MWMCircularProgress *)progress { - (void)progressButtonPressed:(nonnull MWMCircularProgress *)progress
if (progress.state == MWMCircularProgressStateFailed) { {
if (progress.state == MWMCircularProgressStateFailed)
{
[self showInQueue]; [self showInQueue];
[[MWMStorage sharedStorage] retryDownloadNode:@(m_countryId.c_str())]; [[MWMStorage sharedStorage] retryDownloadNode:@(m_countryId.c_str())];
} else { }
else
{
if (m_autoDownloadCountryId == m_countryId) if (m_autoDownloadCountryId == m_countryId)
self.isAutoDownloadCancelled = YES; self.isAutoDownloadCancelled = YES;
[[MWMStorage sharedStorage] cancelDownloadNode:@(m_countryId.c_str())]; [[MWMStorage sharedStorage] cancelDownloadNode:@(m_countryId.c_str())];
@@ -253,22 +264,25 @@ using namespace storage;
#pragma mark - Actions #pragma mark - Actions
- (IBAction)downloadAction { - (IBAction)downloadAction
[[MWMStorage sharedStorage] downloadNode:@(m_countryId.c_str()) {
onSuccess:^{ [self showInQueue]; }]; [[MWMStorage sharedStorage] downloadNode:@(m_countryId.c_str()) onSuccess:^{ [self showInQueue]; }];
} }
#pragma mark - Properties #pragma mark - Properties
- (MWMCircularProgress *)progress { - (MWMCircularProgress *)progress
if (!_progress) { {
if (!_progress)
{
_progress = [MWMCircularProgress downloaderProgressForParentView:self.progressWrapper]; _progress = [MWMCircularProgress downloaderProgressForParentView:self.progressWrapper];
_progress.delegate = self; _progress.delegate = self;
} }
return _progress; return _progress;
} }
- (NSMutableArray<NSDate *> *)skipDownloadTimes { - (NSMutableArray<NSDate *> *)skipDownloadTimes
{
if (!_skipDownloadTimes) if (!_skipDownloadTimes)
_skipDownloadTimes = [@[] mutableCopy]; _skipDownloadTimes = [@[] mutableCopy];
return _skipDownloadTimes; return _skipDownloadTimes;

View File

@@ -25,9 +25,9 @@
self.visualScale = p.m_visualScale; self.visualScale = p.m_visualScale;
m_skin.reset(new gui::Skin(gui::ResolveGuiSkinFile("default"), p.m_visualScale)); m_skin.reset(new gui::Skin(gui::ResolveGuiSkinFile("default"), p.m_visualScale));
m_skin->Resize(p.m_surfaceWidth, p.m_surfaceHeight); m_skin->Resize(p.m_surfaceWidth, p.m_surfaceHeight);
m_skin->ForEach( m_skin->ForEach([&p](gui::EWidget widget, gui::Position const & pos) { p.m_widgetsInitInfo[widget] = pos; });
[&p](gui::EWidget widget, gui::Position const & pos) { p.m_widgetsInitInfo[widget] = pos; }); p.m_widgetsInitInfo[gui::WIDGET_SCALE_FPS_LABEL] =
p.m_widgetsInitInfo[gui::WIDGET_SCALE_FPS_LABEL] = gui::Position(m2::PointF(self.visualScale * 10, self.visualScale * 45), dp::LeftTop); gui::Position(m2::PointF(self.visualScale * 10, self.visualScale * 45), dp::LeftTop);
} }
- (void)resize:(CGSize)size - (void)resize:(CGSize)size
@@ -35,9 +35,10 @@
if (m_skin != nullptr) if (m_skin != nullptr)
m_skin->Resize(size.width, size.height); m_skin->Resize(size.width, size.height);
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if ([MWMCarPlayService shared].isCarplayActivated) { if ([MWMCarPlayService shared].isCarplayActivated)
{
CGRect bounds = [MapViewController sharedController].mapView.bounds; CGRect bounds = [MapViewController sharedController].mapView.bounds;
[self updateLayout: bounds]; [self updateLayout:bounds];
return; return;
} }
[self updateLayoutForAvailableArea]; [self updateLayoutForAvailableArea];
@@ -49,9 +50,8 @@
if (CGRectEqualToRect(self.availableArea, frame)) if (CGRectEqualToRect(self.availableArea, frame))
return; return;
self.availableArea = frame; self.availableArea = frame;
if ([MWMCarPlayService shared].isCarplayActivated) { if ([MWMCarPlayService shared].isCarplayActivated)
return; return;
}
[self updateLayout:frame]; [self updateLayout:frame];
} }
@@ -68,20 +68,20 @@
auto const vs = self.visualScale; auto const vs = self.visualScale;
auto const viewHeight = [MapViewController sharedController].mapView.height; auto const viewHeight = [MapViewController sharedController].mapView.height;
auto const viewWidth = [MapViewController sharedController].mapView.width; auto const viewWidth = [MapViewController sharedController].mapView.width;
auto const rulerOffset = auto const rulerOffset = m2::PointF(frame.origin.x * vs, (frame.origin.y + frame.size.height - viewHeight) * vs);
m2::PointF(frame.origin.x * vs, (frame.origin.y + frame.size.height - viewHeight) * vs);
auto const kCompassAdditionalYOffset = [TrackRecordingManager.shared isActive] ? 50 : 0; auto const kCompassAdditionalYOffset = [TrackRecordingManager.shared isActive] ? 50 : 0;
auto const compassOffset = auto const compassOffset = m2::PointF((frame.origin.x + frame.size.width - viewWidth) * vs,
m2::PointF((frame.origin.x + frame.size.width - viewWidth) * vs, (frame.origin.y + kCompassAdditionalYOffset) * vs); (frame.origin.y + kCompassAdditionalYOffset) * vs);
m_skin->ForEach([&](gui::EWidget w, gui::Position const & pos) { m_skin->ForEach([&](gui::EWidget w, gui::Position const & pos)
{
m2::PointF pivot = pos.m_pixelPivot; m2::PointF pivot = pos.m_pixelPivot;
switch (w) switch (w)
{ {
case gui::WIDGET_RULER: case gui::WIDGET_RULER:
case gui::WIDGET_COPYRIGHT: pivot += rulerOffset; break; case gui::WIDGET_COPYRIGHT: pivot += rulerOffset; break;
case gui::WIDGET_COMPASS: pivot += compassOffset; break; case gui::WIDGET_COMPASS: pivot += compassOffset; break;
case gui::WIDGET_SCALE_FPS_LABEL: case gui::WIDGET_SCALE_FPS_LABEL:
case gui::WIDGET_CHOOSE_POSITION_MARK: break; case gui::WIDGET_CHOOSE_POSITION_MARK: break;
} }
layout[w] = pivot; layout[w] = pivot;
}); });

View File

@@ -5,8 +5,8 @@
#include "base/assert.hpp" #include "base/assert.hpp"
#include "base/logging.cpp" #include "base/logging.cpp"
iosOGLContext::iosOGLContext(CAEAGLLayer * layer, dp::ApiVersion apiVersion, iosOGLContext::iosOGLContext(CAEAGLLayer * layer, dp::ApiVersion apiVersion, iosOGLContext * contextToShareWith,
iosOGLContext * contextToShareWith, bool needBuffers) bool needBuffers)
: m_apiVersion(apiVersion) : m_apiVersion(apiVersion)
, m_layer(layer) , m_layer(layer)
, m_nativeContext(NULL) , m_nativeContext(NULL)
@@ -20,7 +20,7 @@ iosOGLContext::iosOGLContext(CAEAGLLayer * layer, dp::ApiVersion apiVersion,
if (contextToShareWith != NULL) if (contextToShareWith != NULL)
{ {
m_nativeContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 m_nativeContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
sharegroup: contextToShareWith->m_nativeContext.sharegroup]; sharegroup:contextToShareWith->m_nativeContext.sharegroup];
} }
else else
{ {
@@ -36,7 +36,7 @@ iosOGLContext::~iosOGLContext()
void iosOGLContext::MakeCurrent() void iosOGLContext::MakeCurrent()
{ {
ASSERT(m_nativeContext != NULL, ()); ASSERT(m_nativeContext != NULL, ());
[EAGLContext setCurrentContext: m_nativeContext]; [EAGLContext setCurrentContext:m_nativeContext];
if (m_needBuffers && !m_hasBuffers) if (m_needBuffers && !m_hasBuffers)
InitBuffers(); InitBuffers();
@@ -51,16 +51,16 @@ void iosOGLContext::Present()
{ {
ASSERT(m_nativeContext != NULL, ()); ASSERT(m_nativeContext != NULL, ());
ASSERT(m_renderBufferId, ()); ASSERT(m_renderBufferId, ());
GLenum const discards[] = { GL_DEPTH_ATTACHMENT, GL_COLOR_ATTACHMENT0 }; GLenum const discards[] = {GL_DEPTH_ATTACHMENT, GL_COLOR_ATTACHMENT0};
if (m_apiVersion == dp::ApiVersion::OpenGLES3) if (m_apiVersion == dp::ApiVersion::OpenGLES3)
GLCHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards)); GLCHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards));
else else
GLCHECK(glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards)); GLCHECK(glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards));
glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferId); glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferId);
if (m_presentAvailable) if (m_presentAvailable)
[m_nativeContext presentRenderbuffer: GL_RENDERBUFFER]; [m_nativeContext presentRenderbuffer:GL_RENDERBUFFER];
if (m_apiVersion == dp::ApiVersion::OpenGLES3) if (m_apiVersion == dp::ApiVersion::OpenGLES3)
GLCHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards + 1)); GLCHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards + 1));
@@ -107,7 +107,7 @@ void iosOGLContext::InitBuffers()
glGenRenderbuffers(1, &m_renderBufferId); glGenRenderbuffers(1, &m_renderBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferId); glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferId);
[m_nativeContext renderbufferStorage:GL_RENDERBUFFER fromDrawable: m_layer]; [m_nativeContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:m_layer];
// color // color
// Depth // Depth
@@ -126,7 +126,7 @@ void iosOGLContext::InitBuffers()
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId); glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderBufferId); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderBufferId);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBufferId); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBufferId);
GLint fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLint fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fbStatus != GL_FRAMEBUFFER_COMPLETE) if (fbStatus != GL_FRAMEBUFFER_COMPLETE)
LOG(LERROR, ("Incomplete framebuffer:", fbStatus)); LOG(LERROR, ("Incomplete framebuffer:", fbStatus));

View File

@@ -2,8 +2,7 @@
size_t constexpr kGLThreadsCount = 2; size_t constexpr kGLThreadsCount = 2;
iosOGLContextFactory::iosOGLContextFactory(CAEAGLLayer * layer, dp::ApiVersion apiVersion, iosOGLContextFactory::iosOGLContextFactory(CAEAGLLayer * layer, dp::ApiVersion apiVersion, bool presentAvailable)
bool presentAvailable)
: m_layer(layer) : m_layer(layer)
, m_apiVersion(apiVersion) , m_apiVersion(apiVersion)
, m_drawContext(nullptr) , m_drawContext(nullptr)
@@ -75,6 +74,6 @@ void iosOGLContextFactory::WaitForInitialization(dp::GraphicsContext * context)
} }
} }
if (static_cast<dp::GraphicsContext*>(m_drawContext) == context) if (static_cast<dp::GraphicsContext *>(m_drawContext) == context)
m_drawContext->SetPresentAvailable(m_presentAvailable); m_drawContext->SetPresentAvailable(m_presentAvailable);
} }

View File

@@ -5,13 +5,16 @@
@implementation DeepLinkRouteStrategyAdapter @implementation DeepLinkRouteStrategyAdapter
- (instancetype)init:(NSURL *)url { - (instancetype)init:(NSURL *)url
{
self = [super init]; self = [super init];
if (self) { if (self)
{
auto const parsedData = GetFramework().GetParsedRoutingData(); auto const parsedData = GetFramework().GetParsedRoutingData();
auto const points = parsedData.m_points; auto const points = parsedData.m_points;
if (points.size() == 2) { if (points.size() == 2)
{
_p1 = [[MWMRoutePoint alloc] initWithURLSchemeRoutePoint:points.front() _p1 = [[MWMRoutePoint alloc] initWithURLSchemeRoutePoint:points.front()
type:MWMRoutePointTypeStart type:MWMRoutePointTypeStart
intermediateIndex:0]; intermediateIndex:0];
@@ -19,7 +22,9 @@
type:MWMRoutePointTypeFinish type:MWMRoutePointTypeFinish
intermediateIndex:0]; intermediateIndex:0];
_type = routerType(parsedData.m_type); _type = routerType(parsedData.m_type);
} else { }
else
{
return nil; return nil;
} }
} }

View File

@@ -2,45 +2,37 @@
#import <CoreApi/AppInfo.h> #import <CoreApi/AppInfo.h>
#import "SwiftBridge.h" #import "SwiftBridge.h"
#include <string>
#include <map> #include <map>
#include <string>
#include "editor/osm_editor.hpp" #include "editor/osm_editor.hpp"
@implementation MWMEditorHelper @implementation MWMEditorHelper
+ (void)uploadEdits:(void (^)(UIBackgroundFetchResult))completionHandler + (void)uploadEdits:(void (^)(UIBackgroundFetchResult))completionHandler
{ {
if (!Profile.isExisting || if (!Profile.isExisting || Platform::EConnectionType::CONNECTION_NONE == Platform::ConnectionStatus())
Platform::EConnectionType::CONNECTION_NONE == Platform::ConnectionStatus())
{ {
completionHandler(UIBackgroundFetchResultFailed); completionHandler(UIBackgroundFetchResultFailed);
} }
else else
{ {
auto const lambda = [completionHandler](osm::Editor::UploadResult result) { auto const lambda = [completionHandler](osm::Editor::UploadResult result)
{
switch (result) switch (result)
{ {
case osm::Editor::UploadResult::Success: case osm::Editor::UploadResult::Success: completionHandler(UIBackgroundFetchResultNewData); break;
completionHandler(UIBackgroundFetchResultNewData); case osm::Editor::UploadResult::Error: completionHandler(UIBackgroundFetchResultFailed); break;
break; case osm::Editor::UploadResult::NothingToUpload: completionHandler(UIBackgroundFetchResultNoData); break;
case osm::Editor::UploadResult::Error:
completionHandler(UIBackgroundFetchResultFailed);
break;
case osm::Editor::UploadResult::NothingToUpload:
completionHandler(UIBackgroundFetchResultNoData);
break;
} }
}; };
NSString *authorizationToken = Profile.authorizationToken; NSString * authorizationToken = Profile.authorizationToken;
if (authorizationToken == nil) { if (authorizationToken == nil)
authorizationToken = @""; authorizationToken = @"";
}
std::string const oauthToken = std::string([authorizationToken UTF8String]); std::string const oauthToken = std::string([authorizationToken UTF8String]);
osm::Editor::Instance().UploadChanges( osm::Editor::Instance().UploadChanges(
oauthToken, oauthToken,
{{"created_by", {{"created_by", std::string("CoMaps " OMIM_OS_NAME " ") + AppInfo.sharedInfo.bundleVersion.UTF8String},
std::string("CoMaps " OMIM_OS_NAME " ") + AppInfo.sharedInfo.bundleVersion.UTF8String},
{"bundle_id", NSBundle.mainBundle.bundleIdentifier.UTF8String}}, {"bundle_id", NSBundle.mainBundle.bundleIdentifier.UTF8String}},
lambda); lambda);
} }

View File

@@ -22,10 +22,8 @@ void loopWrappers(Observers * observers, TLoopBlock block)
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
for (Observer observer in observers) for (Observer observer in observers)
{
if (observer) if (observer)
block(observer); block(observer);
}
}); });
} }
} // namespace } // namespace
@@ -43,9 +41,7 @@ void loopWrappers(Observers * observers, TLoopBlock block)
{ {
static MWMFrameworkListener * listener; static MWMFrameworkListener * listener;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ listener = [[super alloc] initListener]; });
listener = [[super alloc] initListener];
});
return listener; return listener;
} }
@@ -91,19 +87,21 @@ void loopWrappers(Observers * observers, TLoopBlock block)
using namespace storage; using namespace storage;
Observers * observers = self.routeBuildingObservers; Observers * observers = self.routeBuildingObservers;
auto & rm = GetFramework().GetRoutingManager(); auto & rm = GetFramework().GetRoutingManager();
rm.SetRouteBuildingListener( rm.SetRouteBuildingListener([observers](RouterResultCode code, CountriesSet const & absentCountries)
[observers](RouterResultCode code, CountriesSet const & absentCountries) { {
loopWrappers(observers, [code, absentCountries](TRouteBuildingObserver observer) { loopWrappers(observers, [code, absentCountries](TRouteBuildingObserver observer)
[observer processRouteBuilderEvent:code countries:absentCountries]; { [observer processRouteBuilderEvent:code countries:absentCountries]; });
}); });
}); rm.SetRouteProgressListener([observers](float progress)
rm.SetRouteProgressListener([observers](float progress) { {
loopWrappers(observers, [progress](TRouteBuildingObserver observer) { loopWrappers(observers, [progress](TRouteBuildingObserver observer)
{
if ([observer respondsToSelector:@selector(processRouteBuilderProgress:)]) if ([observer respondsToSelector:@selector(processRouteBuilderProgress:)])
[observer processRouteBuilderProgress:progress]; [observer processRouteBuilderProgress:progress];
}); });
}); });
rm.SetRouteRecommendationListener([observers](RoutingManager::Recommendation recommendation) { rm.SetRouteRecommendationListener([observers](RoutingManager::Recommendation recommendation)
{
MWMRouterRecommendation rec; MWMRouterRecommendation rec;
switch (recommendation) switch (recommendation)
{ {
@@ -111,21 +109,25 @@ void loopWrappers(Observers * observers, TLoopBlock block)
rec = MWMRouterRecommendationRebuildAfterPointsLoading; rec = MWMRouterRecommendationRebuildAfterPointsLoading;
break; break;
} }
loopWrappers(observers, [rec](TRouteBuildingObserver observer) { loopWrappers(observers, [rec](TRouteBuildingObserver observer)
{
if ([observer respondsToSelector:@selector(processRouteRecommendation:)]) if ([observer respondsToSelector:@selector(processRouteRecommendation:)])
[observer processRouteRecommendation:rec]; [observer processRouteRecommendation:rec];
}); });
}); });
rm.SetRouteSpeedCamShowListener([observers](m2::PointD const & point, double cameraSpeedKmPH) { rm.SetRouteSpeedCamShowListener([observers](m2::PointD const & point, double cameraSpeedKmPH)
loopWrappers(observers, [cameraSpeedKmPH](TRouteBuildingObserver observer) { {
loopWrappers(observers, [cameraSpeedKmPH](TRouteBuildingObserver observer)
{
if ([observer respondsToSelector:@selector(speedCameraShowedUpOnRoute:)]) if ([observer respondsToSelector:@selector(speedCameraShowedUpOnRoute:)])
[observer speedCameraShowedUpOnRoute:cameraSpeedKmPH]; [observer speedCameraShowedUpOnRoute:cameraSpeedKmPH];
}); });
}); });
rm.SetRouteSpeedCamsClearListener([observers]() { rm.SetRouteSpeedCamsClearListener([observers]()
{
loopWrappers(observers, ^(TRouteBuildingObserver observer) { loopWrappers(observers, ^(TRouteBuildingObserver observer) {
if ([observer respondsToSelector:@selector(speedCameraLeftVisibleArea)]) if ([observer respondsToSelector:@selector(speedCameraLeftVisibleArea)])
[observer speedCameraLeftVisibleArea]; [observer speedCameraLeftVisibleArea];
}); });
}); });
} }
@@ -136,20 +138,18 @@ void loopWrappers(Observers * observers, TLoopBlock block)
{ {
Observers * observers = self.drapeObservers; Observers * observers = self.drapeObservers;
auto & f = GetFramework(); auto & f = GetFramework();
f.SetCurrentCountryChangedListener([observers](CountryId const & countryId) { f.SetCurrentCountryChangedListener([observers](CountryId const & countryId)
{
for (TDrapeObserver observer in observers) for (TDrapeObserver observer in observers)
{
if ([observer respondsToSelector:@selector(processViewportCountryEvent:)]) if ([observer respondsToSelector:@selector(processViewportCountryEvent:)])
[observer processViewportCountryEvent:countryId]; [observer processViewportCountryEvent:countryId];
}
}); });
f.SetViewportListener([observers](ScreenBase const & screen) { f.SetViewportListener([observers](ScreenBase const & screen)
{
for (TDrapeObserver observer in observers) for (TDrapeObserver observer in observers)
{
if ([observer respondsToSelector:@selector(processViewportChangedEvent)]) if ([observer respondsToSelector:@selector(processViewportChangedEvent)])
[observer processViewportChangedEvent]; [observer processViewportChangedEvent];
}
}); });
} }

View File

@@ -1,34 +1,35 @@
#import "MWMRoutingManager.h" #import "MWMRoutingManager.h"
#import "MWMLocationManager.h" #import "MWMCoreRouterType.h"
#import "MWMLocationObserver.h" #import "MWMCoreUnits.h"
#import "MWMFrameworkListener.h" #import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h" #import "MWMFrameworkObservers.h"
#import "MWMCoreRouterType.h" #import "MWMLocationManager.h"
#import "MWMLocationObserver.h"
#import "MWMRoutePoint+CPP.h" #import "MWMRoutePoint+CPP.h"
#import "MWMCoreUnits.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
@interface MWMRoutingManager()<MWMFrameworkRouteBuilderObserver, MWMLocationObserver> @interface MWMRoutingManager () <MWMFrameworkRouteBuilderObserver, MWMLocationObserver>
@property(nonatomic, readonly) RoutingManager & rm; @property(nonatomic, readonly) RoutingManager & rm;
@property(strong, nonatomic) NSHashTable<id<MWMRoutingManagerListener>> *listeners; @property(strong, nonatomic) NSHashTable<id<MWMRoutingManagerListener>> * listeners;
@end @end
@implementation MWMRoutingManager @implementation MWMRoutingManager
+ (MWMRoutingManager *)routingManager { + (MWMRoutingManager *)routingManager
{
static MWMRoutingManager * routingManager; static MWMRoutingManager * routingManager;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ routingManager = [[self alloc] initManager]; });
routingManager = [[self alloc] initManager];
});
return routingManager; return routingManager;
} }
- (instancetype)initManager { - (instancetype)initManager
{
self = [super init]; self = [super init];
if (self) { if (self)
{
self.listeners = [NSHashTable<id<MWMRoutingManagerListener>> weakObjectsHashTable]; self.listeners = [NSHashTable<id<MWMRoutingManagerListener>> weakObjectsHashTable];
[MWMFrameworkListener addObserver:self]; [MWMFrameworkListener addObserver:self];
[MWMLocationManager addObserver:self]; [MWMLocationManager addObserver:self];
@@ -36,15 +37,18 @@
return self; return self;
} }
- (RoutingManager &)rm { - (RoutingManager &)rm
{
return GetFramework().GetRoutingManager(); return GetFramework().GetRoutingManager();
} }
- (routing::SpeedCameraManager &)scm { - (routing::SpeedCameraManager &)scm
{
return self.rm.GetSpeedCamManager(); return self.rm.GetSpeedCamManager();
} }
- (MWMRoutePoint *)startPoint { - (MWMRoutePoint *)startPoint
{
auto const routePoints = self.rm.GetRoutePoints(); auto const routePoints = self.rm.GetRoutePoints();
if (routePoints.empty()) if (routePoints.empty())
return nil; return nil;
@@ -54,7 +58,8 @@
return nil; return nil;
} }
- (MWMRoutePoint *)endPoint { - (MWMRoutePoint *)endPoint
{
auto const routePoints = self.rm.GetRoutePoints(); auto const routePoints = self.rm.GetRoutePoints();
if (routePoints.empty()) if (routePoints.empty())
return nil; return nil;
@@ -64,19 +69,23 @@
return nil; return nil;
} }
- (BOOL)isOnRoute { - (BOOL)isOnRoute
{
return self.rm.IsRoutingFollowing(); return self.rm.IsRoutingFollowing();
} }
- (BOOL)isRoutingActive { - (BOOL)isRoutingActive
{
return self.rm.IsRoutingActive(); return self.rm.IsRoutingActive();
} }
- (BOOL)isRouteFinished { - (BOOL)isRouteFinished
{
return self.rm.IsRouteFinished(); return self.rm.IsRouteFinished();
} }
- (MWMRouteInfo *)routeInfo { - (MWMRouteInfo *)routeInfo
{
if (!self.isRoutingActive) if (!self.isRoutingActive)
return nil; return nil;
routing::FollowingInfo info; routing::FollowingInfo info;
@@ -90,203 +99,216 @@
NSInteger roundExitNumber = 0; NSInteger roundExitNumber = 0;
if (info.m_turn == routing::turns::CarDirection::EnterRoundAbout || if (info.m_turn == routing::turns::CarDirection::EnterRoundAbout ||
info.m_turn == routing::turns::CarDirection::StayOnRoundAbout || info.m_turn == routing::turns::CarDirection::StayOnRoundAbout ||
info.m_turn == routing::turns::CarDirection::LeaveRoundAbout) { info.m_turn == routing::turns::CarDirection::LeaveRoundAbout)
{
roundExitNumber = info.m_exitNum; roundExitNumber = info.m_exitNum;
} }
MWMRouteInfo *objCInfo = [[MWMRouteInfo alloc] initWithTimeToTarget:info.m_time MWMRouteInfo * objCInfo =
targetDistance: info.m_distToTarget.GetDistance() [[MWMRouteInfo alloc] initWithTimeToTarget:info.m_time
targetUnitsIndex:static_cast<UInt8>(info.m_distToTarget.GetUnits()) targetDistance:info.m_distToTarget.GetDistance()
distanceToTurn:info.m_distToTurn.GetDistance() targetUnitsIndex:static_cast<UInt8>(info.m_distToTarget.GetUnits())
turnUnitsIndex:static_cast<UInt8>(info.m_distToTurn.GetUnits()) distanceToTurn:info.m_distToTurn.GetDistance()
streetName:@(info.m_nextStreetName.c_str()) turnUnitsIndex:static_cast<UInt8>(info.m_distToTurn.GetUnits())
turnImageName:[self turnImageName:info.m_turn isPrimary:YES] streetName:@(info.m_nextStreetName.c_str())
nextTurnImageName:[self turnImageName:info.m_nextTurn isPrimary:NO] turnImageName:[self turnImageName:info.m_turn isPrimary:YES]
speedMps:speedMps nextTurnImageName:[self turnImageName:info.m_nextTurn isPrimary:NO]
speedLimitMps:info.m_speedLimitMps speedMps:speedMps
roundExitNumber:roundExitNumber]; speedLimitMps:info.m_speedLimitMps
roundExitNumber:roundExitNumber];
return objCInfo; return objCInfo;
} }
- (MWMRouterType)type { - (MWMRouterType)type
{
return routerType(self.rm.GetRouter()); return routerType(self.rm.GetRouter());
} }
- (void)addListener:(id<MWMRoutingManagerListener>)listener { - (void)addListener:(id<MWMRoutingManagerListener>)listener
{
[self.listeners addObject:listener]; [self.listeners addObject:listener];
} }
- (void)removeListener:(id<MWMRoutingManagerListener>)listener { - (void)removeListener:(id<MWMRoutingManagerListener>)listener
{
[self.listeners removeObject:listener]; [self.listeners removeObject:listener];
} }
- (void)stopRoutingAndRemoveRoutePoints:(BOOL)flag { - (void)stopRoutingAndRemoveRoutePoints:(BOOL)flag
{
self.rm.CloseRouting(flag); self.rm.CloseRouting(flag);
} }
- (void)deleteSavedRoutePoints { - (void)deleteSavedRoutePoints
{
self.rm.DeleteSavedRoutePoints(); self.rm.DeleteSavedRoutePoints();
} }
- (void)applyRouterType:(MWMRouterType)type { - (void)applyRouterType:(MWMRouterType)type
{
self.rm.SetRouter(coreRouterType(type)); self.rm.SetRouter(coreRouterType(type));
} }
- (void)addRoutePoint:(MWMRoutePoint *)point { - (void)addRoutePoint:(MWMRoutePoint *)point
{
RouteMarkData startPt = point.routeMarkData; RouteMarkData startPt = point.routeMarkData;
self.rm.AddRoutePoint(std::move(startPt)); self.rm.AddRoutePoint(std::move(startPt));
} }
- (void)saveRoute { - (void)saveRoute
{
self.rm.SaveRoutePoints(); self.rm.SaveRoutePoints();
} }
- (void)buildRouteWithDidFailError:(NSError * __autoreleasing __nullable *)errorPtr { - (void)buildRouteWithDidFailError:(NSError * __autoreleasing __nullable *)errorPtr
{
auto const & points = self.rm.GetRoutePoints(); auto const & points = self.rm.GetRoutePoints();
auto const pointsCount = points.size(); auto const pointsCount = points.size();
if (pointsCount > 1) { if (pointsCount > 1)
{
self.rm.BuildRoute(); self.rm.BuildRoute();
} else { }
if (errorPtr) { else if (errorPtr)
if (pointsCount == 0) { {
*errorPtr = [NSError errorWithDomain:@"comaps.app.routing" if (pointsCount == 0)
code:MWMRouterResultCodeStartPointNotFound {
userInfo:nil]; *errorPtr = [NSError errorWithDomain:@"comaps.app.routing"
} else { code:MWMRouterResultCodeStartPointNotFound
auto const & routePoint = points.front(); userInfo:nil];
MWMRouterResultCode code; }
if (routePoint.m_pointType == RouteMarkType::Start) { else
code = MWMRouterResultCodeEndPointNotFound; {
} else { auto const & routePoint = points.front();
code = MWMRouterResultCodeStartPointNotFound; MWMRouterResultCode code;
} if (routePoint.m_pointType == RouteMarkType::Start)
*errorPtr = [NSError errorWithDomain:@"comaps.app.routing" code = MWMRouterResultCodeEndPointNotFound;
code:code else
userInfo:nil]; code = MWMRouterResultCodeStartPointNotFound;
} *errorPtr = [NSError errorWithDomain:@"comaps.app.routing" code:code userInfo:nil];
} }
} }
} }
- (void)startRoute { - (void)startRoute
{
[self saveRoute]; [self saveRoute];
self.rm.FollowRoute(); self.rm.FollowRoute();
} }
- (MWMSpeedCameraManagerMode)speedCameraMode { - (MWMSpeedCameraManagerMode)speedCameraMode
{
auto const mode = self.scm.GetMode(); auto const mode = self.scm.GetMode();
switch (mode) { switch (mode)
case routing::SpeedCameraManagerMode::Auto: {
return MWMSpeedCameraManagerModeAuto; case routing::SpeedCameraManagerMode::Auto: return MWMSpeedCameraManagerModeAuto;
case routing::SpeedCameraManagerMode::Always: case routing::SpeedCameraManagerMode::Always: return MWMSpeedCameraManagerModeAlways;
return MWMSpeedCameraManagerModeAlways; default: return MWMSpeedCameraManagerModeNever;
default:
return MWMSpeedCameraManagerModeNever;
} }
} }
- (void)setSpeedCameraMode:(MWMSpeedCameraManagerMode)mode { - (void)setSpeedCameraMode:(MWMSpeedCameraManagerMode)mode
switch (mode) { {
case MWMSpeedCameraManagerModeAuto: switch (mode)
self.scm.SetMode(routing::SpeedCameraManagerMode::Auto); {
break; case MWMSpeedCameraManagerModeAuto: self.scm.SetMode(routing::SpeedCameraManagerMode::Auto); break;
case MWMSpeedCameraManagerModeAlways: case MWMSpeedCameraManagerModeAlways: self.scm.SetMode(routing::SpeedCameraManagerMode::Always); break;
self.scm.SetMode(routing::SpeedCameraManagerMode::Always); default: self.scm.SetMode(routing::SpeedCameraManagerMode::Never);
break;
default:
self.scm.SetMode(routing::SpeedCameraManagerMode::Never);
} }
} }
- (void)setOnNewTurnCallback:(MWMVoidBlock)callback { - (void)setOnNewTurnCallback:(MWMVoidBlock)callback
self.rm.RoutingSession().SetOnNewTurnCallback([callback] { {
callback(); self.rm.RoutingSession().SetOnNewTurnCallback([callback] { callback(); });
});
} }
- (void)resetOnNewTurnCallback { - (void)resetOnNewTurnCallback
{
self.rm.RoutingSession().SetOnNewTurnCallback(nullptr); self.rm.RoutingSession().SetOnNewTurnCallback(nullptr);
} }
#pragma mark - MWMFrameworkRouteBuilderObserver implementation #pragma mark - MWMFrameworkRouteBuilderObserver implementation
- (void)processRouteBuilderEvent:(routing::RouterResultCode)code - (void)processRouteBuilderEvent:(routing::RouterResultCode)code
countries:(const storage::CountriesSet &)absentCountries { countries:(const storage::CountriesSet &)absentCountries
{
NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects; NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects;
MWMRouterResultCode objCCode = MWMRouterResultCode(code); MWMRouterResultCode objCCode = MWMRouterResultCode(code);
NSMutableArray<NSString *> *objCAbsentCountries = [NSMutableArray new]; NSMutableArray<NSString *> * objCAbsentCountries = [NSMutableArray new];
std::for_each(absentCountries.begin(), absentCountries.end(), ^(std::string const & str) { std::for_each(absentCountries.begin(), absentCountries.end(), ^(std::string const & str) {
id nsstr = [NSString stringWithUTF8String:str.c_str()]; id nsstr = [NSString stringWithUTF8String:str.c_str()];
[objCAbsentCountries addObject:nsstr]; [objCAbsentCountries addObject:nsstr];
}); });
for (id<MWMRoutingManagerListener> object in objects) { for (id<MWMRoutingManagerListener> object in objects)
[object processRouteBuilderEventWithCode:objCCode [object processRouteBuilderEventWithCode:objCCode countries:objCAbsentCountries];
countries:objCAbsentCountries];
}
} }
- (void)speedCameraShowedUpOnRoute:(double)speedLimit { - (void)speedCameraShowedUpOnRoute:(double)speedLimit
{
NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects; NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects;
for (id<MWMRoutingManagerListener> object in objects) { for (id<MWMRoutingManagerListener> object in objects)
if (speedLimit == routing::SpeedCameraOnRoute::kNoSpeedInfo) { {
if (speedLimit == routing::SpeedCameraOnRoute::kNoSpeedInfo)
{
[object updateCameraInfo:YES speedLimitMps:-1]; [object updateCameraInfo:YES speedLimitMps:-1];
} else { }
else
{
auto const metersPerSecond = measurement_utils::KmphToMps(speedLimit); auto const metersPerSecond = measurement_utils::KmphToMps(speedLimit);
[object updateCameraInfo:YES speedLimitMps:metersPerSecond]; [object updateCameraInfo:YES speedLimitMps:metersPerSecond];
} }
} }
} }
- (void)speedCameraLeftVisibleArea { - (void)speedCameraLeftVisibleArea
{
NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects; NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects;
for (id<MWMRoutingManagerListener> object in objects) { for (id<MWMRoutingManagerListener> object in objects)
[object updateCameraInfo:NO speedLimitMps:-1]; [object updateCameraInfo:NO speedLimitMps:-1];
}
} }
#pragma mark - MWMLocationObserver implementation #pragma mark - MWMLocationObserver implementation
- (void)onLocationUpdate:(CLLocation *)location { - (void)onLocationUpdate:(CLLocation *)location
{
NSMutableArray<NSString *> * turnNotifications = [NSMutableArray array]; NSMutableArray<NSString *> * turnNotifications = [NSMutableArray array];
std::vector<std::string> notifications; std::vector<std::string> notifications;
auto announceStreets = [NSUserDefaults.standardUserDefaults boolForKey:@"UserDefaultsNeedToEnableStreetNamesTTS"]; auto announceStreets = [NSUserDefaults.standardUserDefaults boolForKey:@"UserDefaultsNeedToEnableStreetNamesTTS"];
self.rm.GenerateNotifications(notifications, announceStreets); self.rm.GenerateNotifications(notifications, announceStreets);
for (auto const & text : notifications) { for (auto const & text : notifications)
[turnNotifications addObject:@(text.c_str())]; [turnNotifications addObject:@(text.c_str())];
}
NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects; NSArray<id<MWMRoutingManagerListener>> * objects = self.listeners.allObjects;
for (id<MWMRoutingManagerListener> object in objects) { for (id<MWMRoutingManagerListener> object in objects)
[object didLocationUpdate:turnNotifications]; [object didLocationUpdate:turnNotifications];
}
} }
- (NSString *)turnImageName:(routing::turns::CarDirection)turn isPrimary:(BOOL)isPrimary { - (NSString *)turnImageName:(routing::turns::CarDirection)turn isPrimary:(BOOL)isPrimary
{
using namespace routing::turns; using namespace routing::turns;
NSString *imageName = nil; NSString * imageName = nil;
switch (turn) { switch (turn)
case CarDirection::ExitHighwayToRight: imageName = @"ic_cp_exit_highway_to_right"; break; {
case CarDirection::TurnSlightRight: imageName = @"ic_cp_slight_right"; break; case CarDirection::ExitHighwayToRight: imageName = @"ic_cp_exit_highway_to_right"; break;
case CarDirection::TurnRight: imageName = @"ic_cp_simple_right"; break; case CarDirection::TurnSlightRight: imageName = @"ic_cp_slight_right"; break;
case CarDirection::TurnSharpRight: imageName = @"ic_cp_sharp_right"; break; case CarDirection::TurnRight: imageName = @"ic_cp_simple_right"; break;
case CarDirection::ExitHighwayToLeft: imageName = @"ic_cp_exit_highway_to_left"; break; case CarDirection::TurnSharpRight: imageName = @"ic_cp_sharp_right"; break;
case CarDirection::TurnSlightLeft: imageName = @"ic_cp_slight_left"; break; case CarDirection::ExitHighwayToLeft: imageName = @"ic_cp_exit_highway_to_left"; break;
case CarDirection::TurnLeft: imageName = @"ic_cp_simple_left"; break; case CarDirection::TurnSlightLeft: imageName = @"ic_cp_slight_left"; break;
case CarDirection::TurnSharpLeft: imageName = @"ic_cp_sharp_left"; break; case CarDirection::TurnLeft: imageName = @"ic_cp_simple_left"; break;
case CarDirection::UTurnLeft: imageName = @"ic_cp_uturn_left"; break; case CarDirection::TurnSharpLeft: imageName = @"ic_cp_sharp_left"; break;
case CarDirection::UTurnRight: imageName = @"ic_cp_uturn_right"; break; case CarDirection::UTurnLeft: imageName = @"ic_cp_uturn_left"; break;
case CarDirection::ReachedYourDestination: imageName = @"ic_cp_finish_point"; break; case CarDirection::UTurnRight: imageName = @"ic_cp_uturn_right"; break;
case CarDirection::LeaveRoundAbout: case CarDirection::ReachedYourDestination: imageName = @"ic_cp_finish_point"; break;
case CarDirection::EnterRoundAbout: imageName = @"ic_cp_round"; break; case CarDirection::LeaveRoundAbout:
case CarDirection::GoStraight: imageName = @"ic_cp_straight"; break; case CarDirection::EnterRoundAbout: imageName = @"ic_cp_round"; break;
case CarDirection::StartAtEndOfStreet: case CarDirection::GoStraight: imageName = @"ic_cp_straight"; break;
case CarDirection::StayOnRoundAbout: case CarDirection::StartAtEndOfStreet:
case CarDirection::Count: case CarDirection::StayOnRoundAbout:
case CarDirection::None: imageName = isPrimary ? @"ic_cp_straight" : nil; break; case CarDirection::Count:
case CarDirection::None: imageName = isPrimary ? @"ic_cp_straight" : nil; break;
} }
if (!isPrimary && imageName != nil) { if (!isPrimary && imageName != nil)
imageName = [NSString stringWithFormat:@"%@_then", imageName]; imageName = [NSString stringWithFormat:@"%@_then", imageName];
}
return imageName; return imageName;
} }

View File

@@ -30,49 +30,57 @@ enum class GeoMode
BicycleRouting BicycleRouting
}; };
std::string DebugPrint(GeoMode geoMode) { std::string DebugPrint(GeoMode geoMode)
{
using enum GeoMode; using enum GeoMode;
switch (geoMode) { switch (geoMode)
case Pending: return "Pending"; {
case InPosition: return "InPosition"; case Pending: return "Pending";
case NotInPosition: return "NotInPosition"; case InPosition: return "InPosition";
case FollowAndRotate: return "FollowAndRotate"; case NotInPosition: return "NotInPosition";
case VehicleRouting: return "VehicleRouting"; case FollowAndRotate: return "FollowAndRotate";
case PedestrianRouting: return "PedestrianRouting"; case VehicleRouting: return "VehicleRouting";
case BicycleRouting: return "BicycleRouting"; case PedestrianRouting: return "PedestrianRouting";
case BicycleRouting: return "BicycleRouting";
} }
CHECK(false, ("Unsupported value", static_cast<int>(geoMode))); CHECK(false, ("Unsupported value", static_cast<int>(geoMode)));
} }
std::string DebugPrint(MWMMyPositionMode mode) { std::string DebugPrint(MWMMyPositionMode mode)
switch (mode) { {
case MWMMyPositionModePendingPosition: return "MWMMyPositionModePendingPosition"; switch (mode)
case MWMMyPositionModeNotFollowNoPosition: return "MWMMyPositionModeNotFollowNoPosition"; {
case MWMMyPositionModeNotFollow: return "MWMMyPositionModeNotFollow"; case MWMMyPositionModePendingPosition: return "MWMMyPositionModePendingPosition";
case MWMMyPositionModeFollow: return "MWMMyPositionModeFollow"; case MWMMyPositionModeNotFollowNoPosition: return "MWMMyPositionModeNotFollowNoPosition";
case MWMMyPositionModeFollowAndRotate: return "MWMMyPositionModeFollowAndRotate"; case MWMMyPositionModeNotFollow: return "MWMMyPositionModeNotFollow";
case MWMMyPositionModeFollow: return "MWMMyPositionModeFollow";
case MWMMyPositionModeFollowAndRotate: return "MWMMyPositionModeFollowAndRotate";
} }
CHECK(false, ("Unsupported value", static_cast<int>(mode))); CHECK(false, ("Unsupported value", static_cast<int>(mode)));
} }
std::string DebugPrint(MWMLocationStatus status) { std::string DebugPrint(MWMLocationStatus status)
switch (status) { {
case MWMLocationStatusNoError: return "MWMLocationStatusNoError"; switch (status)
case MWMLocationStatusNotSupported: return "MWMLocationStatusNotSupported"; {
case MWMLocationStatusDenied: return "MWMLocationStatusDenied"; case MWMLocationStatusNoError: return "MWMLocationStatusNoError";
case MWMLocationStatusGPSIsOff: return "MWMLocationStatusGPSIsOff"; case MWMLocationStatusNotSupported: return "MWMLocationStatusNotSupported";
case MWMLocationStatusTimeout: return "MWMLocationStatusTimeout"; case MWMLocationStatusDenied: return "MWMLocationStatusDenied";
case MWMLocationStatusGPSIsOff: return "MWMLocationStatusGPSIsOff";
case MWMLocationStatusTimeout: return "MWMLocationStatusTimeout";
} }
CHECK(false, ("Unsupported value", static_cast<int>(status))); CHECK(false, ("Unsupported value", static_cast<int>(status)));
} }
std::string DebugPrint(CLAuthorizationStatus status) { std::string DebugPrint(CLAuthorizationStatus status)
switch (status) { {
case kCLAuthorizationStatusNotDetermined: return "kCLAuthorizationStatusNotDetermined"; switch (status)
case kCLAuthorizationStatusRestricted: return "kCLAuthorizationStatusRestricted"; {
case kCLAuthorizationStatusDenied: return "kCLAuthorizationStatusDenied"; case kCLAuthorizationStatusNotDetermined: return "kCLAuthorizationStatusNotDetermined";
case kCLAuthorizationStatusAuthorizedAlways: return "kCLAuthorizationStatusAuthorizedAlways"; case kCLAuthorizationStatusRestricted: return "kCLAuthorizationStatusRestricted";
case kCLAuthorizationStatusAuthorizedWhenInUse: return "kCLAuthorizationStatusAuthorizedWhenInUse"; case kCLAuthorizationStatusDenied: return "kCLAuthorizationStatusDenied";
case kCLAuthorizationStatusAuthorizedAlways: return "kCLAuthorizationStatusAuthorizedAlways";
case kCLAuthorizationStatusAuthorizedWhenInUse: return "kCLAuthorizationStatusAuthorizedWhenInUse";
} }
CHECK(false, ("Unsupported value", static_cast<int>(status))); CHECK(false, ("Unsupported value", static_cast<int>(status)));
} }
@@ -92,32 +100,25 @@ struct GeoModeSettings
std::map<GeoMode, GeoModeSettings> const kGeoSettings{ std::map<GeoMode, GeoModeSettings> const kGeoSettings{
{GeoMode::Pending, {GeoMode::Pending,
{.distanceFilter = kCLDistanceFilterNone, {.distanceFilter = kCLDistanceFilterNone,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBestForNavigation}}},
.battery = kCLLocationAccuracyBestForNavigation}}},
{GeoMode::InPosition, {GeoMode::InPosition,
{.distanceFilter = 2, {.distanceFilter = 2,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}},
.battery = kCLLocationAccuracyBest}}},
{GeoMode::NotInPosition, {GeoMode::NotInPosition,
{.distanceFilter = 5, {.distanceFilter = 5,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}},
.battery = kCLLocationAccuracyBest}}},
{GeoMode::FollowAndRotate, {GeoMode::FollowAndRotate,
{.distanceFilter = 2, {.distanceFilter = 2,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}},
.battery = kCLLocationAccuracyBest}}},
{GeoMode::VehicleRouting, {GeoMode::VehicleRouting,
{.distanceFilter = kCLDistanceFilterNone, {.distanceFilter = kCLDistanceFilterNone,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}},
.battery = kCLLocationAccuracyBest}}},
{GeoMode::PedestrianRouting, {GeoMode::PedestrianRouting,
{.distanceFilter = 2, {.distanceFilter = 2,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}},
.battery = kCLLocationAccuracyBest}}},
{GeoMode::BicycleRouting, {GeoMode::BicycleRouting,
{.distanceFilter = 2, {.distanceFilter = 2,
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .accuracy = {.charging = kCLLocationAccuracyBestForNavigation, .battery = kCLLocationAccuracyBest}}}};
.battery = kCLLocationAccuracyBest}}}};
BOOL keepRunningInBackground() BOOL keepRunningInBackground()
{ {
@@ -135,20 +136,22 @@ BOOL keepRunningInBackground()
NSString * const kLocationPermissionRequestedKey = @"kLocationPermissionRequestedKey"; NSString * const kLocationPermissionRequestedKey = @"kLocationPermissionRequestedKey";
NSString * const kLocationAlertNeedShowKey = @"kLocationAlertNeedShowKey"; NSString * const kLocationAlertNeedShowKey = @"kLocationAlertNeedShowKey";
BOOL needShowLocationAlert() { BOOL needShowLocationAlert()
{
NSUserDefaults * ud = NSUserDefaults.standardUserDefaults; NSUserDefaults * ud = NSUserDefaults.standardUserDefaults;
if ([ud objectForKey:kLocationAlertNeedShowKey] == nil) if ([ud objectForKey:kLocationAlertNeedShowKey] == nil)
return YES; return YES;
return [ud boolForKey:kLocationAlertNeedShowKey]; return [ud boolForKey:kLocationAlertNeedShowKey];
} }
void setShowLocationAlert(BOOL needShow) { void setShowLocationAlert(BOOL needShow)
{
NSUserDefaults * ud = NSUserDefaults.standardUserDefaults; NSUserDefaults * ud = NSUserDefaults.standardUserDefaults;
[ud setBool:needShow forKey:kLocationAlertNeedShowKey]; [ud setBool:needShow forKey:kLocationAlertNeedShowKey];
} }
} // namespace } // namespace
@interface MWMLocationManager ()<CLLocationManagerDelegate> @interface MWMLocationManager () <CLLocationManagerDelegate>
@property(nonatomic) BOOL started; @property(nonatomic) BOOL started;
@property(nonatomic) CLLocationManager * locationManager; @property(nonatomic) CLLocationManager * locationManager;
@@ -170,9 +173,7 @@ void setShowLocationAlert(BOOL needShow) {
{ {
static MWMLocationManager * manager; static MWMLocationManager * manager;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ manager = [[self alloc] initManager]; });
manager = [[self alloc] initManager];
});
return manager; return manager;
} }
@@ -180,9 +181,7 @@ void setShowLocationAlert(BOOL needShow) {
{ {
self = [super init]; self = [super init];
if (self) if (self)
{
_observers = [Observers weakObjectsHashTable]; _observers = [Observers weakObjectsHashTable];
}
return self; return self;
} }
@@ -192,11 +191,20 @@ void setShowLocationAlert(BOOL needShow) {
self.locationManager.delegate = nil; self.locationManager.delegate = nil;
} }
+ (void)start { [self manager].started = YES; } + (void)start
{
[self manager].started = YES;
}
+ (void)stop { [self manager].started = NO; } + (void)stop
{
[self manager].started = NO;
}
+ (BOOL)isStarted { return [self manager].started; } + (BOOL)isStarted
{
return [self manager].started;
}
#pragma mark - Add/Remove Observers #pragma mark - Add/Remove Observers
@@ -211,9 +219,7 @@ void setShowLocationAlert(BOOL needShow) {
+ (void)removeObserver:(Observer)observer + (void)removeObserver:(Observer)observer
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [[self manager].observers removeObject:observer]; });
[[self manager].observers removeObject:observer];
});
} }
#pragma mark - App Life Cycle #pragma mark - App Life Cycle
@@ -238,8 +244,7 @@ void setShowLocationAlert(BOOL needShow) {
+ (CLLocation *)lastLocation + (CLLocation *)lastLocation
{ {
MWMLocationManager * manager = [self manager]; MWMLocationManager * manager = [self manager];
if (!manager.started || !manager.lastLocationInfo || if (!manager.started || !manager.lastLocationInfo || manager.lastLocationInfo.horizontalAccuracy < 0 ||
manager.lastLocationInfo.horizontalAccuracy < 0 ||
manager.lastLocationStatus != MWMLocationStatusNoError) manager.lastLocationStatus != MWMLocationStatusNoError)
return nil; return nil;
return manager.lastLocationInfo; return manager.lastLocationInfo;
@@ -248,8 +253,7 @@ void setShowLocationAlert(BOOL needShow) {
+ (BOOL)isLocationProhibited + (BOOL)isLocationProhibited
{ {
auto const status = [self manager].lastLocationStatus; auto const status = [self manager].lastLocationStatus;
return status == MWMLocationStatusDenied || return status == MWMLocationStatusDenied || status == MWMLocationStatusGPSIsOff;
status == MWMLocationStatusGPSIsOff;
} }
+ (CLHeading *)lastHeading + (CLHeading *)lastHeading
@@ -269,10 +273,8 @@ void setShowLocationAlert(BOOL needShow) {
if (self.lastLocationStatus != MWMLocationStatusNoError) if (self.lastLocationStatus != MWMLocationStatusNoError)
GetFramework().OnLocationError((location::TLocationError)self.lastLocationStatus); GetFramework().OnLocationError((location::TLocationError)self.lastLocationStatus);
for (Observer observer in self.observers) for (Observer observer in self.observers)
{
if ([observer respondsToSelector:@selector(onLocationError:)]) if ([observer respondsToSelector:@selector(onLocationError:)])
[observer onLocationError:self.lastLocationStatus]; [observer onLocationError:self.lastLocationStatus];
}
} }
- (void)processHeadingUpdate:(CLHeading *)headingInfo - (void)processHeadingUpdate:(CLHeading *)headingInfo
@@ -280,10 +282,8 @@ void setShowLocationAlert(BOOL needShow) {
self.lastHeadingInfo = headingInfo; self.lastHeadingInfo = headingInfo;
GetFramework().OnCompassUpdate(location_util::compassInfoFromHeading(headingInfo)); GetFramework().OnCompassUpdate(location_util::compassInfoFromHeading(headingInfo));
for (Observer observer in self.observers) for (Observer observer in self.observers)
{
if ([observer respondsToSelector:@selector(onHeadingUpdate:)]) if ([observer respondsToSelector:@selector(onHeadingUpdate:)])
[observer onHeadingUpdate:headingInfo]; [observer onHeadingUpdate:headingInfo];
}
} }
- (void)processLocationUpdate:(CLLocation *)locationInfo - (void)processLocationUpdate:(CLLocation *)locationInfo
@@ -304,10 +304,8 @@ void setShowLocationAlert(BOOL needShow) {
self.lastLocationInfo = locationInfo; self.lastLocationInfo = locationInfo;
self.locationSource = source; self.locationSource = source;
for (Observer observer in self.observers) for (Observer observer in self.observers)
{
if ([observer respondsToSelector:@selector(onLocationUpdate:)]) if ([observer respondsToSelector:@selector(onLocationUpdate:)])
[observer onLocationUpdate:locationInfo]; [observer onLocationUpdate:locationInfo];
}
} }
#pragma mark - Location Status #pragma mark - Location Status
@@ -317,26 +315,25 @@ void setShowLocationAlert(BOOL needShow) {
_lastLocationStatus = lastLocationStatus; _lastLocationStatus = lastLocationStatus;
switch (lastLocationStatus) switch (lastLocationStatus)
{ {
case MWMLocationStatusNoError: case MWMLocationStatusNoError: break;
break;
case MWMLocationStatusNotSupported: case MWMLocationStatusNotSupported:
[[MWMAlertViewController activeAlertController] presentLocationServiceNotSupportedAlert]; [[MWMAlertViewController activeAlertController] presentLocationServiceNotSupportedAlert];
break; break;
case MWMLocationStatusDenied: case MWMLocationStatusDenied:
if (needShowLocationAlert()) { if (needShowLocationAlert())
[[MWMAlertViewController activeAlertController] presentLocationAlertWithCancelBlock:^{ {
setShowLocationAlert(NO); [[MWMAlertViewController activeAlertController]
}]; presentLocationAlertWithCancelBlock:^{ setShowLocationAlert(NO); }];
} }
break; break;
case MWMLocationStatusGPSIsOff: case MWMLocationStatusGPSIsOff:
if (needShowLocationAlert()) { if (needShowLocationAlert())
{
[[MWMAlertViewController activeAlertController] presentLocationServicesDisabledAlert]; [[MWMAlertViewController activeAlertController] presentLocationServicesDisabledAlert];
setShowLocationAlert(NO); setShowLocationAlert(NO);
} }
break; break;
case MWMLocationStatusTimeout: case MWMLocationStatusTimeout: CHECK(false, ("MWMLocationStatusTimeout is only used in Qt/Desktop builds"));
CHECK(false, ("MWMLocationStatusTimeout is only used in Qt/Desktop builds"));
} }
} }
@@ -419,16 +416,10 @@ void setShowLocationAlert(BOOL needShow) {
case GeoMode::Pending: case GeoMode::Pending:
case GeoMode::InPosition: case GeoMode::InPosition:
case GeoMode::NotInPosition: case GeoMode::NotInPosition:
case GeoMode::FollowAndRotate: case GeoMode::FollowAndRotate: locationManager.activityType = CLActivityTypeOther; break;
locationManager.activityType = CLActivityTypeOther; case GeoMode::VehicleRouting: locationManager.activityType = CLActivityTypeAutomotiveNavigation; break;
break;
case GeoMode::VehicleRouting:
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
break;
case GeoMode::PedestrianRouting: case GeoMode::PedestrianRouting:
case GeoMode::BicycleRouting: case GeoMode::BicycleRouting: locationManager.activityType = CLActivityTypeOtherNavigation; break;
locationManager.activityType = CLActivityTypeOtherNavigation;
break;
} }
[MWMLocationManager refreshGeoModeSettingsFor:self.locationManager geoMode:self.geoMode]; [MWMLocationManager refreshGeoModeSettingsFor:self.locationManager geoMode:self.geoMode];
@@ -437,14 +428,12 @@ void setShowLocationAlert(BOOL needShow) {
+ (void)refreshGeoModeSettingsFor:(CLLocationManager *)locationManager geoMode:(GeoMode)geoMode + (void)refreshGeoModeSettingsFor:(CLLocationManager *)locationManager geoMode:(GeoMode)geoMode
{ {
UIDeviceBatteryState const state = UIDevice.currentDevice.batteryState; UIDeviceBatteryState const state = UIDevice.currentDevice.batteryState;
BOOL const isCharging = BOOL const isCharging = (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
(state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
GeoModeSettings const settings = kGeoSettings.at(geoMode); GeoModeSettings const settings = kGeoSettings.at(geoMode);
locationManager.desiredAccuracy = locationManager.desiredAccuracy = isCharging ? settings.accuracy.charging : settings.accuracy.battery;
isCharging ? settings.accuracy.charging : settings.accuracy.battery;
locationManager.distanceFilter = settings.distanceFilter; locationManager.distanceFilter = settings.distanceFilter;
LOG(LINFO, ("Refreshed GeoMode settings: accuracy", locationManager.desiredAccuracy, LOG(LINFO, ("Refreshed GeoMode settings: accuracy", locationManager.desiredAccuracy, "distance filter",
"distance filter", locationManager.distanceFilter, "charging", isCharging)); locationManager.distanceFilter, "charging", isCharging));
} }
- (CLLocationManager *)locationManager - (CLLocationManager *)locationManager
@@ -467,8 +456,7 @@ void setShowLocationAlert(BOOL needShow) {
[self processHeadingUpdate:heading]; [self processHeadingUpdate:heading];
} }
- (void)locationManager:(CLLocationManager *)manager - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
didUpdateLocations:(NSArray<CLLocation *> *)locations
{ {
CLLocation * location = locations.lastObject; CLLocation * location = locations.lastObject;
// According to documentation, lat and lon are valid only if horizontalAccuracy is non-negative. // According to documentation, lat and lon are valid only if horizontalAccuracy is non-negative.
@@ -507,26 +495,24 @@ void setShowLocationAlert(BOOL needShow) {
[self processLocationStatus:MWMLocationStatusDenied]; [self processLocationStatus:MWMLocationStatusDenied];
} }
// Delegate's method didChangeAuthorizationStatus is used to handle the authorization status when the application finishes launching // Delegate's method didChangeAuthorizationStatus is used to handle the authorization status when the application
// or user changes location access in the application settings. // finishes launching or user changes location access in the application settings.
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager - (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager
{ {
LOG(LWARNING, ("CLLocationManagerDelegate: Authorization status has changed to", DebugPrint(manager.authorizationStatus))); LOG(LWARNING,
switch (manager.authorizationStatus) { ("CLLocationManagerDelegate: Authorization status has changed to", DebugPrint(manager.authorizationStatus)));
case kCLAuthorizationStatusAuthorizedWhenInUse: switch (manager.authorizationStatus)
case kCLAuthorizationStatusAuthorizedAlways: {
[self startUpdatingLocationFor:manager]; case kCLAuthorizationStatusAuthorizedWhenInUse:
break; case kCLAuthorizationStatusAuthorizedAlways: [self startUpdatingLocationFor:manager]; break;
case kCLAuthorizationStatusNotDetermined: case kCLAuthorizationStatusNotDetermined: [manager requestWhenInUseAuthorization]; break;
[manager requestWhenInUseAuthorization]; case kCLAuthorizationStatusRestricted:
break; case kCLAuthorizationStatusDenied:
case kCLAuthorizationStatusRestricted: if ([CLLocationManager locationServicesEnabled])
case kCLAuthorizationStatusDenied: [self processLocationStatus:MWMLocationStatusDenied];
if ([CLLocationManager locationServicesEnabled]) else
[self processLocationStatus:MWMLocationStatusDenied]; [self processLocationStatus:MWMLocationStatusGPSIsOff];
else break;
[self processLocationStatus:MWMLocationStatusGPSIsOff];
break;
} }
} }
@@ -547,9 +533,11 @@ void setShowLocationAlert(BOOL needShow) {
if (_started == started) if (_started == started)
return; return;
NSNotificationCenter * notificationCenter = NSNotificationCenter.defaultCenter; NSNotificationCenter * notificationCenter = NSNotificationCenter.defaultCenter;
if (started) { if (started)
{
_started = [self start]; _started = [self start];
if (_started) { if (_started)
{
[notificationCenter addObserver:self [notificationCenter addObserver:self
selector:@selector(orientationChanged) selector:@selector(orientationChanged)
name:UIDeviceOrientationDidChangeNotification name:UIDeviceOrientationDidChangeNotification
@@ -559,7 +547,9 @@ void setShowLocationAlert(BOOL needShow) {
name:UIDeviceBatteryStateDidChangeNotification name:UIDeviceBatteryStateDidChangeNotification
object:nil]; object:nil];
} }
} else { }
else
{
_started = NO; _started = NO;
[self stop]; [self stop];
[notificationCenter removeObserver:self]; [notificationCenter removeObserver:self];
@@ -581,18 +571,17 @@ void setShowLocationAlert(BOOL needShow) {
CLLocationManager * locationManager = self.locationManager; CLLocationManager * locationManager = self.locationManager;
switch (locationManager.authorizationStatus) switch (locationManager.authorizationStatus)
{ {
case kCLAuthorizationStatusAuthorizedWhenInUse: case kCLAuthorizationStatusAuthorizedWhenInUse:
case kCLAuthorizationStatusAuthorizedAlways: case kCLAuthorizationStatusAuthorizedAlways:
[self startUpdatingLocationFor:locationManager]; [self startUpdatingLocationFor:locationManager];
return YES; return YES;
break; break;
case kCLAuthorizationStatusNotDetermined: case kCLAuthorizationStatusNotDetermined:
[locationManager requestWhenInUseAuthorization]; [locationManager requestWhenInUseAuthorization];
return YES; return YES;
break; break;
case kCLAuthorizationStatusRestricted: case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied: case kCLAuthorizationStatusDenied: break;
break;
} }
} }
return NO; return NO;
@@ -609,7 +598,8 @@ void setShowLocationAlert(BOOL needShow) {
#pragma mark - Location alert #pragma mark - Location alert
+ (void)enableLocationAlert { + (void)enableLocationAlert
{
setShowLocationAlert(YES); setShowLocationAlert(YES);
} }

View File

@@ -12,9 +12,9 @@ NSUInteger constexpr kMaxPredictionCount = 20;
@property(copy, nonatomic) CLLocation * lastLocation; @property(copy, nonatomic) CLLocation * lastLocation;
@property(nonatomic) BOOL isLastLocationValid; @property(nonatomic) BOOL isLastLocationValid;
@property (nonatomic) BOOL isLastPositionModeValid; @property(nonatomic) BOOL isLastPositionModeValid;
@property (nonatomic) NSUInteger predictionsCount; @property(nonatomic) NSUInteger predictionsCount;
@property (copy, nonatomic) TPredictionBlock onPredictionBlock; @property(copy, nonatomic) TPredictionBlock onPredictionBlock;
@end @end
@@ -45,8 +45,7 @@ NSUInteger constexpr kMaxPredictionCount = 20;
- (BOOL)isActive - (BOOL)isActive
{ {
return self.isLastLocationValid && self.isLastPositionModeValid && return self.isLastLocationValid && self.isLastPositionModeValid && self.predictionsCount < kMaxPredictionCount;
self.predictionsCount < kMaxPredictionCount;
} }
- (void)restart - (void)restart

View File

@@ -15,8 +15,7 @@
@implementation MWMRoutePoint @implementation MWMRoutePoint
- (instancetype)initWithLastLocationAndType:(MWMRoutePointType)type - (instancetype)initWithLastLocationAndType:(MWMRoutePointType)type intermediateIndex:(size_t)intermediateIndex
intermediateIndex:(size_t)intermediateIndex
{ {
auto lastLocation = [MWMLocationManager lastLocation]; auto lastLocation = [MWMLocationManager lastLocation];
if (!lastLocation) if (!lastLocation)
@@ -85,14 +84,10 @@
intermediateIndex:(size_t)intermediateIndex intermediateIndex:(size_t)intermediateIndex
{ {
auto const pointD = m2::PointD(point.x, point.y); auto const pointD = m2::PointD(point.x, point.y);
self = [self initWithPoint:pointD self = [self initWithPoint:pointD title:title subtitle:subtitle type:type intermediateIndex:intermediateIndex];
title:title
subtitle:subtitle
type:type intermediateIndex:intermediateIndex];
return self; return self;
} }
- (instancetype)initWithPoint:(m2::PointD const &)point - (instancetype)initWithPoint:(m2::PointD const &)point
title:(NSString *)title title:(NSString *)title
subtitle:(NSString *)subtitle subtitle:(NSString *)subtitle
@@ -120,8 +115,14 @@
NSAssert(_intermediateIndex >= 0 && _intermediateIndex <= 100, @"Invalid intermediateIndex"); NSAssert(_intermediateIndex >= 0 && _intermediateIndex <= 100, @"Invalid intermediateIndex");
} }
- (double)latitude { return mercator::YToLat(self.point.y); } - (double)latitude
- (double)longitude { return mercator::XToLon(self.point.x); } {
return mercator::YToLat(self.point.y);
}
- (double)longitude
{
return mercator::XToLon(self.point.x);
}
- (NSString *)latLonString - (NSString *)latLonString
{ {
@@ -159,9 +160,8 @@
return [NSString stringWithFormat:@"<%@: %p> Position: [%@, %@] | IsMyPosition: %@ | Type: %@ | " return [NSString stringWithFormat:@"<%@: %p> Position: [%@, %@] | IsMyPosition: %@ | Type: %@ | "
@"IntermediateIndex: %@ | Title: %@ | Subtitle: %@", @"IntermediateIndex: %@ | Title: %@ | Subtitle: %@",
[self class], self, @(_point.x), @(_point.y), [self class], self, @(_point.x), @(_point.y), _isMyPosition ? @"true" : @"false",
_isMyPosition ? @"true" : @"false", type, @(_intermediateIndex), type, @(_intermediateIndex), _title, _subtitle];
_title, _subtitle];
} }
@end @end

View File

@@ -15,8 +15,7 @@
+ (void)openRouteManagerTransaction + (void)openRouteManagerTransaction
{ {
auto router = [MWMRouter router]; auto router = [MWMRouter router];
router.routeManagerTransactionId = router.routeManagerTransactionId = GetFramework().GetRoutingManager().OpenRoutePointsTransaction();
GetFramework().GetRoutingManager().OpenRoutePointsTransaction();
} }
+ (void)applyRouteManagerTransaction + (void)applyRouteManagerTransaction

View File

@@ -15,79 +15,87 @@
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
#include "platform/distance.hpp"
#include "platform/local_country_file_utils.hpp" #include "platform/local_country_file_utils.hpp"
#include "platform/localization.hpp" #include "platform/localization.hpp"
#include "platform/distance.hpp"
using namespace routing; using namespace routing;
@interface MWMRouter () <MWMLocationObserver, MWMFrameworkRouteBuilderObserver> @interface MWMRouter () <MWMLocationObserver, MWMFrameworkRouteBuilderObserver>
@property(nonatomic) NSMutableDictionary<NSValue *, NSData *> *altitudeImagesData; @property(nonatomic) NSMutableDictionary<NSValue *, NSData *> * altitudeImagesData;
@property(nonatomic) NSString *totalAscent; @property(nonatomic) NSString * totalAscent;
@property(nonatomic) NSString *totalDescent; @property(nonatomic) NSString * totalDescent;
@property(nonatomic) dispatch_queue_t renderAltitudeImagesQueue; @property(nonatomic) dispatch_queue_t renderAltitudeImagesQueue;
@property(nonatomic) uint32_t routeManagerTransactionId; @property(nonatomic) uint32_t routeManagerTransactionId;
@property(nonatomic) BOOL canAutoAddLastLocation; @property(nonatomic) BOOL canAutoAddLastLocation;
@property(nonatomic) BOOL isAPICall; @property(nonatomic) BOOL isAPICall;
@property(nonatomic) BOOL isRestoreProcessCompleted; @property(nonatomic) BOOL isRestoreProcessCompleted;
@property(strong, nonatomic) MWMRoutingOptions *routingOptions; @property(strong, nonatomic) MWMRoutingOptions * routingOptions;
+ (MWMRouter *)router; + (MWMRouter *)router;
@end @end
namespace { namespace
char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeImagesQueue"; {
char const * kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeImagesQueue";
} // namespace } // namespace
@implementation MWMRouter @implementation MWMRouter
+ (MWMRouter *)router { + (MWMRouter *)router
static MWMRouter *router; {
static MWMRouter * router;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ router = [[self alloc] initRouter]; });
router = [[self alloc] initRouter];
});
return router; return router;
} }
+ (BOOL)hasRouteAltitude { + (BOOL)hasRouteAltitude
switch ([self type]) { {
case MWMRouterTypeVehicle: switch ([self type])
case MWMRouterTypePublicTransport: {
case MWMRouterTypeRuler: case MWMRouterTypeVehicle:
return NO; case MWMRouterTypePublicTransport:
case MWMRouterTypePedestrian: case MWMRouterTypeRuler: return NO;
case MWMRouterTypeBicycle: case MWMRouterTypePedestrian:
return GetFramework().GetRoutingManager().HasRouteAltitude(); case MWMRouterTypeBicycle: return GetFramework().GetRoutingManager().HasRouteAltitude();
} }
} }
+ (void)startRouting { + (void)startRouting
{
[self start]; [self start];
} }
+ (void)stopRouting { + (void)stopRouting
{
[self stop:YES]; [self stop:YES];
} }
+ (BOOL)isRoutingActive { + (BOOL)isRoutingActive
{
return GetFramework().GetRoutingManager().IsRoutingActive(); return GetFramework().GetRoutingManager().IsRoutingActive();
} }
+ (BOOL)isRouteBuilt { + (BOOL)isRouteBuilt
{
return GetFramework().GetRoutingManager().IsRouteBuilt(); return GetFramework().GetRoutingManager().IsRouteBuilt();
} }
+ (BOOL)isRouteFinished { + (BOOL)isRouteFinished
{
return GetFramework().GetRoutingManager().IsRouteFinished(); return GetFramework().GetRoutingManager().IsRouteFinished();
} }
+ (BOOL)isRouteRebuildingOnly { + (BOOL)isRouteRebuildingOnly
{
return GetFramework().GetRoutingManager().IsRouteRebuildingOnly(); return GetFramework().GetRoutingManager().IsRouteRebuildingOnly();
} }
+ (BOOL)isOnRoute { + (BOOL)isOnRoute
{
return GetFramework().GetRoutingManager().IsRoutingFollowing(); return GetFramework().GetRoutingManager().IsRoutingFollowing();
} }
+ (BOOL)IsRouteValid { + (BOOL)IsRouteValid
{
return GetFramework().GetRoutingManager().IsRouteValid(); return GetFramework().GetRoutingManager().IsRouteValid();
} }
@@ -96,48 +104,56 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
return GetFramework().GetRoutingManager().IsSpeedCamLimitExceeded(); return GetFramework().GetRoutingManager().IsSpeedCamLimitExceeded();
} }
+ (NSArray<MWMRoutePoint *> *)points { + (NSArray<MWMRoutePoint *> *)points
NSMutableArray<MWMRoutePoint *> *points = [@[] mutableCopy]; {
NSMutableArray<MWMRoutePoint *> * points = [@[] mutableCopy];
auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints(); auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints();
for (auto const &routePoint : routePoints) for (auto const & routePoint : routePoints)
[points addObject:[[MWMRoutePoint alloc] initWithRouteMarkData:routePoint]]; [points addObject:[[MWMRoutePoint alloc] initWithRouteMarkData:routePoint]];
return [points copy]; return [points copy];
} }
+ (NSInteger)pointsCount { + (NSInteger)pointsCount
{
return GetFramework().GetRoutingManager().GetRoutePointsCount(); return GetFramework().GetRoutingManager().GetRoutePointsCount();
} }
+ (MWMRoutePoint *)startPoint { + (MWMRoutePoint *)startPoint
{
auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints(); auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints();
if (routePoints.empty()) if (routePoints.empty())
return nil; return nil;
auto const &routePoint = routePoints.front(); auto const & routePoint = routePoints.front();
if (routePoint.m_pointType == RouteMarkType::Start) if (routePoint.m_pointType == RouteMarkType::Start)
return [[MWMRoutePoint alloc] initWithRouteMarkData:routePoint]; return [[MWMRoutePoint alloc] initWithRouteMarkData:routePoint];
return nil; return nil;
} }
+ (MWMRoutePoint *)finishPoint { + (MWMRoutePoint *)finishPoint
{
auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints(); auto const routePoints = GetFramework().GetRoutingManager().GetRoutePoints();
if (routePoints.empty()) if (routePoints.empty())
return nil; return nil;
auto const &routePoint = routePoints.back(); auto const & routePoint = routePoints.back();
if (routePoint.m_pointType == RouteMarkType::Finish) if (routePoint.m_pointType == RouteMarkType::Finish)
return [[MWMRoutePoint alloc] initWithRouteMarkData:routePoint]; return [[MWMRoutePoint alloc] initWithRouteMarkData:routePoint];
return nil; return nil;
} }
+ (void)enableAutoAddLastLocation:(BOOL)enable { + (void)enableAutoAddLastLocation:(BOOL)enable
{
[MWMRouter router].canAutoAddLastLocation = enable; [MWMRouter router].canAutoAddLastLocation = enable;
} }
+ (BOOL)canAddIntermediatePoint { + (BOOL)canAddIntermediatePoint
{
return GetFramework().GetRoutingManager().CouldAddIntermediatePoint(); return GetFramework().GetRoutingManager().CouldAddIntermediatePoint();
} }
- (instancetype)initRouter { - (instancetype)initRouter
{
self = [super init]; self = [super init];
if (self) { if (self)
{
self.altitudeImagesData = [@{} mutableCopy]; self.altitudeImagesData = [@{} mutableCopy];
self.renderAltitudeImagesQueue = dispatch_queue_create(kRenderAltitudeImagesQueueLabel, DISPATCH_QUEUE_SERIAL); self.renderAltitudeImagesQueue = dispatch_queue_create(kRenderAltitudeImagesQueueLabel, DISPATCH_QUEUE_SERIAL);
self.routeManagerTransactionId = RoutingManager::InvalidRoutePointsTransactionId(); self.routeManagerTransactionId = RoutingManager::InvalidRoutePointsTransactionId();
@@ -150,17 +166,20 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
return self; return self;
} }
+ (void)subscribeToEvents { + (void)subscribeToEvents
{
[MWMFrameworkListener addObserver:[MWMRouter router]]; [MWMFrameworkListener addObserver:[MWMRouter router]];
[MWMLocationManager addObserver:[MWMRouter router]]; [MWMLocationManager addObserver:[MWMRouter router]];
} }
+ (void)unsubscribeFromEvents { + (void)unsubscribeFromEvents
{
[MWMFrameworkListener removeObserver:[MWMRouter router]]; [MWMFrameworkListener removeObserver:[MWMRouter router]];
[MWMLocationManager removeObserver:[MWMRouter router]]; [MWMLocationManager removeObserver:[MWMRouter router]];
} }
+ (void)setType:(MWMRouterType)type { + (void)setType:(MWMRouterType)type
{
if (type == self.type) if (type == self.type)
return; return;
@@ -168,53 +187,64 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
GetFramework().GetRoutingManager().SetRouter(coreRouterType(type)); GetFramework().GetRoutingManager().SetRouter(coreRouterType(type));
} }
+ (MWMRouterType)type { + (MWMRouterType)type
{
return routerType(GetFramework().GetRoutingManager().GetRouter()); return routerType(GetFramework().GetRoutingManager().GetRouter());
} }
+ (void)disableFollowMode { + (void)disableFollowMode
{
GetFramework().GetRoutingManager().DisableFollowMode(); GetFramework().GetRoutingManager().DisableFollowMode();
} }
+ (void)enableTurnNotifications:(BOOL)active { + (void)enableTurnNotifications:(BOOL)active
{
GetFramework().GetRoutingManager().EnableTurnNotifications(active); GetFramework().GetRoutingManager().EnableTurnNotifications(active);
} }
+ (BOOL)areTurnNotificationsEnabled { + (BOOL)areTurnNotificationsEnabled
{
return GetFramework().GetRoutingManager().AreTurnNotificationsEnabled(); return GetFramework().GetRoutingManager().AreTurnNotificationsEnabled();
} }
+ (void)setTurnNotificationsLocale:(NSString *)locale { + (void)setTurnNotificationsLocale:(NSString *)locale
{
GetFramework().GetRoutingManager().SetTurnNotificationsLocale(locale.UTF8String); GetFramework().GetRoutingManager().SetTurnNotificationsLocale(locale.UTF8String);
} }
+ (NSArray<NSString *> *)turnNotifications { + (NSArray<NSString *> *)turnNotifications
NSMutableArray<NSString *> *turnNotifications = [@[] mutableCopy]; {
NSMutableArray<NSString *> * turnNotifications = [@[] mutableCopy];
std::vector<std::string> notifications; std::vector<std::string> notifications;
auto announceStreets = [NSUserDefaults.standardUserDefaults boolForKey:@"UserDefaultsNeedToEnableStreetNamesTTS"]; auto announceStreets = [NSUserDefaults.standardUserDefaults boolForKey:@"UserDefaultsNeedToEnableStreetNamesTTS"];
GetFramework().GetRoutingManager().GenerateNotifications(notifications, announceStreets); GetFramework().GetRoutingManager().GenerateNotifications(notifications, announceStreets);
for (auto const &text : notifications) for (auto const & text : notifications)
[turnNotifications addObject:@(text.c_str())]; [turnNotifications addObject:@(text.c_str())];
return [turnNotifications copy]; return [turnNotifications copy];
} }
+ (void)removePoint:(MWMRoutePoint *)point { + (void)removePoint:(MWMRoutePoint *)point
{
RouteMarkData pt = point.routeMarkData; RouteMarkData pt = point.routeMarkData;
GetFramework().GetRoutingManager().RemoveRoutePoint(pt.m_pointType, pt.m_intermediateIndex); GetFramework().GetRoutingManager().RemoveRoutePoint(pt.m_pointType, pt.m_intermediateIndex);
[[MWMNavigationDashboardManager sharedManager] onRoutePointsUpdated]; [[MWMNavigationDashboardManager sharedManager] onRoutePointsUpdated];
} }
+ (void)removePointAndRebuild:(MWMRoutePoint *)point { + (void)removePointAndRebuild:(MWMRoutePoint *)point
{
if (!point) if (!point)
return; return;
[self removePoint:point]; [self removePoint:point];
[self rebuildWithBestRouter:NO]; [self rebuildWithBestRouter:NO];
} }
+ (void)removePoints { + (void)removePoints
{
GetFramework().GetRoutingManager().RemoveRoutePoints(); GetFramework().GetRoutingManager().RemoveRoutePoints();
} }
+ (void)addPoint:(MWMRoutePoint *)point { + (void)addPoint:(MWMRoutePoint *)point
if (!point) { {
if (!point)
{
NSAssert(NO, @"Point can not be nil"); NSAssert(NO, @"Point can not be nil");
return; return;
} }
@@ -224,34 +254,37 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
[[MWMNavigationDashboardManager sharedManager] onRoutePointsUpdated]; [[MWMNavigationDashboardManager sharedManager] onRoutePointsUpdated];
} }
+ (void)addPointAndRebuild:(MWMRoutePoint *)point { + (void)addPointAndRebuild:(MWMRoutePoint *)point
{
if (!point) if (!point)
return; return;
[self addPoint:point]; [self addPoint:point];
[self rebuildWithBestRouter:NO]; [self rebuildWithBestRouter:NO];
} }
+ (void)buildFromPoint:(MWMRoutePoint *)startPoint bestRouter:(BOOL)bestRouter { + (void)buildFromPoint:(MWMRoutePoint *)startPoint bestRouter:(BOOL)bestRouter
{
if (!startPoint) if (!startPoint)
return; return;
[self addPoint:startPoint]; [self addPoint:startPoint];
[self rebuildWithBestRouter:bestRouter]; [self rebuildWithBestRouter:bestRouter];
} }
+ (void)buildToPoint:(MWMRoutePoint *)finishPoint bestRouter:(BOOL)bestRouter { + (void)buildToPoint:(MWMRoutePoint *)finishPoint bestRouter:(BOOL)bestRouter
{
if (!finishPoint) if (!finishPoint)
return; return;
[self addPoint:finishPoint]; [self addPoint:finishPoint];
if (![self startPoint] && [MWMLocationManager lastLocation] && [MWMRouter router].canAutoAddLastLocation) { if (![self startPoint] && [MWMLocationManager lastLocation] && [MWMRouter router].canAutoAddLastLocation)
[self addPoint:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart intermediateIndex:0]]; [self addPoint:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart intermediateIndex:0]];
}
if ([self startPoint] && [self finishPoint]) if ([self startPoint] && [self finishPoint])
[self rebuildWithBestRouter:bestRouter]; [self rebuildWithBestRouter:bestRouter];
} }
+ (void)buildApiRouteWithType:(MWMRouterType)type + (void)buildApiRouteWithType:(MWMRouterType)type
startPoint:(MWMRoutePoint *)startPoint startPoint:(MWMRoutePoint *)startPoint
finishPoint:(MWMRoutePoint *)finishPoint { finishPoint:(MWMRoutePoint *)finishPoint
{
if (!startPoint || !finishPoint) if (!startPoint || !finishPoint)
return; return;
@@ -266,13 +299,15 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
[self rebuildWithBestRouter:NO]; [self rebuildWithBestRouter:NO];
} }
+ (void)rebuildWithBestRouter:(BOOL)bestRouter { + (void)rebuildWithBestRouter:(BOOL)bestRouter
{
[self clearAltitudeImagesData]; [self clearAltitudeImagesData];
auto &rm = GetFramework().GetRoutingManager(); auto & rm = GetFramework().GetRoutingManager();
auto const &points = rm.GetRoutePoints(); auto const & points = rm.GetRoutePoints();
auto const pointsCount = points.size(); auto const pointsCount = points.size();
if (pointsCount < 2) { if (pointsCount < 2)
{
[self doStop:NO]; [self doStop:NO];
[[MWMMapViewControlsManager manager] onRoutePrepare]; [[MWMMapViewControlsManager manager] onRoutePrepare];
return; return;
@@ -284,17 +319,18 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
rm.BuildRoute(); rm.BuildRoute();
} }
+ (void)start { + (void)start
{
[self saveRoute]; [self saveRoute];
auto const doStart = ^{ auto const doStart = ^{
auto &rm = GetFramework().GetRoutingManager(); auto & rm = GetFramework().GetRoutingManager();
auto const routePoints = rm.GetRoutePoints(); auto const routePoints = rm.GetRoutePoints();
if (routePoints.size() >= 2) if (routePoints.size() >= 2)
{ {
auto p1 = [[MWMRoutePoint alloc] initWithRouteMarkData:routePoints.front()]; auto p1 = [[MWMRoutePoint alloc] initWithRouteMarkData:routePoints.front()];
auto p2 = [[MWMRoutePoint alloc] initWithRouteMarkData:routePoints.back()]; auto p2 = [[MWMRoutePoint alloc] initWithRouteMarkData:routePoints.back()];
CLLocation *lastLocation = [MWMLocationManager lastLocation]; CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (p1.isMyPosition && lastLocation) if (p1.isMyPosition && lastLocation)
{ {
rm.FollowRoute(); rm.FollowRoute();
@@ -306,19 +342,22 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
BOOL const needToRebuild = lastLocation && [MWMLocationManager isStarted] && !p2.isMyPosition; BOOL const needToRebuild = lastLocation && [MWMLocationManager isStarted] && !p2.isMyPosition;
[[MWMAlertViewController activeAlertController] [[MWMAlertViewController activeAlertController]
presentPoint2PointAlertWithOkBlock:^{ presentPoint2PointAlertWithOkBlock:^{
[self buildFromPoint:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart [self buildFromPoint:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart
intermediateIndex:0] intermediateIndex:0]
bestRouter:NO]; bestRouter:NO];
} }
needToRebuild:needToRebuild]; needToRebuild:needToRebuild];
} }
} }
}; };
if ([MWMSettings routingDisclaimerApproved]) { if ([MWMSettings routingDisclaimerApproved])
{
doStart(); doStart();
} else { }
else
{
[[MWMAlertViewController activeAlertController] presentRoutingDisclaimerAlertWithOkBlock:^{ [[MWMAlertViewController activeAlertController] presentRoutingDisclaimerAlertWithOkBlock:^{
doStart(); doStart();
[MWMSettings setRoutingDisclaimerApproved]; [MWMSettings setRoutingDisclaimerApproved];
@@ -326,13 +365,15 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
} }
} }
+ (void)stop:(BOOL)removeRoutePoints { + (void)stop:(BOOL)removeRoutePoints
{
[self doStop:removeRoutePoints]; [self doStop:removeRoutePoints];
[self hideNavigationMapControls]; [self hideNavigationMapControls];
[MWMRouter router].canAutoAddLastLocation = YES; [MWMRouter router].canAutoAddLastLocation = YES;
} }
+ (void)doStop:(BOOL)removeRoutePoints { + (void)doStop:(BOOL)removeRoutePoints
{
[self clearAltitudeImagesData]; [self clearAltitudeImagesData];
GetFramework().GetRoutingManager().CloseRouting(removeRoutePoints); GetFramework().GetRoutingManager().CloseRouting(removeRoutePoints);
if (removeRoutePoints) if (removeRoutePoints)
@@ -340,14 +381,15 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
[MWMThemeManager setAutoUpdates:NO]; [MWMThemeManager setAutoUpdates:NO];
} }
- (void)updateFollowingInfo { - (void)updateFollowingInfo
{
if (![MWMRouter isRoutingActive]) if (![MWMRouter isRoutingActive])
return; return;
auto const &rm = GetFramework().GetRoutingManager(); auto const & rm = GetFramework().GetRoutingManager();
routing::FollowingInfo info; routing::FollowingInfo info;
rm.GetRouteFollowingInfo(info); rm.GetRouteFollowingInfo(info);
if (!info.IsValid()) if (!info.IsValid())
return; return;
auto navManager = [MWMNavigationDashboardManager sharedManager]; auto navManager = [MWMNavigationDashboardManager sharedManager];
if ([MWMRouter type] == MWMRouterTypePublicTransport) if ([MWMRouter type] == MWMRouterTypePublicTransport)
[navManager updateTransitInfo:rm.GetTransitRouteInfo()]; [navManager updateTransitInfo:rm.GetTransitRouteInfo()];
@@ -355,7 +397,8 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
[navManager updateFollowingInfo:info routePoints:[MWMRouter points] type:[MWMRouter type]]; [navManager updateFollowingInfo:info routePoints:[MWMRouter points] type:[MWMRouter type]];
} }
+ (void)routeAltitudeImageForSize:(CGSize)size completion:(MWMImageHeightBlock)block { + (void)routeAltitudeImageForSize:(CGSize)size completion:(MWMImageHeightBlock)block
{
if (![self hasRouteAltitude]) if (![self hasRouteAltitude])
return; return;
@@ -364,7 +407,8 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
return; return;
// |altitudes| should not be used in the method after line below. // |altitudes| should not be used in the method after line below.
dispatch_async(self.router.renderAltitudeImagesQueue, [=]() { dispatch_async(self.router.renderAltitudeImagesQueue, [=]()
{
auto router = self.router; auto router = self.router;
CGFloat const screenScale = [UIScreen mainScreen].scale; CGFloat const screenScale = [UIScreen mainScreen].scale;
CGSize const scaledSize = {size.width * screenScale, size.height * screenScale}; CGSize const scaledSize = {size.width * screenScale, size.height * screenScale};
@@ -375,8 +419,8 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
if (width == 0 || height == 0) if (width == 0 || height == 0)
return; return;
NSValue *sizeValue = [NSValue valueWithCGSize:scaledSize]; NSValue * sizeValue = [NSValue valueWithCGSize:scaledSize];
NSData *imageData = router.altitudeImagesData[sizeValue]; NSData * imageData = router.altitudeImagesData[sizeValue];
if (!imageData) if (!imageData)
{ {
altitudes->Simplify(); altitudes->Simplify();
@@ -398,14 +442,15 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIImage *altitudeImage = [UIImage imageWithRGBAData:imageData width:width height:height]; UIImage * altitudeImage = [UIImage imageWithRGBAData:imageData width:width height:height];
if (altitudeImage) if (altitudeImage)
block(altitudeImage, router.totalAscent, router.totalDescent); block(altitudeImage, router.totalAscent, router.totalDescent);
}); });
}); });
} }
+ (void)clearAltitudeImagesData { + (void)clearAltitudeImagesData
{
auto router = self.router; auto router = self.router;
dispatch_async(router.renderAltitudeImagesQueue, ^{ dispatch_async(router.renderAltitudeImagesQueue, ^{
[router.altitudeImagesData removeAllObjects]; [router.altitudeImagesData removeAllObjects];
@@ -416,12 +461,14 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
#pragma mark - MWMLocationObserver #pragma mark - MWMLocationObserver
- (void)onLocationUpdate:(CLLocation *)location { - (void)onLocationUpdate:(CLLocation *)location
{
if (![MWMRouter isRoutingActive]) if (![MWMRouter isRoutingActive])
return; return;
auto tts = [MWMTextToSpeech tts]; auto tts = [MWMTextToSpeech tts];
NSArray<NSString *> *turnNotifications = [MWMRouter turnNotifications]; NSArray<NSString *> * turnNotifications = [MWMRouter turnNotifications];
if ([MWMRouter isOnRoute] && tts.active) { if ([MWMRouter isOnRoute] && tts.active)
{
[tts playTurnNotifications:turnNotifications]; [tts playTurnNotifications:turnNotifications];
[tts playWarningSound]; [tts playWarningSound];
} }
@@ -431,179 +478,183 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm
#pragma mark - MWMFrameworkRouteBuilderObserver #pragma mark - MWMFrameworkRouteBuilderObserver
- (void)onRouteReady:(BOOL)hasWarnings { - (void)onRouteReady:(BOOL)hasWarnings
{
self.routingOptions = [MWMRoutingOptions new]; self.routingOptions = [MWMRoutingOptions new];
GetFramework().DeactivateMapSelection(); GetFramework().DeactivateMapSelection();
auto startPoint = [MWMRouter startPoint]; auto startPoint = [MWMRouter startPoint];
if (!startPoint || !startPoint.isMyPosition) { if (!startPoint || !startPoint.isMyPosition)
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [MWMRouter disableFollowMode]; });
[MWMRouter disableFollowMode];
});
}
[[MWMMapViewControlsManager manager] onRouteReady:hasWarnings]; [[MWMMapViewControlsManager manager] onRouteReady:hasWarnings];
[self updateFollowingInfo]; [self updateFollowingInfo];
} }
- (void)processRouteBuilderEvent:(routing::RouterResultCode)code - (void)processRouteBuilderEvent:(routing::RouterResultCode)code
countries:(storage::CountriesSet const &)absentCountries { countries:(storage::CountriesSet const &)absentCountries
MWMMapViewControlsManager *mapViewControlsManager = [MWMMapViewControlsManager manager]; {
switch (code) { MWMMapViewControlsManager * mapViewControlsManager = [MWMMapViewControlsManager manager];
case routing::RouterResultCode::NoError: switch (code)
[self onRouteReady:NO]; {
break; case routing::RouterResultCode::NoError: [self onRouteReady:NO]; break;
case routing::RouterResultCode::HasWarnings: case routing::RouterResultCode::HasWarnings: [self onRouteReady:YES]; break;
[self onRouteReady:YES]; case routing::RouterResultCode::RouteFileNotExist:
break; case routing::RouterResultCode::InconsistentMWMandRoute:
case routing::RouterResultCode::RouteFileNotExist: case routing::RouterResultCode::NeedMoreMaps:
case routing::RouterResultCode::InconsistentMWMandRoute: case routing::RouterResultCode::FileTooOld:
case routing::RouterResultCode::NeedMoreMaps: case routing::RouterResultCode::RouteNotFound:
case routing::RouterResultCode::FileTooOld: self.routingOptions = [MWMRoutingOptions new];
case routing::RouterResultCode::RouteNotFound: [self presentDownloaderAlert:code countries:absentCountries];
self.routingOptions = [MWMRoutingOptions new]; [[MWMNavigationDashboardManager sharedManager] onRouteError:L(@"routing_planning_error")];
[self presentDownloaderAlert:code countries:absentCountries]; break;
[[MWMNavigationDashboardManager sharedManager] onRouteError:L(@"routing_planning_error")]; case routing::RouterResultCode::Cancelled: [mapViewControlsManager onRoutePrepare]; break;
break; case routing::RouterResultCode::StartPointNotFound:
case routing::RouterResultCode::Cancelled: case routing::RouterResultCode::EndPointNotFound:
[mapViewControlsManager onRoutePrepare]; case routing::RouterResultCode::NoCurrentPosition:
break; case routing::RouterResultCode::PointsInDifferentMWM:
case routing::RouterResultCode::StartPointNotFound: case routing::RouterResultCode::InternalError:
case routing::RouterResultCode::EndPointNotFound: case routing::RouterResultCode::IntermediatePointNotFound:
case routing::RouterResultCode::NoCurrentPosition: case routing::RouterResultCode::TransitRouteNotFoundNoNetwork:
case routing::RouterResultCode::PointsInDifferentMWM: case routing::RouterResultCode::TransitRouteNotFoundTooLongPedestrian:
case routing::RouterResultCode::InternalError: case routing::RouterResultCode::RouteNotFoundRedressRouteError:
case routing::RouterResultCode::IntermediatePointNotFound: [[MWMAlertViewController activeAlertController] presentAlert:code];
case routing::RouterResultCode::TransitRouteNotFoundNoNetwork: [[MWMNavigationDashboardManager sharedManager] onRouteError:L(@"routing_planning_error")];
case routing::RouterResultCode::TransitRouteNotFoundTooLongPedestrian: break;
case routing::RouterResultCode::RouteNotFoundRedressRouteError:
[[MWMAlertViewController activeAlertController] presentAlert:code];
[[MWMNavigationDashboardManager sharedManager] onRouteError:L(@"routing_planning_error")];
break;
} }
} }
- (void)processRouteBuilderProgress:(CGFloat)progress { - (void)processRouteBuilderProgress:(CGFloat)progress
{
[[MWMNavigationDashboardManager sharedManager] setRouteBuilderProgress:progress]; [[MWMNavigationDashboardManager sharedManager] setRouteBuilderProgress:progress];
} }
- (void)processRouteRecommendation:(MWMRouterRecommendation)recommendation { - (void)processRouteRecommendation:(MWMRouterRecommendation)recommendation
switch (recommendation) { {
case MWMRouterRecommendationRebuildAfterPointsLoading: switch (recommendation)
[MWMRouter addPointAndRebuild:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart {
intermediateIndex:0]]; case MWMRouterRecommendationRebuildAfterPointsLoading:
break; [MWMRouter addPointAndRebuild:[[MWMRoutePoint alloc] initWithLastLocationAndType:MWMRoutePointTypeStart
intermediateIndex:0]];
break;
} }
} }
#pragma mark - Alerts #pragma mark - Alerts
- (void)presentDownloaderAlert:(routing::RouterResultCode)code countries:(storage::CountriesSet const &)countries { - (void)presentDownloaderAlert:(routing::RouterResultCode)code countries:(storage::CountriesSet const &)countries
MWMAlertViewController *activeAlertController = [MWMAlertViewController activeAlertController]; {
if (!countries.empty()) { MWMAlertViewController * activeAlertController = [MWMAlertViewController activeAlertController];
if (!countries.empty())
{
[activeAlertController presentDownloaderAlertWithCountries:countries [activeAlertController presentDownloaderAlertWithCountries:countries
code:code code:code
cancelBlock:^{ cancelBlock:^{
if (code != routing::RouterResultCode::NeedMoreMaps) if (code != routing::RouterResultCode::NeedMoreMaps)
[MWMRouter stopRouting]; [MWMRouter stopRouting];
}
downloadBlock:^(storage::CountriesVec const &downloadCountries, MWMVoidBlock onSuccess) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:downloadCountries.size()];
for (auto const &cid : downloadCountries) {
[array addObject:@(cid.c_str())];
} }
[[MWMStorage sharedStorage] downloadNodes:array onSuccess:onSuccess]; downloadBlock:^(storage::CountriesVec const & downloadCountries, MWMVoidBlock onSuccess) {
} NSMutableArray * array = [NSMutableArray arrayWithCapacity:downloadCountries.size()];
downloadCompleteBlock:^{ for (auto const & cid : downloadCountries)
[MWMRouter rebuildWithBestRouter:NO]; [array addObject:@(cid.c_str())];
}]; [[MWMStorage sharedStorage] downloadNodes:array onSuccess:onSuccess];
} else if ([MWMRouter hasActiveDrivingOptions]) { }
[activeAlertController presentDefaultAlertWithTitle:L(@"unable_to_calc_alert_title") downloadCompleteBlock:^{ [MWMRouter rebuildWithBestRouter:NO]; }];
message:L(@"unable_to_calc_alert_subtitle") }
rightButtonTitle:L(@"settings") else if ([MWMRouter hasActiveDrivingOptions])
leftButtonTitle:L(@"cancel") {
rightButtonAction:^{ [activeAlertController
[[MapViewController sharedController] openDrivingOptions]; presentDefaultAlertWithTitle:L(@"unable_to_calc_alert_title")
}]; message:L(@"unable_to_calc_alert_subtitle")
} else { rightButtonTitle:L(@"settings")
leftButtonTitle:L(@"cancel")
rightButtonAction:^{ [[MapViewController sharedController] openDrivingOptions]; }];
}
else
{
[activeAlertController presentAlert:code]; [activeAlertController presentAlert:code];
} }
} }
#pragma mark - Save / Load route points #pragma mark - Save / Load route points
+ (void)saveRoute { + (void)saveRoute
{
GetFramework().GetRoutingManager().SaveRoutePoints(); GetFramework().GetRoutingManager().SaveRoutePoints();
} }
+ (void)saveRouteIfNeeded { + (void)saveRouteIfNeeded
{
if ([self isOnRoute]) if ([self isOnRoute])
[self saveRoute]; [self saveRoute];
} }
+ (void)restoreRouteIfNeeded { + (void)restoreRouteIfNeeded
if ([MapsAppDelegate theApp].isDrapeEngineCreated) { {
auto &rm = GetFramework().GetRoutingManager(); if ([MapsAppDelegate theApp].isDrapeEngineCreated)
if ([self isRoutingActive] || ![self hasSavedRoute]) { {
auto & rm = GetFramework().GetRoutingManager();
if ([self isRoutingActive] || ![self hasSavedRoute])
{
self.router.isRestoreProcessCompleted = YES; self.router.isRestoreProcessCompleted = YES;
return; return;
} }
rm.LoadRoutePoints([self](bool success) { rm.LoadRoutePoints([self](bool success)
{
if (success) if (success)
[self rebuildWithBestRouter:YES]; [self rebuildWithBestRouter:YES];
self.router.isRestoreProcessCompleted = YES; self.router.isRestoreProcessCompleted = YES;
}); });
} else { }
dispatch_async(dispatch_get_main_queue(), ^{ else
[self restoreRouteIfNeeded]; {
}); dispatch_async(dispatch_get_main_queue(), ^{ [self restoreRouteIfNeeded]; });
} }
} }
+ (BOOL)isRestoreProcessCompleted { + (BOOL)isRestoreProcessCompleted
{
return self.router.isRestoreProcessCompleted; return self.router.isRestoreProcessCompleted;
} }
+ (BOOL)hasSavedRoute { + (BOOL)hasSavedRoute
{
return GetFramework().GetRoutingManager().HasSavedRoutePoints(); return GetFramework().GetRoutingManager().HasSavedRoutePoints();
} }
+ (void)updateRoute { + (void)updateRoute
MWMRoutingOptions *newOptions = [MWMRoutingOptions new]; {
if ((self.isRoutingActive && !self.isOnRoute) && ![newOptions isEqual:[self router].routingOptions]) { MWMRoutingOptions * newOptions = [MWMRoutingOptions new];
if ((self.isRoutingActive && !self.isOnRoute) && ![newOptions isEqual:[self router].routingOptions])
[self rebuildWithBestRouter:YES]; [self rebuildWithBestRouter:YES];
}
} }
+ (BOOL)hasActiveDrivingOptions { + (BOOL)hasActiveDrivingOptions
{
return [MWMRoutingOptions new].hasOptions && self.type != MWMRouterTypeRuler; return [MWMRoutingOptions new].hasOptions && self.type != MWMRouterTypeRuler;
} }
+ (void)avoidRoadTypeAndRebuild:(MWMRoadType)type { + (void)avoidRoadTypeAndRebuild:(MWMRoadType)type
MWMRoutingOptions *options = [MWMRoutingOptions new]; {
switch (type) { MWMRoutingOptions * options = [MWMRoutingOptions new];
case MWMRoadTypeToll: switch (type)
options.avoidToll = YES; {
break; case MWMRoadTypeToll: options.avoidToll = YES; break;
case MWMRoadTypeDirty: case MWMRoadTypeDirty: options.avoidDirty = YES; break;
options.avoidDirty = YES; case MWMRoadTypeFerry: options.avoidFerry = YES; break;
break; case MWMRoadTypeMotorway: options.avoidMotorway = YES; break;
case MWMRoadTypeFerry:
options.avoidFerry = YES;
break;
case MWMRoadTypeMotorway:
options.avoidMotorway = YES;
break;
} }
[options save]; [options save];
[self rebuildWithBestRouter:YES]; [self rebuildWithBestRouter:YES];
} }
+ (void)showNavigationMapControls { + (void)showNavigationMapControls
{
[[MWMMapViewControlsManager manager] onRouteStart]; [[MWMMapViewControlsManager manager] onRouteStart];
} }
+ (void)hideNavigationMapControls { + (void)hideNavigationMapControls
{
[[MWMMapViewControlsManager manager] onRouteStop]; [[MWMMapViewControlsManager manager] onRouteStop];
} }

View File

@@ -1,8 +1,8 @@
#import <CoreApi/AppInfo.h>
#import <CoreApi/Framework.h>
#import <CoreApi/MWMCommon.h>
#import <CoreSpotlight/CoreSpotlight.h> #import <CoreSpotlight/CoreSpotlight.h>
#import <MobileCoreServices/MobileCoreServices.h> #import <MobileCoreServices/MobileCoreServices.h>
#import <CoreApi/Framework.h>
#import <CoreApi/AppInfo.h>
#import <CoreApi/MWMCommon.h>
#import "MWMSearch+CoreSpotlight.h" #import "MWMSearch+CoreSpotlight.h"
#import "MWMSettings.h" #import "MWMSettings.h"
@@ -23,14 +23,15 @@
for (auto const & categoryKey : categoriesKeys) for (auto const & categoryKey : categoriesKeys)
{ {
CSSearchableItemAttributeSet * attrSet = [[CSSearchableItemAttributeSet alloc] CSSearchableItemAttributeSet * attrSet =
initWithItemContentType: UTTypeItem.identifier]; [[CSSearchableItemAttributeSet alloc] initWithItemContentType:UTTypeItem.identifier];
NSString * categoryName = nil; NSString * categoryName = nil;
NSMutableDictionary<NSString *, NSString *> * localizedStrings = [@{} mutableCopy]; NSMutableDictionary<NSString *, NSString *> * localizedStrings = [@{} mutableCopy];
categories.ForEachSynonym(categoryKey, [&localizedStrings, &localeLanguageId, &categoryName]( categories.ForEachSynonym(categoryKey, [&localizedStrings, &localeLanguageId, &categoryName](
std::string const & name, std::string const & locale) { std::string const & name, std::string const & locale)
{
NSString * nsName = @(name.c_str()); NSString * nsName = @(name.c_str());
NSString * nsLocale = @(locale.c_str()); NSString * nsLocale = @(locale.c_str());
if ([localeLanguageId isEqualToString:nsLocale]) if ([localeLanguageId isEqualToString:nsLocale])
@@ -43,18 +44,22 @@
attrSet.displayName = [[CSLocalizedString alloc] initWithLocalizedStrings:localizedStrings]; attrSet.displayName = [[CSLocalizedString alloc] initWithLocalizedStrings:localizedStrings];
NSString * categoryKeyString = @(categoryKey.c_str()); NSString * categoryKeyString = @(categoryKey.c_str());
NSString * imageName = [NSString stringWithFormat:@"Search/Categories/%@", [categoryKeyString stringByReplacingOccurrencesOfString: @"category_" withString:@""]]; NSString * imageName = [NSString
UIImage * image = [UIImage imageNamed:imageName inBundle:nil compatibleWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle: UIUserInterfaceStyleLight]]; stringWithFormat:@"Search/Categories/%@", [categoryKeyString stringByReplacingOccurrencesOfString:@"category_"
withString:@""]];
UIImage * image = [UIImage imageNamed:imageName
inBundle:nil
compatibleWithTraitCollection:[UITraitCollection
traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]];
UIGraphicsBeginImageContext(CGSizeMake(360, 360)); UIGraphicsBeginImageContext(CGSizeMake(360, 360));
[image drawInRect:CGRectMake(0, 0, 360, 360)]; [image drawInRect:CGRectMake(0, 0, 360, 360)];
UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext(); UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext() ; UIGraphicsEndImageContext();
attrSet.thumbnailData = UIImagePNGRepresentation(resizedImage); attrSet.thumbnailData = UIImagePNGRepresentation(resizedImage);
CSSearchableItem * item = CSSearchableItem * item = [[CSSearchableItem alloc] initWithUniqueIdentifier:categoryKeyString
[[CSSearchableItem alloc] initWithUniqueIdentifier:categoryKeyString domainIdentifier:@"comaps.app.categories"
domainIdentifier:@"comaps.app.categories" attributeSet:attrSet];
attributeSet:attrSet];
[items addObject:item]; [items addObject:item];
} }
@@ -64,8 +69,7 @@
if (error) if (error)
{ {
NSError * err = error; NSError * err = error;
LOG(LERROR, LOG(LERROR, ("addCategoriesToSpotlight failed: ", err.localizedDescription.UTF8String));
("addCategoriesToSpotlight failed: ", err.localizedDescription.UTF8String));
} }
else else
{ {

View File

@@ -4,15 +4,16 @@
#import "SearchResult+Core.h" #import "SearchResult+Core.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
#include <CoreApi/MWMTypes.h>
#include <CoreApi/Framework.h> #include <CoreApi/Framework.h>
#include <CoreApi/MWMTypes.h>
#include "platform/network_policy.hpp" #include "platform/network_policy.hpp"
namespace { namespace
{
using Observer = id<MWMSearchObserver>; using Observer = id<MWMSearchObserver>;
using Observers = NSHashTable<Observer>; using Observers = NSHashTable<Observer>;
} // namespace } // namespace
@interface MWMSearch () <MWMFrameworkDrapeObserver> @interface MWMSearch () <MWMFrameworkDrapeObserver>
@@ -26,7 +27,8 @@ using Observers = NSHashTable<Observer>;
@end @end
@implementation MWMSearch { @implementation MWMSearch
{
std::string m_query; std::string m_query;
std::string m_locale; std::string m_locale;
bool m_isCategory; bool m_isCategory;
@@ -36,117 +38,123 @@ using Observers = NSHashTable<Observer>;
#pragma mark - Instance #pragma mark - Instance
+ (MWMSearch *)manager { + (MWMSearch *)manager
static MWMSearch *manager; {
static MWMSearch * manager;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ manager = [[self alloc] initManager]; });
manager = [[self alloc] initManager];
});
return manager; return manager;
} }
- (instancetype)initManager { - (instancetype)initManager
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_observers = [Observers weakObjectsHashTable]; _observers = [Observers weakObjectsHashTable];
[MWMFrameworkListener addObserver:self]; [MWMFrameworkListener addObserver:self];
} }
return self; return self;
} }
- (void)searchEverywhere { - (void)searchEverywhere
{
self.lastSearchTimestamp += 1; self.lastSearchTimestamp += 1;
NSUInteger const timestamp = self.lastSearchTimestamp; NSUInteger const timestamp = self.lastSearchTimestamp;
search::EverywhereSearchParams params{ search::EverywhereSearchParams params{
m_query, m_locale, {} /* default timeout */, m_isCategory, m_query,
// m_onResults m_locale,
[self, timestamp](search::Results results, std::vector<search::ProductInfo> productInfo) {} /* default timeout */,
m_isCategory,
// m_onResults
[self, timestamp](search::Results results, std::vector<search::ProductInfo> productInfo)
{
// Store the flag first, because we will make move next.
bool const isEndMarker = results.IsEndMarker();
if (timestamp == self.lastSearchTimestamp)
{ {
// Store the flag first, because we will make move next. self.suggestionsCount = results.GetSuggestsCount();
bool const isEndMarker = results.IsEndMarker(); self->m_everywhereResults = std::move(results);
if (timestamp == self.lastSearchTimestamp) [self onSearchResultsUpdated];
{
self.suggestionsCount = results.GetSuggestsCount();
self->m_everywhereResults = std::move(results);
[self onSearchResultsUpdated];
}
if (isEndMarker)
self.searchCount -= 1;
} }
};
if (isEndMarker)
self.searchCount -= 1;
}};
GetFramework().GetSearchAPI().SearchEverywhere(std::move(params)); GetFramework().GetSearchAPI().SearchEverywhere(std::move(params));
self.searchCount += 1; self.searchCount += 1;
} }
- (void)searchInViewport { - (void)searchInViewport
search::ViewportSearchParams params { {
m_query, m_locale, {} /* default timeout */, m_isCategory, search::ViewportSearchParams params{m_query,
// m_onStarted m_locale,
{}, {} /* default timeout */,
// m_onCompleted m_isCategory,
[self](search::Results results) // m_onStarted
{ {},
if (!results.IsEndMarker()) // m_onCompleted
return; [self](search::Results results)
if (!results.IsEndedCancelled()) {
self->m_viewportResults = std::move(results); if (!results.IsEndMarker())
} return;
}; if (!results.IsEndedCancelled())
self->m_viewportResults = std::move(results);
}};
GetFramework().GetSearchAPI().SearchInViewport(std::move(params)); GetFramework().GetSearchAPI().SearchInViewport(std::move(params));
} }
- (void)update { - (void)update
{
if (m_query.empty()) if (m_query.empty())
return; return;
switch (self.searchMode) { switch (self.searchMode)
case SearchModeEverywhere: {
[self searchEverywhere]; case SearchModeEverywhere: [self searchEverywhere]; break;
break; case SearchModeViewport: [self searchInViewport]; break;
case SearchModeViewport: case SearchModeEverywhereAndViewport:
[self searchInViewport]; [self searchEverywhere];
break; [self searchInViewport];
case SearchModeEverywhereAndViewport: break;
[self searchEverywhere];
[self searchInViewport];
break;
} }
} }
#pragma mark - Add/Remove Observers #pragma mark - Add/Remove Observers
+ (void)addObserver:(id<MWMSearchObserver>)observer { + (void)addObserver:(id<MWMSearchObserver>)observer
{
[[MWMSearch manager].observers addObject:observer]; [[MWMSearch manager].observers addObject:observer];
} }
+ (void)removeObserver:(id<MWMSearchObserver>)observer { + (void)removeObserver:(id<MWMSearchObserver>)observer
{
[[MWMSearch manager].observers removeObject:observer]; [[MWMSearch manager].observers removeObject:observer];
} }
#pragma mark - Methods #pragma mark - Methods
+ (void)saveQuery:(SearchQuery *)query { + (void)saveQuery:(SearchQuery *)query
{
if (!query.text || query.text.length == 0) if (!query.text || query.text.length == 0)
return; return;
std::string locale = (!query.locale || query.locale == 0) std::string locale = (!query.locale || query.locale == 0) ? [MWMSearch manager]->m_locale : query.locale.UTF8String;
? [MWMSearch manager]->m_locale
: query.locale.UTF8String;
std::string text = query.text.UTF8String; std::string text = query.text.UTF8String;
GetFramework().GetSearchAPI().SaveSearchQuery({std::move(locale), std::move(text)}); GetFramework().GetSearchAPI().SaveSearchQuery({std::move(locale), std::move(text)});
} }
+ (void)searchQuery:(SearchQuery *)query { + (void)searchQuery:(SearchQuery *)query
{
if (!query.text) if (!query.text)
return; return;
MWMSearch *manager = [MWMSearch manager]; MWMSearch * manager = [MWMSearch manager];
if (query.locale.length != 0) if (query.locale.length != 0)
manager->m_locale = query.locale.UTF8String; manager->m_locale = query.locale.UTF8String;
@@ -160,39 +168,46 @@ using Observers = NSHashTable<Observer>;
[manager update]; [manager update];
} }
+ (void)showResultAtIndex:(NSUInteger)index { + (void)showResultAtIndex:(NSUInteger)index
{
auto const & result = [MWMSearch manager]->m_everywhereResults[index]; auto const & result = [MWMSearch manager]->m_everywhereResults[index];
GetFramework().StopLocationFollow(); GetFramework().StopLocationFollow();
GetFramework().SelectSearchResult(result, true); GetFramework().SelectSearchResult(result, true);
} }
+ (SearchResult *)resultWithContainerIndex:(NSUInteger)index { + (SearchResult *)resultWithContainerIndex:(NSUInteger)index
{
SearchResult * result = [[SearchResult alloc] initWithResult:[MWMSearch manager]->m_everywhereResults[index] SearchResult * result = [[SearchResult alloc] initWithResult:[MWMSearch manager]->m_everywhereResults[index]
itemType:[MWMSearch resultTypeWithRow:index] itemType:[MWMSearch resultTypeWithRow:index]
index:index]; index:index];
return result; return result;
} }
+ (NSArray<SearchResult *> *)getResults { + (NSArray<SearchResult *> *)getResults
{
NSMutableArray<SearchResult *> * results = [[NSMutableArray alloc] initWithCapacity:MWMSearch.resultsCount]; NSMutableArray<SearchResult *> * results = [[NSMutableArray alloc] initWithCapacity:MWMSearch.resultsCount];
for (NSUInteger i = 0; i < MWMSearch.resultsCount; ++i) { for (NSUInteger i = 0; i < MWMSearch.resultsCount; ++i)
{
SearchResult * result = [MWMSearch resultWithContainerIndex:i]; SearchResult * result = [MWMSearch resultWithContainerIndex:i];
[results addObject:result]; [results addObject:result];
} }
return [results copy]; return [results copy];
} }
+ (SearchItemType)resultTypeWithRow:(NSUInteger)row { + (SearchItemType)resultTypeWithRow:(NSUInteger)row
{
auto itemsIndex = [MWMSearch manager].itemsIndex; auto itemsIndex = [MWMSearch manager].itemsIndex;
return [itemsIndex resultTypeWithRow:row]; return [itemsIndex resultTypeWithRow:row];
} }
+ (NSUInteger)containerIndexWithRow:(NSUInteger)row { + (NSUInteger)containerIndexWithRow:(NSUInteger)row
{
auto itemsIndex = [MWMSearch manager].itemsIndex; auto itemsIndex = [MWMSearch manager].itemsIndex;
return [itemsIndex resultContainerIndexWithRow:row]; return [itemsIndex resultContainerIndexWithRow:row];
} }
- (void)reset { - (void)reset
{
self.lastSearchTimestamp += 1; self.lastSearchTimestamp += 1;
GetFramework().GetSearchAPI().CancelAllSearches(); GetFramework().GetSearchAPI().CancelAllSearches();
@@ -202,18 +217,21 @@ using Observers = NSHashTable<Observer>;
[self onSearchResultsUpdated]; [self onSearchResultsUpdated];
} }
+ (void)clear { + (void)clear
{
auto manager = [MWMSearch manager]; auto manager = [MWMSearch manager];
manager->m_query.clear(); manager->m_query.clear();
manager.suggestionsCount = 0; manager.suggestionsCount = 0;
[manager reset]; [manager reset];
} }
+ (SearchMode)searchMode { + (SearchMode)searchMode
{
return [MWMSearch manager].searchMode; return [MWMSearch manager].searchMode;
} }
+ (void)setSearchMode:(SearchMode)mode { + (void)setSearchMode:(SearchMode)mode
{
MWMSearch * manager = [MWMSearch manager]; MWMSearch * manager = [MWMSearch manager];
if (manager.searchMode == mode) if (manager.searchMode == mode)
return; return;
@@ -221,50 +239,54 @@ using Observers = NSHashTable<Observer>;
[manager update]; [manager update];
} }
+ (NSUInteger)suggestionsCount { + (NSUInteger)suggestionsCount
{
return [MWMSearch manager].suggestionsCount; return [MWMSearch manager].suggestionsCount;
} }
+ (NSUInteger)resultsCount { + (NSUInteger)resultsCount
{
return [MWMSearch manager].itemsIndex.count; return [MWMSearch manager].itemsIndex.count;
} }
- (void)updateItemsIndexWithBannerReload:(BOOL)reloadBanner { - (void)updateItemsIndexWithBannerReload:(BOOL)reloadBanner
{
auto const resultsCount = self->m_everywhereResults.GetCount(); auto const resultsCount = self->m_everywhereResults.GetCount();
auto const itemsIndex = [[SearchIndex alloc] initWithSuggestionsCount:self.suggestionsCount auto const itemsIndex = [[SearchIndex alloc] initWithSuggestionsCount:self.suggestionsCount
resultsCount:resultsCount]; resultsCount:resultsCount];
[itemsIndex build]; [itemsIndex build];
self.itemsIndex = itemsIndex; self.itemsIndex = itemsIndex;
} }
#pragma mark - Notifications #pragma mark - Notifications
- (void)onSearchStarted { - (void)onSearchStarted
for (Observer observer in self.observers) { {
for (Observer observer in self.observers)
if ([observer respondsToSelector:@selector(onSearchStarted)]) if ([observer respondsToSelector:@selector(onSearchStarted)])
[observer onSearchStarted]; [observer onSearchStarted];
}
} }
- (void)onSearchCompleted { - (void)onSearchCompleted
{
[self updateItemsIndexWithBannerReload:YES]; [self updateItemsIndexWithBannerReload:YES];
for (Observer observer in self.observers) { for (Observer observer in self.observers)
if ([observer respondsToSelector:@selector(onSearchCompleted)]) if ([observer respondsToSelector:@selector(onSearchCompleted)])
[observer onSearchCompleted]; [observer onSearchCompleted];
}
} }
- (void)onSearchResultsUpdated { - (void)onSearchResultsUpdated
{
[self updateItemsIndexWithBannerReload:NO]; [self updateItemsIndexWithBannerReload:NO];
for (Observer observer in self.observers) { for (Observer observer in self.observers)
if ([observer respondsToSelector:@selector(onSearchResultsUpdated)]) if ([observer respondsToSelector:@selector(onSearchResultsUpdated)])
[observer onSearchResultsUpdated]; [observer onSearchResultsUpdated];
}
} }
#pragma mark - MWMFrameworkDrapeObserver #pragma mark - MWMFrameworkDrapeObserver
- (void)processViewportChangedEvent { - (void)processViewportChangedEvent
{
if (!GetFramework().GetSearchAPI().IsViewportSearchActive()) if (!GetFramework().GetSearchAPI().IsViewportSearchActive())
return; return;
@@ -272,19 +294,18 @@ using Observers = NSHashTable<Observer>;
if (!isSearchCompleted) if (!isSearchCompleted)
return; return;
switch (self.searchMode) { switch (self.searchMode)
case SearchModeEverywhere: {
case SearchModeViewport: case SearchModeEverywhere:
break; case SearchModeViewport: break;
case SearchModeEverywhereAndViewport: case SearchModeEverywhereAndViewport: [self searchEverywhere]; break;
[self searchEverywhere];
break;
} }
} }
#pragma mark - Properties #pragma mark - Properties
- (void)setSearchCount:(NSInteger)searchCount { - (void)setSearchCount:(NSInteger)searchCount
{
NSAssert((searchCount >= 0) && ((_searchCount == searchCount - 1) || (_searchCount == searchCount + 1)), NSAssert((searchCount >= 0) && ((_searchCount == searchCount - 1) || (_searchCount == searchCount + 1)),
@"Invalid search count update"); @"Invalid search count update");
if (searchCount > 0) if (searchCount > 0)

View File

@@ -1,10 +1,10 @@
#import "SearchResult+Core.h"
#import "CLLocation+Mercator.h" #import "CLLocation+Mercator.h"
#import "MWMLocationManager.h" #import "MWMLocationManager.h"
#import "SearchResult+Core.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
#import "platform/localization.hpp"
#import "platform/distance.hpp" #import "platform/distance.hpp"
#import "platform/localization.hpp"
#include "map/bookmark_helpers.hpp" #include "map/bookmark_helpers.hpp"
@@ -12,9 +12,11 @@
@implementation SearchResult @implementation SearchResult
- (instancetype)initWithTitleText:(NSString *)titleText type:(SearchItemType)type suggestion:(NSString *)suggestion { - (instancetype)initWithTitleText:(NSString *)titleText type:(SearchItemType)type suggestion:(NSString *)suggestion
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_titleText = titleText; _titleText = titleText;
_itemType = type; _itemType = type;
_suggestion = suggestion; _suggestion = suggestion;
@@ -24,71 +26,87 @@
@end @end
@implementation SearchResult(Core) @implementation SearchResult (Core)
- (instancetype)initWithResult:(const search::Result &)result itemType:(SearchItemType)itemType index:(NSUInteger)index { - (instancetype)initWithResult:(search::Result const &)result itemType:(SearchItemType)itemType index:(NSUInteger)index
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_index = index; _index = index;
_titleText = result.GetString().empty() ? @(result.GetLocalizedFeatureType().c_str()) : @(result.GetString().c_str()); _titleText =
result.GetString().empty() ? @(result.GetLocalizedFeatureType().c_str()) : @(result.GetString().c_str());
_addressText = @(result.GetAddress().c_str()); _addressText = @(result.GetAddress().c_str());
_infoText = @(result.GetFeatureDescription().c_str()); _infoText = @(result.GetFeatureDescription().c_str());
if (result.IsSuggest()) if (result.IsSuggest())
_suggestion = @(result.GetSuggestionString().c_str()); _suggestion = @(result.GetSuggestionString().c_str());
_distanceText = nil; _distanceText = nil;
if (result.HasPoint()) { if (result.HasPoint())
{
auto const center = result.GetFeatureCenter(); auto const center = result.GetFeatureCenter();
_point = CGPointMake(center.x, center.y); _point = CGPointMake(center.x, center.y);
auto const [centerLat, centerLon] = mercator::ToLatLon(center); auto const [centerLat, centerLon] = mercator::ToLatLon(center);
_coordinate = CLLocationCoordinate2DMake(centerLat, centerLon); _coordinate = CLLocationCoordinate2DMake(centerLat, centerLon);
CLLocation * lastLocation = [MWMLocationManager lastLocation]; CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (lastLocation) { if (lastLocation)
{
double const distanceM = mercator::DistanceOnEarth(lastLocation.mercator, center); double const distanceM = mercator::DistanceOnEarth(lastLocation.mercator, center);
std::string const distanceStr = platform::Distance::CreateFormatted(distanceM).ToString(); std::string const distanceStr = platform::Distance::CreateFormatted(distanceM).ToString();
_distanceText = @(distanceStr.c_str()); _distanceText = @(distanceStr.c_str());
} }
} }
switch (result.IsOpenNow()) { switch (result.IsOpenNow())
case osm::Yes: { {
const int minutes = result.GetMinutesUntilClosed(); case osm::Yes:
if (minutes < 60) { // less than 1 hour {
_openStatusColor = [UIColor colorNamed:@"Base Colors/Yellow Color"]; int const minutes = result.GetMinutesUntilClosed();
NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")]; if (minutes < 60)
_openStatusText = [NSString stringWithFormat:L(@"closes_in"), time]; { // less than 1 hour
} else { _openStatusColor = [UIColor colorNamed:@"Base Colors/Yellow Color"];
_openStatusColor = [UIColor colorNamed:@"Base Colors/Green Color"]; NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")];
_openStatusText = L(@"editor_time_open"); _openStatusText = [NSString stringWithFormat:L(@"closes_in"), time];
}
break;
} }
case osm::No: { else
const int minutes = result.GetMinutesUntilOpen(); {
if (minutes < 60) { // less than 1 hour _openStatusColor = [UIColor colorNamed:@"Base Colors/Green Color"];
NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")]; _openStatusText = L(@"editor_time_open");
_openStatusText = [NSString stringWithFormat:L(@"opens_in"), time];
} else {
_openStatusText = L(@"closed");
}
_openStatusColor = [UIColor colorNamed:@"Base Colors/Red Color"];
break;
} }
case osm::Unknown: { break;
_openStatusText = nil; }
_openStatusColor = UIColor.clearColor; case osm::No:
break; {
int const minutes = result.GetMinutesUntilOpen();
if (minutes < 60)
{ // less than 1 hour
NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")];
_openStatusText = [NSString stringWithFormat:L(@"opens_in"), time];
} }
else
{
_openStatusText = L(@"closed");
}
_openStatusColor = [UIColor colorNamed:@"Base Colors/Red Color"];
break;
}
case osm::Unknown:
{
_openStatusText = nil;
_openStatusColor = UIColor.clearColor;
break;
}
} }
_isPopularHidden = YES; // Restore logic in the future when popularity is available. _isPopularHidden = YES; // Restore logic in the future when popularity is available.
_isPureSuggest = result.GetResultType() == search::Result::Type::PureSuggest; _isPureSuggest = result.GetResultType() == search::Result::Type::PureSuggest;
NSMutableArray<NSValue *> * ranges = [NSMutableArray array]; NSMutableArray<NSValue *> * ranges = [NSMutableArray array];
size_t const rangesCount = result.GetHighlightRangesCount(); size_t const rangesCount = result.GetHighlightRangesCount();
for (size_t i = 0; i < rangesCount; ++i) { for (size_t i = 0; i < rangesCount; ++i)
auto const &range = result.GetHighlightRange(i); {
auto const & range = result.GetHighlightRange(i);
NSRange nsRange = NSMakeRange(range.first, range.second); NSRange nsRange = NSMakeRange(range.first, range.second);
[ranges addObject:[NSValue valueWithRange:nsRange]]; [ranges addObject:[NSValue valueWithRange:nsRange]];
} }
@@ -96,12 +114,12 @@
_itemType = itemType; _itemType = itemType;
if (result.GetResultType() == search::Result::Type::Feature) { if (result.GetResultType() == search::Result::Type::Feature)
{
auto const featureType = result.GetFeatureType(); auto const featureType = result.GetFeatureType();
auto const bookmarkImage = GetBookmarkIconByFeatureType(featureType); auto const bookmarkImage = GetBookmarkIconByFeatureType(featureType);
_iconImageName = [NSString stringWithFormat:@"%@%@", _iconImageName =
@"ic_bm_", [NSString stringWithFormat:@"%@%@", @"ic_bm_", [@(kml::ToString(bookmarkImage).c_str()) lowercaseString]];
[@(kml::ToString(bookmarkImage).c_str()) lowercaseString]];
} }
} }
return self; return self;

View File

@@ -2,7 +2,8 @@
#include "routing/routing_options.hpp" #include "routing/routing_options.hpp"
@interface MWMRoutingOptions() { @interface MWMRoutingOptions ()
{
routing::RoutingOptions _options; routing::RoutingOptions _options;
} }
@@ -10,70 +11,80 @@
@implementation MWMRoutingOptions @implementation MWMRoutingOptions
- (instancetype)init { - (instancetype)init
{
self = [super init]; self = [super init];
if (self) { if (self)
_options = routing::RoutingOptions::LoadCarOptionsFromSettings(); _options = routing::RoutingOptions::LoadCarOptionsFromSettings();
}
return self; return self;
} }
- (BOOL)avoidToll { - (BOOL)avoidToll
{
return _options.Has(routing::RoutingOptions::Road::Toll); return _options.Has(routing::RoutingOptions::Road::Toll);
} }
- (void)setAvoidToll:(BOOL)avoid { - (void)setAvoidToll:(BOOL)avoid
{
[self setOption:(routing::RoutingOptions::Road::Toll) enabled:avoid]; [self setOption:(routing::RoutingOptions::Road::Toll) enabled:avoid];
} }
- (BOOL)avoidDirty { - (BOOL)avoidDirty
{
return _options.Has(routing::RoutingOptions::Road::Dirty); return _options.Has(routing::RoutingOptions::Road::Dirty);
} }
- (void)setAvoidDirty:(BOOL)avoid { - (void)setAvoidDirty:(BOOL)avoid
{
[self setOption:(routing::RoutingOptions::Road::Dirty) enabled:avoid]; [self setOption:(routing::RoutingOptions::Road::Dirty) enabled:avoid];
} }
- (BOOL)avoidFerry { - (BOOL)avoidFerry
{
return _options.Has(routing::RoutingOptions::Road::Ferry); return _options.Has(routing::RoutingOptions::Road::Ferry);
} }
- (void)setAvoidFerry:(BOOL)avoid { - (void)setAvoidFerry:(BOOL)avoid
{
[self setOption:(routing::RoutingOptions::Road::Ferry) enabled:avoid]; [self setOption:(routing::RoutingOptions::Road::Ferry) enabled:avoid];
} }
- (BOOL)avoidMotorway { - (BOOL)avoidMotorway
{
return _options.Has(routing::RoutingOptions::Road::Motorway); return _options.Has(routing::RoutingOptions::Road::Motorway);
} }
- (void)setAvoidMotorway:(BOOL)avoid { - (void)setAvoidMotorway:(BOOL)avoid
{
[self setOption:(routing::RoutingOptions::Road::Motorway) enabled:avoid]; [self setOption:(routing::RoutingOptions::Road::Motorway) enabled:avoid];
} }
- (BOOL)hasOptions { - (BOOL)hasOptions
{
return self.avoidToll || self.avoidDirty || self.avoidFerry || self.avoidMotorway; return self.avoidToll || self.avoidDirty || self.avoidFerry || self.avoidMotorway;
} }
- (void)save { - (void)save
{
routing::RoutingOptions::SaveCarOptionsToSettings(_options); routing::RoutingOptions::SaveCarOptionsToSettings(_options);
} }
- (void)setOption:(routing::RoutingOptions::Road)option enabled:(BOOL)enabled { - (void)setOption:(routing::RoutingOptions::Road)option enabled:(BOOL)enabled
if (enabled) { {
if (enabled)
_options.Add(option); _options.Add(option);
} else { else
_options.Remove(option); _options.Remove(option);
}
} }
- (BOOL)isEqual:(id)object { - (BOOL)isEqual:(id)object
if (![object isMemberOfClass:self.class]) { {
if (![object isMemberOfClass:self.class])
return NO; return NO;
} MWMRoutingOptions * another = (MWMRoutingOptions *)object;
MWMRoutingOptions *another = (MWMRoutingOptions *)object;
return another.avoidToll == self.avoidToll && another.avoidDirty == self.avoidDirty && return another.avoidToll == self.avoidToll && another.avoidDirty == self.avoidDirty &&
another.avoidFerry == self.avoidFerry && another.avoidMotorway == self.avoidMotorway; another.avoidFerry == self.avoidFerry && another.avoidMotorway == self.avoidMotorway;
} }
@end @end

View File

@@ -31,16 +31,15 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
{ {
bool _ = true, on = true; bool _ = true, on = true;
GetFramework().Load3dMode(_, on); GetFramework().Load3dMode(_, on);
if (GetFramework().GetPowerManager().GetScheme() == power_management::Scheme::EconomyMaximum) { if (GetFramework().GetPowerManager().GetScheme() == power_management::Scheme::EconomyMaximum)
return false; return false;
} else { else
return on; return on;
}
} }
+ (void)setBuildings3dViewEnabled:(BOOL)buildings3dViewEnabled; + (void)setBuildings3dViewEnabled:(BOOL)buildings3dViewEnabled;
{ {
auto &f = GetFramework(); auto & f = GetFramework();
bool _ = true, is3dBuildings = true; bool _ = true, is3dBuildings = true;
f.Load3dMode(_, is3dBuildings); f.Load3dMode(_, is3dBuildings);
is3dBuildings = static_cast<bool>(buildings3dViewEnabled); is3dBuildings = static_cast<bool>(buildings3dViewEnabled);
@@ -51,14 +50,14 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (BOOL)perspectiveViewEnabled; + (BOOL)perspectiveViewEnabled;
{ {
bool _ = true, on = true; bool _ = true, on = true;
auto &f = GetFramework(); auto & f = GetFramework();
f.Load3dMode(on, _); f.Load3dMode(on, _);
return on; return on;
} }
+ (void)setPerspectiveViewEnabled:(BOOL)perspectiveViewEnabled; + (void)setPerspectiveViewEnabled:(BOOL)perspectiveViewEnabled;
{ {
auto &f = GetFramework(); auto & f = GetFramework();
bool is3d = true, _ = true; bool is3d = true, _ = true;
f.Load3dMode(is3d, _); f.Load3dMode(is3d, _);
is3d = static_cast<bool>(perspectiveViewEnabled); is3d = static_cast<bool>(perspectiveViewEnabled);
@@ -73,7 +72,7 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (void)setAutoZoomEnabled:(BOOL)autoZoomEnabled + (void)setAutoZoomEnabled:(BOOL)autoZoomEnabled
{ {
auto &f = GetFramework(); auto & f = GetFramework();
f.AllowAutoZoom(autoZoomEnabled); f.AllowAutoZoom(autoZoomEnabled);
f.SaveAutoZoom(autoZoomEnabled); f.SaveAutoZoom(autoZoomEnabled);
} }
@@ -130,12 +129,14 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (MWMTheme)theme + (MWMTheme)theme
{ {
if ([MWMCarPlayService shared].isCarplayActivated) { if ([MWMCarPlayService shared].isCarplayActivated)
{
UIUserInterfaceStyle style = [[MWMCarPlayService shared] interfaceStyle]; UIUserInterfaceStyle style = [[MWMCarPlayService shared] interfaceStyle];
switch (style) { switch (style)
case UIUserInterfaceStyleLight: return MWMThemeDay; {
case UIUserInterfaceStyleDark: return MWMThemeNight; case UIUserInterfaceStyleLight: return MWMThemeDay;
case UIUserInterfaceStyleUnspecified: break; case UIUserInterfaceStyleDark: return MWMThemeNight;
case UIUserInterfaceStyleUnspecified: break;
} }
} }
auto ud = NSUserDefaults.standardUserDefaults; auto ud = NSUserDefaults.standardUserDefaults;
@@ -158,11 +159,10 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (NSInteger)powerManagement + (NSInteger)powerManagement
{ {
Scheme scheme = GetFramework().GetPowerManager().GetScheme(); Scheme scheme = GetFramework().GetPowerManager().GetScheme();
if (scheme == Scheme::EconomyMaximum) { if (scheme == Scheme::EconomyMaximum)
return 2; return 2;
} else if (scheme == Scheme::Auto) { else if (scheme == Scheme::Auto)
return 1; return 1;
}
return 0; return 0;
} }
@@ -170,11 +170,10 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (void)setPowerManagement:(NSInteger)powerManagement + (void)setPowerManagement:(NSInteger)powerManagement
{ {
Scheme scheme = Scheme::Normal; Scheme scheme = Scheme::Normal;
if (powerManagement == 2) { if (powerManagement == 2)
scheme = Scheme::EconomyMaximum; scheme = Scheme::EconomyMaximum;
} else if (powerManagement == 1) { else if (powerManagement == 1)
scheme = Scheme::Auto; scheme = Scheme::Auto;
}
GetFramework().GetPowerManager().SetScheme(scheme); GetFramework().GetPowerManager().SetScheme(scheme);
} }
@@ -185,7 +184,10 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
return enabled; return enabled;
} }
+ (void)setRoutingDisclaimerApproved { settings::Set(kRoutingDisclaimerApprovedKey, true); } + (void)setRoutingDisclaimerApproved
{
settings::Set(kRoutingDisclaimerApprovedKey, true);
}
+ (NSString *)spotlightLocaleLanguageId + (NSString *)spotlightLocaleLanguageId
{ {
return [NSUserDefaults.standardUserDefaults stringForKey:kSpotlightLocaleLanguageId]; return [NSUserDefaults.standardUserDefaults stringForKey:kSpotlightLocaleLanguageId];
@@ -197,7 +199,10 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
[ud setObject:spotlightLocaleLanguageId forKey:kSpotlightLocaleLanguageId]; [ud setObject:spotlightLocaleLanguageId forKey:kSpotlightLocaleLanguageId];
} }
+ (BOOL)largeFontSize { return GetFramework().LoadLargeFontsSize(); } + (BOOL)largeFontSize
{
return GetFramework().LoadLargeFontsSize();
}
+ (void)setLargeFontSize:(BOOL)largeFontSize + (void)setLargeFontSize:(BOOL)largeFontSize
{ {
GetFramework().SetLargeFontsSize(static_cast<bool>(largeFontSize)); GetFramework().SetLargeFontsSize(static_cast<bool>(largeFontSize));
@@ -205,11 +210,10 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (NSDictionary<NSString *, NSString *> *)availableMapLanguages; + (NSDictionary<NSString *, NSString *> *)availableMapLanguages;
{ {
NSMutableDictionary<NSString *, NSString *> *availableLanguages = [[NSMutableDictionary alloc] init]; NSMutableDictionary<NSString *, NSString *> * availableLanguages = [[NSMutableDictionary alloc] init];
auto const & v = StringUtf8Multilang::GetSupportedLanguages(false); auto const & v = StringUtf8Multilang::GetSupportedLanguages(false);
for (auto i: v) { for (auto i : v)
[availableLanguages setObject:@(std::string(i.m_name).c_str()) forKey:@(std::string(i.m_code).c_str())]; [availableLanguages setObject:@(std::string(i.m_name).c_str()) forKey:@(std::string(i.m_code).c_str())];
}
return availableLanguages; return availableLanguages;
} }
@@ -217,24 +221,25 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
{ {
std::string mapLanguageCode; std::string mapLanguageCode;
bool hasMapLanguageCode = settings::Get(kMapLanguageCode, mapLanguageCode); bool hasMapLanguageCode = settings::Get(kMapLanguageCode, mapLanguageCode);
if (hasMapLanguageCode) { if (hasMapLanguageCode)
return @(mapLanguageCode.c_str()); return @(mapLanguageCode.c_str());
}
return @"auto"; return @"auto";
} }
+ (void)setMapLanguageCode:(NSString *)mapLanguageCode; + (void)setMapLanguageCode:(NSString *)mapLanguageCode;
{ {
auto &f = GetFramework(); auto & f = GetFramework();
if ([mapLanguageCode isEqual: @"auto"]) { if ([mapLanguageCode isEqual:@"auto"])
f.ResetMapLanguageCode(); f.ResetMapLanguageCode();
} else { else
f.SetMapLanguageCode(std::string([mapLanguageCode UTF8String])); f.SetMapLanguageCode(std::string([mapLanguageCode UTF8String]));
}
} }
+ (BOOL)transliteration { return GetFramework().LoadTransliteration(); } + (BOOL)transliteration
{
return GetFramework().LoadTransliteration();
}
+ (void)setTransliteration:(BOOL)transliteration + (void)setTransliteration:(BOOL)transliteration
{ {
bool const isTransliteration = static_cast<bool>(transliteration); bool const isTransliteration = static_cast<bool>(transliteration);
@@ -268,21 +273,23 @@ NSString * const kUDFileLoggingEnabledKey = @"FileLoggingEnabledKey";
+ (void)setICLoudSynchronizationEnabled:(BOOL)iCLoudSyncEnabled + (void)setICLoudSynchronizationEnabled:(BOOL)iCLoudSyncEnabled
{ {
[NSUserDefaults.standardUserDefaults setBool:iCLoudSyncEnabled forKey:kiCLoudSynchronizationEnabledKey]; [NSUserDefaults.standardUserDefaults setBool:iCLoudSyncEnabled forKey:kiCLoudSynchronizationEnabledKey];
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.iCloudSynchronizationDidChangeEnabledState object:nil]; [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.iCloudSynchronizationDidChangeEnabledState
object:nil];
} }
+ (void)initializeLogging { + (void)initializeLogging
{
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ [self setFileLoggingEnabled:[self isFileLoggingEnabled]]; });
[self setFileLoggingEnabled:[self isFileLoggingEnabled]];
});
} }
+ (BOOL)isFileLoggingEnabled { + (BOOL)isFileLoggingEnabled
{
return [NSUserDefaults.standardUserDefaults boolForKey:kUDFileLoggingEnabledKey]; return [NSUserDefaults.standardUserDefaults boolForKey:kUDFileLoggingEnabledKey];
} }
+ (void)setFileLoggingEnabled:(BOOL)fileLoggingEnabled { + (void)setFileLoggingEnabled:(BOOL)fileLoggingEnabled
{
[NSUserDefaults.standardUserDefaults setBool:fileLoggingEnabled forKey:kUDFileLoggingEnabledKey]; [NSUserDefaults.standardUserDefaults setBool:fileLoggingEnabled forKey:kUDFileLoggingEnabledKey];
[Logger setFileLoggingEnabled:fileLoggingEnabled]; [Logger setFileLoggingEnabled:fileLoggingEnabled];
} }

View File

@@ -48,7 +48,7 @@ using Observer = id<MWMTextToSpeechObserver>;
using Observers = NSHashTable<Observer>; using Observers = NSHashTable<Observer>;
} // namespace } // namespace
@interface MWMTextToSpeech ()<AVSpeechSynthesizerDelegate> @interface MWMTextToSpeech () <AVSpeechSynthesizerDelegate>
{ {
std::vector<std::pair<std::string, std::string>> _availableLanguages; std::vector<std::pair<std::string, std::string>> _availableLanguages;
} }
@@ -63,24 +63,26 @@ using Observers = NSHashTable<Observer>;
@implementation MWMTextToSpeech @implementation MWMTextToSpeech
+ (MWMTextToSpeech *)tts { + (MWMTextToSpeech *)tts
{
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
static MWMTextToSpeech * tts = nil; static MWMTextToSpeech * tts = nil;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{ tts = [[self alloc] initTTS]; });
tts = [[self alloc] initTTS];
});
return tts; return tts;
} }
+ (void)applicationDidBecomeActive { + (void)applicationDidBecomeActive
{
auto tts = [self tts]; auto tts = [self tts];
tts.speechSynthesizer = nil; tts.speechSynthesizer = nil;
tts.speechVoice = nil; tts.speechVoice = nil;
} }
- (instancetype)initTTS { - (instancetype)initTTS
{
self = [super init]; self = [super init];
if (self) { if (self)
{
_availableLanguages = availableLanguages(); _availableLanguages = availableLanguages();
_observers = [Observers weakObjectsHashTable]; _observers = [Observers weakObjectsHashTable];
@@ -92,52 +94,64 @@ using Observers = NSHashTable<Observer>;
preferedLanguageBcp47 = [AVSpeechSynthesisVoice currentLanguageCode]; preferedLanguageBcp47 = [AVSpeechSynthesisVoice currentLanguageCode];
std::pair<std::string, std::string> const lan = std::pair<std::string, std::string> const lan =
std::make_pair(preferedLanguageBcp47.UTF8String, std::make_pair(preferedLanguageBcp47.UTF8String, tts::translateLocale(preferedLanguageBcp47.UTF8String));
tts::translateLocale(preferedLanguageBcp47.UTF8String));
if (find(_availableLanguages.begin(), _availableLanguages.end(), lan) != if (find(_availableLanguages.begin(), _availableLanguages.end(), lan) != _availableLanguages.end())
_availableLanguages.end())
[self setNotificationsLocale:preferedLanguageBcp47]; [self setNotificationsLocale:preferedLanguageBcp47];
else else
[self setNotificationsLocale:kDefaultLanguage]; [self setNotificationsLocale:kDefaultLanguage];
NSError * err = nil; NSError * err = nil;
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
mode:AVAudioSessionModeVoicePrompt mode:AVAudioSessionModeVoicePrompt
options:AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | options:AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
AVAudioSessionCategoryOptionDuckOthers AVAudioSessionCategoryOptionDuckOthers
error:&err]) { error:&err])
{
LOG(LWARNING, ("Couldn't configure audio session: ", [err localizedDescription])); LOG(LWARNING, ("Couldn't configure audio session: ", [err localizedDescription]));
} }
// Set initial StreetNamesTTS setting // Set initial StreetNamesTTS setting
NSDictionary *dictionary = @{ kIsStreetNamesTTSEnabled : @NO }; NSDictionary * dictionary = @{kIsStreetNamesTTSEnabled: @NO};
[NSUserDefaults.standardUserDefaults registerDefaults:dictionary]; [NSUserDefaults.standardUserDefaults registerDefaults:dictionary];
self.active = YES; self.active = YES;
} }
return self; return self;
} }
- (void)dealloc { - (void)dealloc
{
[[AVAudioSession sharedInstance] setActive:NO [[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil]; error:nil];
self.speechSynthesizer.delegate = nil; self.speechSynthesizer.delegate = nil;
} }
- (std::vector<std::pair<std::string, std::string>>)availableLanguages { return _availableLanguages; } - (std::vector<std::pair<std::string, std::string>>)availableLanguages
- (std::pair<std::string, std::string>)standardLanguage { {
return _availableLanguages;
}
- (std::pair<std::string, std::string>)standardLanguage
{
return std::make_pair(kDefaultLanguage.UTF8String, tts::translateLocale(kDefaultLanguage.UTF8String)); return std::make_pair(kDefaultLanguage.UTF8String, tts::translateLocale(kDefaultLanguage.UTF8String));
} }
- (void)setNotificationsLocale:(NSString *)locale { - (void)setNotificationsLocale:(NSString *)locale
{
NSUserDefaults * ud = NSUserDefaults.standardUserDefaults; NSUserDefaults * ud = NSUserDefaults.standardUserDefaults;
[ud setObject:locale forKey:kUserDefaultsTTSLanguageBcp47]; [ud setObject:locale forKey:kUserDefaultsTTSLanguageBcp47];
[self createVoice:locale]; [self createVoice:locale];
} }
- (BOOL)isValid { return _speechSynthesizer != nil && _speechVoice != nil; } - (BOOL)isValid
+ (BOOL)isTTSEnabled { return [NSUserDefaults.standardUserDefaults boolForKey:kIsTTSEnabled]; } {
+ (void)setTTSEnabled:(BOOL)enabled { return _speechSynthesizer != nil && _speechVoice != nil;
}
+ (BOOL)isTTSEnabled
{
return [NSUserDefaults.standardUserDefaults boolForKey:kIsTTSEnabled];
}
+ (void)setTTSEnabled:(BOOL)enabled
{
if ([self isTTSEnabled] == enabled) if ([self isTTSEnabled] == enabled)
return; return;
auto tts = [self tts]; auto tts = [self tts];
@@ -150,8 +164,12 @@ using Observers = NSHashTable<Observer>;
if (enabled) if (enabled)
[tts setActive:YES]; [tts setActive:YES];
} }
+ (BOOL)isStreetNamesTTSEnabled { return [NSUserDefaults.standardUserDefaults boolForKey:kIsStreetNamesTTSEnabled]; } + (BOOL)isStreetNamesTTSEnabled
+ (void)setStreetNamesTTSEnabled:(BOOL)enabled { {
return [NSUserDefaults.standardUserDefaults boolForKey:kIsStreetNamesTTSEnabled];
}
+ (void)setStreetNamesTTSEnabled:(BOOL)enabled
{
if ([self isStreetNamesTTSEnabled] == enabled) if ([self isStreetNamesTTSEnabled] == enabled)
return; return;
NSUserDefaults * ud = NSUserDefaults.standardUserDefaults; NSUserDefaults * ud = NSUserDefaults.standardUserDefaults;
@@ -159,60 +177,59 @@ using Observers = NSHashTable<Observer>;
[ud synchronize]; [ud synchronize];
} }
- (void)setActive:(BOOL)active { - (void)setActive:(BOOL)active
{
if (![[self class] isTTSEnabled] || self.active == active) if (![[self class] isTTSEnabled] || self.active == active)
return; return;
if (active && ![self isValid]) if (active && ![self isValid])
[self createVoice:[[self class] savedLanguage]]; [self createVoice:[[self class] savedLanguage]];
[MWMRouter enableTurnNotifications:active]; [MWMRouter enableTurnNotifications:active];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [self onTTSStatusUpdated]; });
[self onTTSStatusUpdated];
});
} }
- (BOOL)active { return [[self class] isTTSEnabled] && [MWMRouter areTurnNotificationsEnabled]; } - (BOOL)active
{
return [[self class] isTTSEnabled] && [MWMRouter areTurnNotificationsEnabled];
}
+ (NSDictionary<NSString *, NSString *> *)availableLanguages + (NSDictionary<NSString *, NSString *> *)availableLanguages
{ {
NSMutableDictionary<NSString *, NSString *> *availableLanguages = [[NSMutableDictionary alloc] init]; NSMutableDictionary<NSString *, NSString *> * availableLanguages = [[NSMutableDictionary alloc] init];
auto const & v = [[self tts] availableLanguages]; auto const & v = [[self tts] availableLanguages];
for (auto i: v) { for (auto i : v)
[availableLanguages setObject:@(i.second.c_str()) forKey:@(i.first.c_str())]; [availableLanguages setObject:@(i.second.c_str()) forKey:@(i.first.c_str())];
}
return availableLanguages; return availableLanguages;
} }
+ (NSString *)selectedLanguage { + (NSString *)selectedLanguage
if ([self savedLanguage] != nil) { {
if ([self savedLanguage] != nil)
return [self savedLanguage]; return [self savedLanguage];
}
NSString * preferedLanguageBcp47 = [AVSpeechSynthesisVoice currentLanguageCode]; NSString * preferedLanguageBcp47 = [AVSpeechSynthesisVoice currentLanguageCode];
std::pair<std::string, std::string> const lan = std::pair<std::string, std::string> const lan =
std::make_pair(preferedLanguageBcp47.UTF8String, tts::translateLocale(preferedLanguageBcp47.UTF8String)); std::make_pair(preferedLanguageBcp47.UTF8String, tts::translateLocale(preferedLanguageBcp47.UTF8String));
std::vector<std::pair<std::string, std::string>> const availableLanguages = [[self tts] availableLanguages]; std::vector<std::pair<std::string, std::string>> const availableLanguages = [[self tts] availableLanguages];
if (find(availableLanguages.begin(), availableLanguages.end(), lan) != if (find(availableLanguages.begin(), availableLanguages.end(), lan) != availableLanguages.end())
availableLanguages.end()) {
return preferedLanguageBcp47; return preferedLanguageBcp47;
}
return kDefaultLanguage; return kDefaultLanguage;
} }
+ (NSString *)savedLanguage { + (NSString *)savedLanguage
{
return [NSUserDefaults.standardUserDefaults stringForKey:kUserDefaultsTTSLanguageBcp47]; return [NSUserDefaults.standardUserDefaults stringForKey:kUserDefaultsTTSLanguageBcp47];
} }
+ (NSInteger)speedCameraMode + (NSInteger)speedCameraMode
{ {
SpeedCameraManagerMode mode = GetFramework().GetRoutingManager().GetSpeedCamManager().GetMode(); SpeedCameraManagerMode mode = GetFramework().GetRoutingManager().GetSpeedCamManager().GetMode();
if (mode == SpeedCameraManagerMode::Auto) { if (mode == SpeedCameraManagerMode::Auto)
return 2; return 2;
} else if (mode == SpeedCameraManagerMode::Always) { else if (mode == SpeedCameraManagerMode::Always)
return 1; return 1;
}
return 0; return 0;
} }
@@ -220,21 +237,22 @@ using Observers = NSHashTable<Observer>;
+ (void)setSpeedCameraMode:(NSInteger)speedCameraMode + (void)setSpeedCameraMode:(NSInteger)speedCameraMode
{ {
SpeedCameraManagerMode mode = SpeedCameraManagerMode::Never; SpeedCameraManagerMode mode = SpeedCameraManagerMode::Never;
if (speedCameraMode == 2) { if (speedCameraMode == 2)
mode = SpeedCameraManagerMode::Auto; mode = SpeedCameraManagerMode::Auto;
} else if (speedCameraMode == 1) { else if (speedCameraMode == 1)
mode = SpeedCameraManagerMode::Always; mode = SpeedCameraManagerMode::Always;
}
GetFramework().GetRoutingManager().GetSpeedCamManager().SetMode(mode); GetFramework().GetRoutingManager().GetSpeedCamManager().SetMode(mode);
} }
- (void)createVoice:(NSString *)locale { - (void)createVoice:(NSString *)locale
if (!self.speechSynthesizer) { {
if (!self.speechSynthesizer)
{
self.speechSynthesizer = [[AVSpeechSynthesizer alloc] init]; self.speechSynthesizer = [[AVSpeechSynthesizer alloc] init];
self.speechSynthesizer.delegate = self; self.speechSynthesizer.delegate = self;
} }
NSMutableArray<NSString *> * candidateLocales = [@[ kDefaultLanguage, @"en-GB" ] mutableCopy]; NSMutableArray<NSString *> * candidateLocales = [@[kDefaultLanguage, @"en-GB"] mutableCopy];
if (locale) if (locale)
[candidateLocales insertObject:locale atIndex:0]; [candidateLocales insertObject:locale atIndex:0];
@@ -242,38 +260,36 @@ using Observers = NSHashTable<Observer>;
LOG(LWARNING, ("locale is nil. Trying default locale.")); LOG(LWARNING, ("locale is nil. Trying default locale."));
AVSpeechSynthesisVoice * voice = nil; AVSpeechSynthesisVoice * voice = nil;
for (NSString * loc in candidateLocales) { for (NSString * loc in candidateLocales)
if (@available(iOS 16.0, *)) { {
for (AVSpeechSynthesisVoice * aVoice in [AVSpeechSynthesisVoice speechVoices]) { if (@available(iOS 16.0, *))
if (voice == nil && aVoice.language == loc && aVoice.quality == AVSpeechSynthesisVoiceQualityPremium) { {
for (AVSpeechSynthesisVoice * aVoice in [AVSpeechSynthesisVoice speechVoices])
if (voice == nil && aVoice.language == loc && aVoice.quality == AVSpeechSynthesisVoiceQualityPremium)
voice = aVoice; voice = aVoice;
}
}
} }
for (AVSpeechSynthesisVoice * aVoice in [AVSpeechSynthesisVoice speechVoices]) { for (AVSpeechSynthesisVoice * aVoice in [AVSpeechSynthesisVoice speechVoices])
if (voice == nil && aVoice.language == loc && aVoice.quality == AVSpeechSynthesisVoiceQualityEnhanced) { if (voice == nil && aVoice.language == loc && aVoice.quality == AVSpeechSynthesisVoiceQualityEnhanced)
voice = aVoice; voice = aVoice;
} if (voice == nil)
}
if (voice == nil) {
voice = [AVSpeechSynthesisVoice voiceWithLanguage:loc]; voice = [AVSpeechSynthesisVoice voiceWithLanguage:loc];
} if (voice)
if (voice) {
break; break;
}
} }
self.speechVoice = voice; self.speechVoice = voice;
if (voice) { if (voice)
{
std::string const twineLang = bcp47ToTwineLanguage(voice.language); std::string const twineLang = bcp47ToTwineLanguage(voice.language);
if (twineLang.empty()) if (twineLang.empty())
LOG(LERROR, ("Cannot convert UI locale or default locale to twine language. MWMTextToSpeech " LOG(LERROR, ("Cannot convert UI locale or default locale to twine language. MWMTextToSpeech "
"is invalid.")); "is invalid."));
else else
[MWMRouter setTurnNotificationsLocale:@(twineLang.c_str())]; [MWMRouter setTurnNotificationsLocale:@(twineLang.c_str())];
} else { }
LOG(LWARNING, else
("The UI language and English are not available for TTS. MWMTextToSpeech is invalid.")); {
LOG(LWARNING, ("The UI language and English are not available for TTS. MWMTextToSpeech is invalid."));
} }
} }
@@ -283,25 +299,26 @@ using Observers = NSHashTable<Observer>;
[ttsTester playRandomTestString]; [ttsTester playRandomTestString];
} }
- (void)speakOneString:(NSString *)textToSpeak
- (void)speakOneString:(NSString *)textToSpeak { {
AVSpeechUtterance * utterance = [AVSpeechUtterance speechUtteranceWithString:textToSpeak]; AVSpeechUtterance * utterance = [AVSpeechUtterance speechUtteranceWithString:textToSpeak];
utterance.voice = self.speechVoice; utterance.voice = self.speechVoice;
utterance.rate = AVSpeechUtteranceDefaultSpeechRate; utterance.rate = AVSpeechUtteranceDefaultSpeechRate;
[self.speechSynthesizer speakUtterance:utterance]; [self.speechSynthesizer speakUtterance:utterance];
} }
- (void)playTurnNotifications:(NSArray<NSString *> *)turnNotifications { - (void)playTurnNotifications:(NSArray<NSString *> *)turnNotifications
{
auto stopSession = ^{ auto stopSession = ^{
if (self.speechSynthesizer.isSpeaking) if (self.speechSynthesizer.isSpeaking)
return; return;
[[AVAudioSession sharedInstance] [[AVAudioSession sharedInstance] setActive:NO
setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
error:nil];
}; };
if (![MWMRouter isOnRoute] || !self.active) { if (![MWMRouter isOnRoute] || !self.active)
{
stopSession(); stopSession();
return; return;
} }
@@ -309,17 +326,22 @@ using Observers = NSHashTable<Observer>;
if (![self isValid]) if (![self isValid])
[self createVoice:[[self class] savedLanguage]]; [self createVoice:[[self class] savedLanguage]];
if (![self isValid]) { if (![self isValid])
{
stopSession(); stopSession();
return; return;
} }
if (turnNotifications.count == 0) { if (turnNotifications.count == 0)
{
stopSession(); stopSession();
return; return;
} else { }
else
{
NSError * err = nil; NSError * err = nil;
if (![[AVAudioSession sharedInstance] setActive:YES error:&err]) { if (![[AVAudioSession sharedInstance] setActive:YES error:&err])
{
LOG(LWARNING, ("Couldn't activate audio session: ", [err localizedDescription])); LOG(LWARNING, ("Couldn't activate audio session: ", [err localizedDescription]));
return; return;
} }
@@ -329,20 +351,26 @@ using Observers = NSHashTable<Observer>;
} }
} }
- (void)playWarningSound { - (void)playWarningSound
{
if (!GetFramework().GetRoutingManager().GetSpeedCamManager().ShouldPlayBeepSignal()) if (!GetFramework().GetRoutingManager().GetSpeedCamManager().ShouldPlayBeepSignal())
return; return;
[self.audioPlayer play]; [self.audioPlayer play];
} }
- (AVAudioPlayer *)audioPlayer { - (AVAudioPlayer *)audioPlayer
if (!_audioPlayer) { {
if (auto url = [[NSBundle mainBundle] URLForResource:@"Alert 5" withExtension:@"m4a"]) { if (!_audioPlayer)
{
if (auto url = [[NSBundle mainBundle] URLForResource:@"Alert 5" withExtension:@"m4a"])
{
NSError * error = nil; NSError * error = nil;
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
CHECK(!error, (error.localizedDescription.UTF8String)); CHECK(!error, (error.localizedDescription.UTF8String));
} else { }
else
{
CHECK(false, ("Speed warning file not found")); CHECK(false, ("Speed warning file not found"));
} }
} }
@@ -350,27 +378,31 @@ using Observers = NSHashTable<Observer>;
return _audioPlayer; return _audioPlayer;
} }
- (void)play:(NSString *)text { - (void)play:(NSString *)text
{
if (![self isValid]) if (![self isValid])
[self createVoice:[[self class] savedLanguage]]; [self createVoice:[[self class] savedLanguage]];
[self speakOneString:text]; [self speakOneString:text];
} }
#pragma mark - MWMNavigationDashboardObserver #pragma mark - MWMNavigationDashboardObserver
- (void)onTTSStatusUpdated { - (void)onTTSStatusUpdated
{
for (Observer observer in self.observers) for (Observer observer in self.observers)
[observer onTTSStatusUpdated]; [observer onTTSStatusUpdated];
} }
#pragma mark - Add/Remove Observers #pragma mark - Add/Remove Observers
+ (void)addObserver:(id<MWMTextToSpeechObserver>)observer { + (void)addObserver:(id<MWMTextToSpeechObserver>)observer
{
[[self tts].observers addObject:observer]; [[self tts].observers addObject:observer];
} }
+ (void)removeObserver:(id<MWMTextToSpeechObserver>)observer { + (void)removeObserver:(id<MWMTextToSpeechObserver>)observer
{
[[self tts].observers removeObject:observer]; [[self tts].observers removeObject:observer];
} }
@@ -380,8 +412,8 @@ namespace tts
{ {
std::string translateLocale(std::string const & localeString) std::string translateLocale(std::string const & localeString)
{ {
NSString * nsLocaleString = [NSString stringWithUTF8String: localeString.c_str()]; NSString * nsLocaleString = [NSString stringWithUTF8String:localeString.c_str()];
NSLocale * locale = [[NSLocale alloc] initWithLocaleIdentifier: nsLocaleString]; NSLocale * locale = [[NSLocale alloc] initWithLocaleIdentifier:nsLocaleString];
NSString * localizedName = [locale localizedStringForLocaleIdentifier:nsLocaleString]; NSString * localizedName = [locale localizedStringForLocaleIdentifier:nsLocaleString];
localizedName = [localizedName capitalizedString]; localizedName = [localizedName capitalizedString];
return std::string(localizedName.UTF8String); return std::string(localizedName.UTF8String);

View File

@@ -14,45 +14,51 @@ NSString * testStringsLanguage;
int testStringIndex; int testStringIndex;
- (void)playRandomTestString { - (void)playRandomTestString
{
NSString * currentTTSLanguage = MWMTextToSpeech.savedLanguage; NSString * currentTTSLanguage = MWMTextToSpeech.savedLanguage;
if (testStrings == nil || ![currentTTSLanguage isEqualToString:testStringsLanguage]) { if (testStrings == nil || ![currentTTSLanguage isEqualToString:testStringsLanguage])
{
testStrings = [self getTestStrings:currentTTSLanguage]; testStrings = [self getTestStrings:currentTTSLanguage];
if (testStrings == nil) { if (testStrings == nil)
{
LOG(LWARNING, ("Couldn't load TTS test strings")); LOG(LWARNING, ("Couldn't load TTS test strings"));
return; return;
} }
testStringsLanguage = currentTTSLanguage; testStringsLanguage = currentTTSLanguage;
} }
[[MWMTextToSpeech tts] play:testStrings[testStringIndex]]; [[MWMTextToSpeech tts] play:testStrings[testStringIndex]];
if (++testStringIndex >= testStrings.count) if (++testStringIndex >= testStrings.count)
testStringIndex = 0; testStringIndex = 0;
} }
- (NSArray<NSString *> *)getTestStrings:(NSString *)language { - (NSArray<NSString *> *)getTestStrings:(NSString *)language
{
NSString * twineLanguage = [NSString stringWithUTF8String:locale_translator::bcp47ToTwineLanguage(language).c_str()]; NSString * twineLanguage = [NSString stringWithUTF8String:locale_translator::bcp47ToTwineLanguage(language).c_str()];
NSString * languagePath = [NSBundle.mainBundle pathForResource:twineLanguage ofType:@"lproj"]; NSString * languagePath = [NSBundle.mainBundle pathForResource:twineLanguage ofType:@"lproj"];
if (languagePath == nil) { if (languagePath == nil)
{
LOG(LWARNING, ("Couldn't find translation file for ", twineLanguage.UTF8String)); LOG(LWARNING, ("Couldn't find translation file for ", twineLanguage.UTF8String));
return nil; return nil;
} }
NSBundle * bundle = [NSBundle bundleWithPath:languagePath]; NSBundle * bundle = [NSBundle bundleWithPath:languagePath];
NSMutableArray * appTips = [NSMutableArray new]; NSMutableArray * appTips = [NSMutableArray new];
for (int idx = 0; ; idx++) { for (int idx = 0;; idx++)
{
NSString * appTipKey = [NSString stringWithFormat:@"app_tip_%02d", idx]; NSString * appTipKey = [NSString stringWithFormat:@"app_tip_%02d", idx];
NSString * appTip = [bundle localizedStringForKey:appTipKey value:NotFoundDelimiter table:nil]; NSString * appTip = [bundle localizedStringForKey:appTipKey value:NotFoundDelimiter table:nil];
if ([appTip isEqualToString:NotFoundDelimiter]) if ([appTip isEqualToString:NotFoundDelimiter])
break; break;
[appTips addObject:appTip]; [appTips addObject:appTip];
} }
// shuffle // shuffle
for (NSUInteger i = appTips.count; i > 1; i--) for (NSUInteger i = appTips.count; i > 1; i--)
[appTips exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)]; [appTips exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
return appTips; return appTips;
} }

View File

@@ -7,21 +7,25 @@
@implementation MWMTextToSpeechTest @implementation MWMTextToSpeechTest
- (void)testAvailableLanguages { - (void)testAvailableLanguages
{
MWMTextToSpeech * tts = [MWMTextToSpeech tts]; MWMTextToSpeech * tts = [MWMTextToSpeech tts];
std::vector<std::pair<std::string, std::string>> langs = tts.availableLanguages; std::vector<std::pair<std::string, std::string>> langs = tts.availableLanguages;
decltype(langs)::value_type const defaultLang = std::make_pair("en-US", "English (United States)"); decltype(langs)::value_type const defaultLang = std::make_pair("en-US", "English (United States)");
XCTAssertTrue(std::find(langs.begin(), langs.end(), defaultLang) != langs.end()); XCTAssertTrue(std::find(langs.begin(), langs.end(), defaultLang) != langs.end());
} }
- (void)testTranslateLocaleWithTwineString { - (void)testTranslateLocaleWithTwineString
{
XCTAssertEqual(tts::translateLocale("en"), "English"); XCTAssertEqual(tts::translateLocale("en"), "English");
} }
- (void)testTranslateLocaleWithBcp47String { - (void)testTranslateLocaleWithBcp47String
{
XCTAssertEqual(tts::translateLocale("en-US"), "English (United States)"); XCTAssertEqual(tts::translateLocale("en-US"), "English (United States)");
} }
- (void)testTranslateLocaleWithUnknownString { - (void)testTranslateLocaleWithUnknownString
{
XCTAssertEqual(tts::translateLocale("unknown"), ""); XCTAssertEqual(tts::translateLocale("unknown"), "");
} }

View File

@@ -10,7 +10,10 @@
namespace namespace
{ {
NSString *RootId() { return @(GetFramework().GetStorage().GetRootId().c_str()); } NSString * RootId()
{
return @(GetFramework().GetStorage().GetRootId().c_str());
}
enum class State enum class State
{ {
Downloading, Downloading,
@@ -66,7 +69,7 @@ using namespace storage;
[self layoutIfNeeded]; [self layoutIfNeeded];
} }
-(void)setUpdateSize:(NSString *)updateSize - (void)setUpdateSize:(NSString *)updateSize
{ {
_updateSize = updateSize; _updateSize = updateSize;
self.primaryButton.localizedText = self.primaryButton.localizedText =
@@ -154,8 +157,8 @@ using namespace storage;
+ (instancetype)instanceWithPurpose:(Framework::DoAfterUpdate)todo + (instancetype)instanceWithPurpose:(Framework::DoAfterUpdate)todo
{ {
MWMAutoupdateController * controller = MWMAutoupdateController * controller = [[MWMAutoupdateController alloc] initWithNibName:[self className]
[[MWMAutoupdateController alloc] initWithNibName:[self className] bundle:NSBundle.mainBundle]; bundle:NSBundle.mainBundle];
controller.todo = todo; controller.todo = todo;
auto view = static_cast<MWMAutoupdateView *>(controller.view); auto view = static_cast<MWMAutoupdateView *>(controller.view);
view.delegate = controller; view.delegate = controller;
@@ -168,14 +171,15 @@ using namespace storage;
{ {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
self.progressFinished = NO; self.progressFinished = NO;
MWMAutoupdateView *view = (MWMAutoupdateView *)self.view; MWMAutoupdateView * view = (MWMAutoupdateView *)self.view;
if (self.todo == Framework::DoAfterUpdate::AutoupdateMaps) if (self.todo == Framework::DoAfterUpdate::AutoupdateMaps)
{ {
[view stateDownloading]; [view stateDownloading];
[[MWMStorage sharedStorage] updateNode:RootId() onCancel:^{ [[MWMStorage sharedStorage] updateNode:RootId()
[self updateSize]; onCancel:^{
[view stateWaiting]; [self updateSize];
}]; [view stateWaiting];
}];
} }
else else
{ {
@@ -186,9 +190,7 @@ using namespace storage;
- (void)dismiss - (void)dismiss
{ {
[static_cast<MWMAutoupdateView *>(self.view) stopSpinner]; [static_cast<MWMAutoupdateView *>(self.view) stopSpinner];
[self dismissViewControllerAnimated:YES completion:^{ [self dismissViewControllerAnimated:YES completion:^{ [[MWMStorage sharedStorage] removeObserver:self]; }];
[[MWMStorage sharedStorage] removeObserver:self];
}];
} }
- (void)updateSize - (void)updateSize
@@ -204,34 +206,35 @@ using namespace storage;
- (IBAction)updateTap - (IBAction)updateTap
{ {
MWMAutoupdateView *view = (MWMAutoupdateView *)self.view; MWMAutoupdateView * view = (MWMAutoupdateView *)self.view;
[view stateDownloading]; [view stateDownloading];
[[MWMStorage sharedStorage] updateNode:RootId() onCancel:^{ [[MWMStorage sharedStorage] updateNode:RootId()
[self updateSize]; onCancel:^{
[view stateWaiting]; [self updateSize];
}]; [view stateWaiting];
}];
}
- (IBAction)hideTap
{
[self dismiss];
} }
- (IBAction)hideTap { [self dismiss]; }
- (void)cancel - (void)cancel
{ {
auto view = static_cast<MWMAutoupdateView *>(self.view); auto view = static_cast<MWMAutoupdateView *>(self.view);
UIAlertController * alertController = UIAlertController * alertController = [UIAlertController alertControllerWithTitle:nil
[UIAlertController alertControllerWithTitle:nil message:nil
message:nil preferredStyle:UIAlertControllerStyleActionSheet];
preferredStyle:UIAlertControllerStyleActionSheet];
alertController.popoverPresentationController.sourceView = view.secondaryButton; alertController.popoverPresentationController.sourceView = view.secondaryButton;
alertController.popoverPresentationController.sourceRect = view.secondaryButton.bounds; alertController.popoverPresentationController.sourceRect = view.secondaryButton.bounds;
auto cancelDownloadAction = auto cancelDownloadAction = [UIAlertAction actionWithTitle:L(@"cancel_download")
[UIAlertAction actionWithTitle:L(@"cancel_download") style:UIAlertActionStyleDestructive
style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {
handler:^(UIAlertAction * action) { [[MWMStorage sharedStorage] cancelDownloadNode:RootId()];
[[MWMStorage sharedStorage] cancelDownloadNode:RootId()]; [self dismiss];
[self dismiss]; }];
}];
[alertController addAction:cancelDownloadAction]; [alertController addAction:cancelDownloadAction];
auto cancelAction = auto cancelAction = [UIAlertAction actionWithTitle:L(@"cancel") style:UIAlertActionStyleCancel handler:nil];
[UIAlertAction actionWithTitle:L(@"cancel") style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction]; [alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil]; [self presentViewController:alertController animated:YES completion:nil];
} }
@@ -240,9 +243,11 @@ using namespace storage;
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{ {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { [coordinator
[static_cast<MWMAutoupdateView *>(self.view) updateForSize:size]; animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
} completion:nil]; [static_cast<MWMAutoupdateView *>(self.view) updateForSize:size];
}
completion:nil];
} }
- (void)updateProcessStatus:(CountryId const &)countryId - (void)updateProcessStatus:(CountryId const &)countryId
@@ -259,7 +264,10 @@ using namespace storage;
#pragma mark - MWMCircularProgressProtocol #pragma mark - MWMCircularProgressProtocol
- (void)progressButtonPressed:(MWMCircularProgress *)progress { [self cancel]; } - (void)progressButtonPressed:(MWMCircularProgress *)progress
{
[self cancel];
}
#pragma mark - MWMStorageObserver #pragma mark - MWMStorageObserver
@@ -284,7 +292,7 @@ using namespace storage;
default: m_updatingCountries.insert(countryId.UTF8String); default: m_updatingCountries.insert(countryId.UTF8String);
} }
} }
if (self.progressFinished && m_updatingCountries.empty()) if (self.progressFinished && m_updatingCountries.empty())
[self dismiss]; [self dismiss];
else else
@@ -298,9 +306,7 @@ using namespace storage;
[[MWMStorage sharedStorage] cancelDownloadNode:RootId()]; [[MWMStorage sharedStorage] cancelDownloadNode:RootId()];
} }
- (void)processCountry:(NSString *)countryId - (void)processCountry:(NSString *)countryId downloadedBytes:(uint64_t)downloadedBytes totalBytes:(uint64_t)totalBytes
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes
{ {
if (m_updatingCountries.find(countryId.UTF8String) != m_updatingCountries.end()) if (m_updatingCountries.find(countryId.UTF8String) != m_updatingCountries.end())
[self updateProcessStatus:countryId.UTF8String]; [self updateProcessStatus:countryId.UTF8String];

View File

@@ -5,7 +5,7 @@
@interface MWMEditorAdditionalNamesTableViewController () @interface MWMEditorAdditionalNamesTableViewController ()
@property (weak, nonatomic) id<MWMEditorAdditionalNamesProtocol> delegate; @property(weak, nonatomic) id<MWMEditorAdditionalNamesProtocol> delegate;
@end @end
@@ -19,8 +19,8 @@
#pragma mark - UITableViewDataSource #pragma mark - UITableViewDataSource
- (void)configWithDelegate:(id<MWMEditorAdditionalNamesProtocol>)delegate - (void)configWithDelegate:(id<MWMEditorAdditionalNamesProtocol>)delegate
name:(StringUtf8Multilang const &)name name:(StringUtf8Multilang const &)name
additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes
{ {
self.delegate = delegate; self.delegate = delegate;
m_name = name; m_name = name;
@@ -52,15 +52,16 @@ additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes
} }
std::sort(m_languages.begin(), m_languages.end(), std::sort(m_languages.begin(), m_languages.end(),
[&getIndex](StringUtf8Multilang::Lang const & lhs, StringUtf8Multilang::Lang const & rhs) { [&getIndex](StringUtf8Multilang::Lang const & lhs, StringUtf8Multilang::Lang const & rhs)
// Default name can be changed in advanced mode, but it should be last in list of names. {
if (getIndex(lhs.m_code) == kDefaultCode && getIndex(rhs.m_code) != kDefaultCode) // Default name can be changed in advanced mode, but it should be last in list of names.
return false; if (getIndex(lhs.m_code) == kDefaultCode && getIndex(rhs.m_code) != kDefaultCode)
if (getIndex(lhs.m_code) != kDefaultCode && getIndex(rhs.m_code) == kDefaultCode) return false;
return true; if (getIndex(lhs.m_code) != kDefaultCode && getIndex(rhs.m_code) == kDefaultCode)
return true;
return std::string(lhs.m_code) < std::string(rhs.m_code); return std::string(lhs.m_code) < std::string(rhs.m_code);
}); });
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

View File

@@ -22,23 +22,17 @@
self.icon.image = icon; self.icon.image = icon;
self.icon.styleName = @"MWMBlack"; self.icon.styleName = @"MWMBlack";
self.label.text = text; self.label.text = text;
[self.segmentedControl setTitle:NSLocalizedString(@"no", nil) forSegmentAtIndex:0]; [self.segmentedControl setTitle:NSLocalizedString(@"no", nil) forSegmentAtIndex:0];
[self.segmentedControl setTitle:NSLocalizedString(@"yes", nil) forSegmentAtIndex:2]; [self.segmentedControl setTitle:NSLocalizedString(@"yes", nil) forSegmentAtIndex:2];
switch(value) switch (value)
{ {
case Yes: case Yes: self.segmentedControl.selectedSegmentIndex = 2; break;
self.segmentedControl.selectedSegmentIndex = 2; case No: self.segmentedControl.selectedSegmentIndex = 0; break;
break; case Unknown: self.segmentedControl.selectedSegmentIndex = 1; break;
case No:
self.segmentedControl.selectedSegmentIndex = 0;
break;
case Unknown:
self.segmentedControl.selectedSegmentIndex = 1;
break;
} }
[self setTextColorWithSegmentedValue:value]; [self setTextColorWithSegmentedValue:value];
} }
@@ -46,13 +40,9 @@
{ {
switch (value) switch (value)
{ {
case Yes: case Yes:
case No: case No: self.label.textColor = [UIColor blackPrimaryText]; break;
self.label.textColor = [UIColor blackPrimaryText]; case Unknown: self.label.textColor = [UIColor blackHintText]; break;
break;
case Unknown:
self.label.textColor = [UIColor blackHintText];
break;
} }
} }
@@ -61,18 +51,13 @@
YesNoUnknown value; YesNoUnknown value;
switch (self.segmentedControl.selectedSegmentIndex) switch (self.segmentedControl.selectedSegmentIndex)
{ {
case 0: case 0: value = No; break;
value = No; case 1: value = Unknown; break;
break; case 2: value = Yes; break;
case 1: default:
value = Unknown; value = Unknown;
break; NSAssert(false, @"Unexpected YesNoUnknown value %ld",
case 2: static_cast<long>(self.segmentedControl.selectedSegmentIndex));
value = Yes;
break;
default:
value = Unknown;
NSAssert(false, @"Unexpected YesNoUnknown value %ld", static_cast<long>(self.segmentedControl.selectedSegmentIndex));
} }
[self.delegate cell:self changeSegmented:value]; [self.delegate cell:self changeSegmented:value];

View File

@@ -19,7 +19,7 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
} }
} // namespace } // namespace
@interface MWMCuisineEditorViewController ()<UISearchBarDelegate, MWMKeyboardObserver> @interface MWMCuisineEditorViewController () <UISearchBarDelegate, MWMKeyboardObserver>
{ {
osm::AllCuisines m_allCuisines; osm::AllCuisines m_allCuisines;
std::vector<std::string> m_selectedCuisines; std::vector<std::string> m_selectedCuisines;
@@ -107,8 +107,14 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
[self.tableView reloadData]; [self.tableView reloadData];
} }
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; } {
[searchBar resignFirstResponder];
}
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
- (void)searchBar:(UISearchBar *)searchBar setActiveState:(BOOL)isActiveState - (void)searchBar:(UISearchBar *)searchBar setActiveState:(BOOL)isActiveState
{ {
[searchBar setShowsCancelButton:isActiveState animated:YES]; [searchBar setShowsCancelButton:isActiveState animated:YES];
@@ -153,13 +159,15 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
- (void)configTable - (void)configTable
{ {
[self.tableView registerClass:[MWMTableViewCell class] [self.tableView registerClass:[MWMTableViewCell class] forCellReuseIdentifier:[UITableViewCell className]];
forCellReuseIdentifier:[UITableViewCell className]];
} }
#pragma mark - Actions #pragma mark - Actions
- (void)onCancel { [self.navigationController popViewControllerAnimated:YES]; } - (void)onCancel
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)onDone - (void)onDone
{ {
[self.delegate setSelectedCuisines:m_selectedCuisines]; [self.delegate setSelectedCuisines:m_selectedCuisines];
@@ -181,8 +189,7 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView - (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView
cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{ {
auto cell = auto cell = [tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
[tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
NSInteger const index = indexPath.row; NSInteger const index = indexPath.row;
auto const & dataSource = [self dataSourceForSection:indexPath.section]; auto const & dataSource = [self dataSourceForSection:indexPath.section];
@@ -224,16 +231,13 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
#pragma mark - UITableViewDelegate #pragma mark - UITableViewDelegate
- (void)tableView:(UITableView * _Nonnull)tableView - (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{ {
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath]; UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setSelected:NO animated:YES]; [cell setSelected:NO animated:YES];
BOOL const isAlreadySelected = cell.accessoryType == UITableViewCellAccessoryCheckmark; BOOL const isAlreadySelected = cell.accessoryType == UITableViewCellAccessoryCheckmark;
cell.accessoryType = cell.accessoryType = isAlreadySelected ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark;
isAlreadySelected ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark; [self change:[self dataSourceForSection:indexPath.section][indexPath.row] selected:!isAlreadySelected];
[self change:[self dataSourceForSection:indexPath.section][indexPath.row]
selected:!isAlreadySelected];
} }
@end @end

View File

@@ -9,9 +9,9 @@
#import "MWMEditorCategoryCell.h" #import "MWMEditorCategoryCell.h"
#import "MWMEditorCellType.h" #import "MWMEditorCellType.h"
#import "MWMEditorNotesFooter.h" #import "MWMEditorNotesFooter.h"
#import "MWMEditorSegmentedTableViewCell.hpp"
#import "MWMEditorSelectTableViewCell.h" #import "MWMEditorSelectTableViewCell.h"
#import "MWMEditorSwitchTableViewCell.h" #import "MWMEditorSwitchTableViewCell.h"
#import "MWMEditorSegmentedTableViewCell.hpp"
#import "MWMEditorTextTableViewCell.h" #import "MWMEditorTextTableViewCell.h"
#import "MWMNoteCell.h" #import "MWMNoteCell.h"
#import "MWMObjectsCategorySelectorController.h" #import "MWMObjectsCategorySelectorController.h"
@@ -24,8 +24,8 @@
#import <CoreApi/Framework.h> #import <CoreApi/Framework.h>
#import <CoreApi/StringUtils.h> #import <CoreApi/StringUtils.h>
#include "platform/localization.hpp"
#include "indexer/validate_and_format_contacts.hpp" #include "indexer/validate_and_format_contacts.hpp"
#include "platform/localization.hpp"
namespace namespace
{ {
@@ -49,15 +49,14 @@ typedef NS_ENUM(NSUInteger, MWMEditorSection) {
MWMEditorSectionButton MWMEditorSectionButton
}; };
std::vector<MWMEditorCellID> const kSectionCategoryCellTypes { MWMEditorCellTypeCategory }; std::vector<MWMEditorCellID> const kSectionCategoryCellTypes{MWMEditorCellTypeCategory};
std::vector<MWMEditorCellID> const kSectionAddressCellTypes { std::vector<MWMEditorCellID> const kSectionAddressCellTypes{MWMEditorCellTypeStreet, MWMEditorCellTypeBuilding,
MWMEditorCellTypeStreet, MWMEditorCellTypeBuilding, MetadataID::FMD_POSTCODE MetadataID::FMD_POSTCODE};
};
std::vector<MWMEditorCellID> const kSectionNoteCellTypes { MWMEditorCellTypeNote }; std::vector<MWMEditorCellID> const kSectionNoteCellTypes{MWMEditorCellTypeNote};
std::vector<MWMEditorCellID> const kSectionButtonCellTypes { MWMEditorCellTypeReportButton }; std::vector<MWMEditorCellID> const kSectionButtonCellTypes{MWMEditorCellTypeReportButton};
std::map<MWMEditorCellID, Class> const kCellType2Class { std::map<MWMEditorCellID, Class> const kCellType2Class{
{MWMEditorCellTypeCategory, [MWMEditorCategoryCell class]}, {MWMEditorCellTypeCategory, [MWMEditorCategoryCell class]},
{MWMEditorCellTypeAdditionalName, [MWMEditorAdditionalNameTableViewCell class]}, {MWMEditorCellTypeAdditionalName, [MWMEditorAdditionalNameTableViewCell class]},
{MWMEditorCellTypeAddAdditionalName, [MWMEditorAddAdditionalNameTableViewCell class]}, {MWMEditorCellTypeAddAdditionalName, [MWMEditorAddAdditionalNameTableViewCell class]},
@@ -70,8 +69,7 @@ std::map<MWMEditorCellID, Class> const kCellType2Class {
{MetadataID::FMD_SELF_SERVICE, [MWMEditorSegmentedTableViewCell class]}, {MetadataID::FMD_SELF_SERVICE, [MWMEditorSegmentedTableViewCell class]},
{MetadataID::FMD_OUTDOOR_SEATING, [MWMEditorSegmentedTableViewCell class]}, {MetadataID::FMD_OUTDOOR_SEATING, [MWMEditorSegmentedTableViewCell class]},
{MWMEditorCellTypeNote, [MWMNoteCell class]}, {MWMEditorCellTypeNote, [MWMNoteCell class]},
{MWMEditorCellTypeReportButton, [MWMButtonCell class]} {MWMEditorCellTypeReportButton, [MWMButtonCell class]}};
};
// Default class, if no entry in kCellType2Class. // Default class, if no entry in kCellType2Class.
Class kDefaultCellTypeClass = [MWMEditorTextTableViewCell class]; Class kDefaultCellTypeClass = [MWMEditorTextTableViewCell class];
/// @return kDefaultCellTypeClass if cellType not specified in kCellType2Class. /// @return kDefaultCellTypeClass if cellType not specified in kCellType2Class.
@@ -87,16 +85,15 @@ void cleanupAdditionalLanguages(std::vector<osm::LocalizedName> const & names,
std::vector<NSInteger> & newAdditionalLanguages) std::vector<NSInteger> & newAdditionalLanguages)
{ {
base::EraseIf(newAdditionalLanguages, [&names](NSInteger x) base::EraseIf(newAdditionalLanguages, [&names](NSInteger x)
{ {
auto it = find_if(names.begin(), names.end(), auto it = find_if(names.begin(), names.end(), [x](osm::LocalizedName const & name) { return name.m_code == x; });
[x](osm::LocalizedName const & name) { return name.m_code == x; }); return it != names.end();
return it != names.end(); });
});
} }
std::vector<MWMEditorCellID> cellsForAdditionalNames(osm::NamesDataSource const & ds, std::vector<MWMEditorCellID> cellsForAdditionalNames(osm::NamesDataSource const & ds,
std::vector<NSInteger> const & newAdditionalLanguages, std::vector<NSInteger> const & newAdditionalLanguages,
BOOL showAdditionalNames) BOOL showAdditionalNames)
{ {
std::vector<MWMEditorCellID> res; std::vector<MWMEditorCellID> res;
auto const allNamesSize = ds.names.size() + newAdditionalLanguages.size(); auto const allNamesSize = ds.names.size() + newAdditionalLanguages.size();
@@ -125,11 +122,19 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
} }
} // namespace } // namespace
@interface MWMEditorViewController ()< @interface MWMEditorViewController () <UITableViewDelegate,
UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, MWMOpeningHoursEditorProtocol, UITableViewDataSource,
MWMPlacePageOpeningHoursCellProtocol, MWMEditorCellProtocol, MWMCuisineEditorProtocol, UITextFieldDelegate,
MWMStreetEditorProtocol, MWMObjectsCategorySelectorDelegate, MWMNoteCellDelegate, MWMOpeningHoursEditorProtocol,
MWMEditorAdditionalName, MWMButtonCellDelegate, MWMEditorAdditionalNamesProtocol> MWMPlacePageOpeningHoursCellProtocol,
MWMEditorCellProtocol,
MWMCuisineEditorProtocol,
MWMStreetEditorProtocol,
MWMObjectsCategorySelectorDelegate,
MWMNoteCellDelegate,
MWMEditorAdditionalName,
MWMButtonCellDelegate,
MWMEditorAdditionalNamesProtocol>
@property(nonatomic) NSMutableDictionary<Class, UITableViewCell *> * offscreenCells; @property(nonatomic) NSMutableDictionary<Class, UITableViewCell *> * offscreenCells;
@property(nonatomic) NSMutableArray<NSIndexPath *> * invalidCells; @property(nonatomic) NSMutableArray<NSIndexPath *> * invalidCells;
@@ -163,9 +168,9 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
if (self.isCreating) if (self.isCreating)
{ {
self.navigationItem.leftBarButtonItem = self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self target:self
action:@selector(onCancel)]; action:@selector(onCancel)];
} }
} }
@@ -191,8 +196,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
- (void)configNavBar - (void)configNavBar
{ {
self.title = self.title = L(self.isCreating ? @"editor_add_place_title" : @"editor_edit_place_title");
L(self.isCreating ? @"editor_add_place_title" : @"editor_edit_place_title");
self.navigationItem.rightBarButtonItem = self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self target:self
@@ -234,9 +238,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
switch (f.SaveEditedMapObject(m_mapObject)) switch (f.SaveEditedMapObject(m_mapObject))
{ {
case osm::Editor::SaveResult::NoUnderlyingMapError: case osm::Editor::SaveResult::NoUnderlyingMapError:
case osm::Editor::SaveResult::SavingError: case osm::Editor::SaveResult::SavingError: [self.navigationController popToRootViewControllerAnimated:YES]; break;
[self.navigationController popToRootViewControllerAnimated:YES];
break;
case osm::Editor::SaveResult::NothingWasChanged: case osm::Editor::SaveResult::NothingWasChanged:
[self.navigationController popToRootViewControllerAnimated:YES]; [self.navigationController popToRootViewControllerAnimated:YES];
if (haveNote) if (haveNote)
@@ -247,9 +249,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
f.UpdatePlacePageInfoForCurrentSelection(); f.UpdatePlacePageInfoForCurrentSelection();
[self.navigationController popToRootViewControllerAnimated:YES]; [self.navigationController popToRootViewControllerAnimated:YES];
break; break;
case osm::Editor::SaveResult::NoFreeSpaceError: case osm::Editor::SaveResult::NoFreeSpaceError: [self.alertController presentNotEnoughSpaceAlert]; break;
[self.alertController presentNotEnoughSpaceAlert];
break;
} }
} }
@@ -289,8 +289,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
_showAdditionalNames = showAdditionalNames; _showAdditionalNames = showAdditionalNames;
[self.additionalNamesHeader setShowAdditionalNames:showAdditionalNames]; [self.additionalNamesHeader setShowAdditionalNames:showAdditionalNames];
[self configTable]; [self configTable];
auto const additionalNamesSectionIt = auto const additionalNamesSectionIt = find(m_sections.begin(), m_sections.end(), MWMEditorSectionAdditionalNames);
find(m_sections.begin(), m_sections.end(), MWMEditorSectionAdditionalNames);
if (additionalNamesSectionIt == m_sections.end()) if (additionalNamesSectionIt == m_sections.end())
{ {
[self.tableView reloadData]; [self.tableView reloadData];
@@ -330,10 +329,10 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
BOOL const isAddressEditable = m_mapObject.IsAddressEditable(); BOOL const isAddressEditable = m_mapObject.IsAddressEditable();
auto editableProperties = m_mapObject.GetEditableProperties(); auto editableProperties = m_mapObject.GetEditableProperties();
// Remove fields that are already displayed in the Address section. // Remove fields that are already displayed in the Address section.
editableProperties.erase(std::remove_if(editableProperties.begin(), editableProperties.end(), [](osm::MapObject::MetadataID mid) editableProperties.erase(
{ std::remove_if(editableProperties.begin(), editableProperties.end(), [](osm::MapObject::MetadataID mid)
return mid == MetadataID::FMD_POSTCODE || mid == MetadataID::FMD_BUILDING_LEVELS; { return mid == MetadataID::FMD_POSTCODE || mid == MetadataID::FMD_BUILDING_LEVELS; }),
}), editableProperties.end()); editableProperties.end());
BOOL const isCreating = self.isCreating; BOOL const isCreating = self.isCreating;
BOOL const showNotesToOSMEditors = YES; BOOL const showNotesToOSMEditors = YES;
@@ -342,8 +341,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
auto const ds = m_mapObject.GetNamesDataSource(); auto const ds = m_mapObject.GetNamesDataSource();
auto const & localizedNames = ds.names; auto const & localizedNames = ds.names;
cleanupAdditionalLanguages(localizedNames, m_newAdditionalLanguages); cleanupAdditionalLanguages(localizedNames, m_newAdditionalLanguages);
auto const cells = auto const cells = cellsForAdditionalNames(ds, m_newAdditionalLanguages, self.showAdditionalNames);
cellsForAdditionalNames(ds, m_newAdditionalLanguages, self.showAdditionalNames);
m_sections.push_back(MWMEditorSectionAdditionalNames); m_sections.push_back(MWMEditorSectionAdditionalNames);
m_cells[MWMEditorSectionAdditionalNames] = cells; m_cells[MWMEditorSectionAdditionalNames] = cells;
registerCellsForTableView(cells, self.tableView); registerCellsForTableView(cells, self.tableView);
@@ -419,7 +417,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
placeholder:(NSString * _Nonnull)name placeholder:(NSString * _Nonnull)name
{ {
MetadataID metaId = static_cast<MetadataID>(cellID); MetadataID metaId = static_cast<MetadataID>(cellID);
NSString* value = ToNSString(m_mapObject.GetMetadata(metaId)); NSString * value = ToNSString(m_mapObject.GetMetadata(metaId));
if (osm::isSocialContactTag(metaId) && [value containsString:@"/"]) if (osm::isSocialContactTag(metaId) && [value containsString:@"/"])
value = ToNSString(osm::socialContactToURL(metaId, [value UTF8String])); value = ToNSString(osm::socialContactToURL(metaId, [value UTF8String]));
@@ -523,13 +521,13 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
} }
case MWMEditorCellTypeAdditionalName: case MWMEditorCellTypeAdditionalName:
{ {
MWMEditorAdditionalNameTableViewCell * tCell = MWMEditorAdditionalNameTableViewCell * tCell = static_cast<MWMEditorAdditionalNameTableViewCell *>(cell);
static_cast<MWMEditorAdditionalNameTableViewCell *>(cell);
auto const & localizedNames = m_mapObject.GetNamesDataSource().names; auto const & localizedNames = m_mapObject.GetNamesDataSource().names;
if (indexPath.row < localizedNames.size()) if (indexPath.row < localizedNames.size())
{ {
osm::LocalizedName const & name = localizedNames[indexPath.row]; osm::LocalizedName const & name = localizedNames[indexPath.row];
NSString * langName = indexPath.row == StringUtf8Multilang::kDefaultCode ? L(@"editor_default_language_hint") : ToNSString(name.m_langName); NSString * langName = indexPath.row == StringUtf8Multilang::kDefaultCode ? L(@"editor_default_language_hint")
: ToNSString(name.m_langName);
[tCell configWithDelegate:self [tCell configWithDelegate:self
langCode:name.m_code langCode:name.m_code
langName:langName langName:langName
@@ -546,9 +544,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
std::string name; std::string name;
// Default name can be changed in advanced mode. // Default name can be changed in advanced mode.
if (langCode == StringUtf8Multilang::kDefaultCode) if (langCode == StringUtf8Multilang::kDefaultCode)
{
name = m_mapObject.GetDefaultName(); name = m_mapObject.GetDefaultName();
}
[tCell configWithDelegate:self [tCell configWithDelegate:self
langCode:langCode langCode:langCode
@@ -597,17 +593,16 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
errorMessage:L(@"error_enter_correct_zip_code") errorMessage:L(@"error_enter_correct_zip_code")
isValid:isValid isValid:isValid
keyboardType:UIKeyboardTypeDefault]; keyboardType:UIKeyboardTypeDefault];
static_cast<MWMEditorTextTableViewCell *>(cell).textField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; static_cast<MWMEditorTextTableViewCell *>(cell).textField.autocapitalizationType =
UITextAutocapitalizationTypeAllCharacters;
break; break;
} }
case MetadataID::FMD_BUILDING_LEVELS: case MetadataID::FMD_BUILDING_LEVELS:
{ {
NSString * placeholder = NSString * placeholder =
[NSString stringWithFormat:L(@"editor_storey_number"), [NSString stringWithFormat:L(@"editor_storey_number"), osm::EditableMapObject::kMaximumLevelsEditableByUsers];
osm::EditableMapObject::kMaximumLevelsEditableByUsers]; NSString * errorMessage = [NSString stringWithFormat:L(@"error_enter_correct_storey_number"),
NSString * errorMessage = osm::EditableMapObject::kMaximumLevelsEditableByUsers];
[NSString stringWithFormat:L(@"error_enter_correct_storey_number"),
osm::EditableMapObject::kMaximumLevelsEditableByUsers];
[self configTextViewCell:cell [self configTextViewCell:cell
cellID:cellID cellID:cellID
icon:nil icon:nil
@@ -620,9 +615,8 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
case MetadataID::FMD_LEVEL: case MetadataID::FMD_LEVEL:
{ {
/// @todo Is it ok to use the same error string as in building levels? /// @todo Is it ok to use the same error string as in building levels?
NSString * errorMessage = NSString * errorMessage = [NSString stringWithFormat:L(@"error_enter_correct_storey_number"),
[NSString stringWithFormat:L(@"error_enter_correct_storey_number"), osm::EditableMapObject::kMaximumLevelsEditableByUsers];
osm::EditableMapObject::kMaximumLevelsEditableByUsers];
[self configTextViewCell:cell [self configTextViewCell:cell
cellID:cellID cellID:cellID
@@ -648,7 +642,8 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
[tCell configWithDelegate:self [tCell configWithDelegate:self
icon:[UIImage imageNamed:@"ic_placepage_drive_through"] icon:[UIImage imageNamed:@"ic_placepage_drive_through"]
text:L(@"drive_through") text:L(@"drive_through")
value:feature::YesNoUnknownFromString(m_mapObject.GetMetadata(feature::Metadata::FMD_DRIVE_THROUGH))]; value:feature::YesNoUnknownFromString(
m_mapObject.GetMetadata(feature::Metadata::FMD_DRIVE_THROUGH))];
break; break;
} }
case MetadataID::FMD_SELF_SERVICE: case MetadataID::FMD_SELF_SERVICE:
@@ -657,7 +652,8 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
[tCell configWithDelegate:self [tCell configWithDelegate:self
icon:[UIImage imageNamed:@"ic_placepage_self_service"] icon:[UIImage imageNamed:@"ic_placepage_self_service"]
text:L(@"self_service") text:L(@"self_service")
value:feature::YesNoUnknownFromString(m_mapObject.GetMetadata(feature::Metadata::FMD_SELF_SERVICE))]; value:feature::YesNoUnknownFromString(
m_mapObject.GetMetadata(feature::Metadata::FMD_SELF_SERVICE))];
break; break;
} }
case MetadataID::FMD_OUTDOOR_SEATING: case MetadataID::FMD_OUTDOOR_SEATING:
@@ -666,79 +662,56 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
[tCell configWithDelegate:self [tCell configWithDelegate:self
icon:[UIImage imageNamed:@"ic_placepage_outdoor_seating"] icon:[UIImage imageNamed:@"ic_placepage_outdoor_seating"]
text:L(@"outdoor_seating") text:L(@"outdoor_seating")
value:feature::YesNoUnknownFromString(m_mapObject.GetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING))]; value:feature::YesNoUnknownFromString(
m_mapObject.GetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING))];
break; break;
} }
case MetadataID::FMD_CONTACT_FEDIVERSE: case MetadataID::FMD_CONTACT_FEDIVERSE:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_fediverse" placeholder:L(@"fediverse")];
cellID:cellID
icon:@"ic_placepage_fediverse"
placeholder:L(@"fediverse")];
break; break;
} }
case MetadataID::FMD_CONTACT_FACEBOOK: case MetadataID::FMD_CONTACT_FACEBOOK:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_facebook" placeholder:L(@"facebook")];
cellID:cellID
icon:@"ic_placepage_facebook"
placeholder:L(@"facebook")];
break; break;
} }
case MetadataID::FMD_CONTACT_INSTAGRAM: case MetadataID::FMD_CONTACT_INSTAGRAM:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_instagram" placeholder:L(@"instagram")];
cellID:cellID
icon:@"ic_placepage_instagram"
placeholder:L(@"instagram")];
break; break;
} }
case MetadataID::FMD_CONTACT_TWITTER: case MetadataID::FMD_CONTACT_TWITTER:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_twitter" placeholder:L(@"twitter")];
cellID:cellID
icon:@"ic_placepage_twitter"
placeholder:L(@"twitter")];
break; break;
} }
case MetadataID::FMD_CONTACT_VK: case MetadataID::FMD_CONTACT_VK:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_vk" placeholder:L(@"vk")];
cellID:cellID
icon:@"ic_placepage_vk"
placeholder:L(@"vk")];
break; break;
} }
case MetadataID::FMD_CONTACT_LINE: case MetadataID::FMD_CONTACT_LINE:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_line" placeholder:L(@"line")];
cellID:cellID
icon:@"ic_placepage_line"
placeholder:L(@"line")];
break; break;
} }
case MetadataID::FMD_CONTACT_BLUESKY: case MetadataID::FMD_CONTACT_BLUESKY:
{ {
[self configTextViewCell:cell [self configTextViewCell:cell cellID:cellID icon:@"ic_placepage_bluesky" placeholder:L(@"bluesky")];
cellID:cellID
icon:@"ic_placepage_bluesky"
placeholder:L(@"bluesky")];
break; break;
} }
case MWMEditorCellTypeNote: case MWMEditorCellTypeNote:
{ {
MWMNoteCell * tCell = static_cast<MWMNoteCell *>(cell); MWMNoteCell * tCell = static_cast<MWMNoteCell *>(cell);
[tCell configWithDelegate:self [tCell configWithDelegate:self noteText:self.note placeholder:L(@"editor_detailed_description_hint")];
noteText:self.note
placeholder:L(@"editor_detailed_description_hint")];
break; break;
} }
case MWMEditorCellTypeReportButton: case MWMEditorCellTypeReportButton:
{ {
MWMButtonCell * tCell = static_cast<MWMButtonCell *>(cell); MWMButtonCell * tCell = static_cast<MWMButtonCell *>(cell);
auto title = ^NSString *(FeatureStatus s, BOOL isUploaded) auto title = ^NSString *(FeatureStatus s, BOOL isUploaded) {
{
if (isUploaded) if (isUploaded)
return L(@"editor_place_doesnt_exist"); return L(@"editor_place_doesnt_exist");
switch (s) switch (s)
@@ -753,12 +726,10 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
} }
}; };
[tCell configureWithDelegate:self title:title(self.featureStatus, self.isFeatureUploaded) enabled: YES]; [tCell configureWithDelegate:self title:title(self.featureStatus, self.isFeatureUploaded) enabled:YES];
break; break;
} }
default: default: NSAssert(false, @"Invalid field for editor: %d", (int)cellID); break;
NSAssert(false, @"Invalid field for editor: %d", (int)cellID);
break;
} }
} }
@@ -785,8 +756,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
#pragma mark - UITableViewDelegate #pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView * _Nonnull)tableView - (CGFloat)tableView:(UITableView * _Nonnull)tableView heightForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
heightForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{ {
Class cls = [self cellClassForIndexPath:indexPath]; Class cls = [self cellClassForIndexPath:indexPath];
auto cell = [self offscreenCellForClass:cls]; auto cell = [self offscreenCellForClass:cls];
@@ -861,8 +831,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
{ {
switch (m_sections[section]) switch (m_sections[section])
{ {
case MWMEditorSectionAddress: case MWMEditorSectionAddress: return 1.0;
return 1.0;
case MWMEditorSectionDetails: case MWMEditorSectionDetails:
if (find(m_sections.begin(), m_sections.end(), MWMEditorSectionNote) == m_sections.end()) if (find(m_sections.begin(), m_sections.end(), MWMEditorSectionNote) == m_sections.end())
return self.notesFooter.height; return self.notesFooter.height;
@@ -876,10 +845,22 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
#pragma mark - MWMPlacePageOpeningHoursCellProtocol #pragma mark - MWMPlacePageOpeningHoursCellProtocol
- (BOOL)forcedButton { return YES; } - (BOOL)forcedButton
- (BOOL)isPlaceholder { return m_mapObject.GetOpeningHours().empty(); } {
- (BOOL)isEditor { return YES; } return YES;
- (BOOL)openingHoursCellExpanded { return YES; } }
- (BOOL)isPlaceholder
{
return m_mapObject.GetOpeningHours().empty();
}
- (BOOL)isEditor
{
return YES;
}
- (BOOL)openingHoursCellExpanded
{
return YES;
}
- (void)setOpeningHoursCellExpanded:(BOOL)openingHoursCellExpanded - (void)setOpeningHoursCellExpanded:(BOOL)openingHoursCellExpanded
{ {
[self performSegueWithIdentifier:kOpeningHoursEditorSegue sender:nil]; [self performSegueWithIdentifier:kOpeningHoursEditorSegue sender:nil];
@@ -890,8 +871,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
if (![self.invalidCells containsObject:indexPath]) if (![self.invalidCells containsObject:indexPath])
[self.invalidCells addObject:indexPath]; [self.invalidCells addObject:indexPath];
[self.tableView reloadRowsAtIndexPaths:@[ indexPath ] [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
withRowAnimation:UITableViewRowAnimationFade];
} }
#pragma mark - MWMNoteCellDelegate #pragma mark - MWMNoteCellDelegate
@@ -908,7 +888,10 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
}); });
} }
- (void)cell:(MWMNoteCell *)cell didFinishEditingWithText:(NSString *)text { self.note = text; } - (void)cell:(MWMNoteCell *)cell didFinishEditingWithText:(NSString *)text
{
self.note = text;
}
#pragma mark - MWMEditorAdditionalName #pragma mark - MWMEditorAdditionalName
- (void)editAdditionalNameLanguage:(NSInteger)selectedLangCode - (void)editAdditionalNameLanguage:(NSInteger)selectedLangCode
@@ -922,16 +905,13 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
{ {
m_newAdditionalLanguages.push_back(languageIndex); m_newAdditionalLanguages.push_back(languageIndex);
self.showAdditionalNames = YES; self.showAdditionalNames = YES;
auto additionalNamesSectionIt = auto additionalNamesSectionIt = find(m_sections.begin(), m_sections.end(), MWMEditorSectionAdditionalNames);
find(m_sections.begin(), m_sections.end(), MWMEditorSectionAdditionalNames);
assert(additionalNamesSectionIt != m_sections.end()); assert(additionalNamesSectionIt != m_sections.end());
auto const section = distance(m_sections.begin(), additionalNamesSectionIt); auto const section = distance(m_sections.begin(), additionalNamesSectionIt);
NSInteger const row = [self tableView:self.tableView numberOfRowsInSection:section]; NSInteger const row = [self tableView:self.tableView numberOfRowsInSection:section];
assert(row > 0); assert(row > 0);
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row - 1 inSection:section]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row - 1 inSection:section];
[self.tableView scrollToRowAtIndexPath:indexPath [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
atScrollPosition:UITableViewScrollPositionMiddle
animated:NO];
} }
#pragma mark - MWMEditorCellProtocol #pragma mark - MWMEditorCellProtocol
@@ -965,7 +945,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
default: default:
auto const metadataID = static_cast<MetadataID>(cellType); auto const metadataID = static_cast<MetadataID>(cellType);
ASSERT_LESS(metadataID, MetadataID::FMD_COUNT, ()); ASSERT_LESS(metadataID, MetadataID::FMD_COUNT, ());
isFieldValid = osm::EditableMapObject::IsValidMetadata(metadataID, val)? YES : NO; isFieldValid = osm::EditableMapObject::IsValidMetadata(metadataID, val) ? YES : NO;
m_mapObject.SetMetadata(metadataID, std::move(val)); m_mapObject.SetMetadata(metadataID, std::move(val));
break; break;
} }
@@ -992,49 +972,31 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
switch ([self cellTypeForIndexPath:indexPath]) switch ([self cellTypeForIndexPath:indexPath])
{ {
case MetadataID::FMD_DRIVE_THROUGH: case MetadataID::FMD_DRIVE_THROUGH:
switch (changeSegmented) switch (changeSegmented)
{ {
case Yes: case Yes: m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, "yes"); break;
m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, "yes"); case No: m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, "no"); break;
break; case Unknown: m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, ""); break;
case No: }
m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, "no"); break;
break;
case Unknown:
m_mapObject.SetMetadata(feature::Metadata::FMD_DRIVE_THROUGH, "");
break;
}
break;
case MetadataID::FMD_SELF_SERVICE: case MetadataID::FMD_SELF_SERVICE:
switch (changeSegmented) switch (changeSegmented)
{ {
case Yes: case Yes: m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, "yes"); break;
m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, "yes"); case No: m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, "no"); break;
break; case Unknown: m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, ""); break;
case No: }
m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, "no"); break;
break;
case Unknown:
m_mapObject.SetMetadata(feature::Metadata::FMD_SELF_SERVICE, "");
break;
}
break;
case MetadataID::FMD_OUTDOOR_SEATING: case MetadataID::FMD_OUTDOOR_SEATING:
switch (changeSegmented) switch (changeSegmented)
{ {
case Yes: case Yes: m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, "yes"); break;
m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, "yes"); case No: m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, "no"); break;
break; case Unknown: m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, ""); break;
case No: }
m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, "no"); break;
break;
case Unknown:
m_mapObject.SetMetadata(feature::Metadata::FMD_OUTDOOR_SEATING, "");
break;
}
break;
default: NSAssert(false, @"Invalid field for changeSegmented"); break; default: NSAssert(false, @"Invalid field for changeSegmented"); break;
} }
@@ -1047,15 +1009,9 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
NSIndexPath * indexPath = [self.tableView indexPathForCell:cell]; NSIndexPath * indexPath = [self.tableView indexPathForCell:cell];
switch ([self cellTypeForIndexPath:indexPath]) switch ([self cellTypeForIndexPath:indexPath])
{ {
case MWMEditorCellTypeStreet: case MWMEditorCellTypeStreet: [self performSegueWithIdentifier:kStreetEditorSegue sender:nil]; break;
[self performSegueWithIdentifier:kStreetEditorSegue sender:nil]; case MetadataID::FMD_CUISINE: [self performSegueWithIdentifier:kCuisineEditorSegue sender:nil]; break;
break; case MWMEditorCellTypeCategory: [self performSegueWithIdentifier:kCategoryEditorSegue sender:nil]; break;
case MetadataID::FMD_CUISINE:
[self performSegueWithIdentifier:kCuisineEditorSegue sender:nil];
break;
case MWMEditorCellTypeCategory:
[self performSegueWithIdentifier:kCategoryEditorSegue sender:nil];
break;
case MWMEditorCellTypeReportButton: [self tapOnButtonCell:cell]; break; case MWMEditorCellTypeReportButton: [self tapOnButtonCell:cell]; break;
default: NSAssert(false, @"Invalid field for cellSelect"); break; default: NSAssert(false, @"Invalid field for cellSelect"); break;
} }
@@ -1066,13 +1022,12 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
auto const & fid = m_mapObject.GetID(); auto const & fid = m_mapObject.GetID();
self.isFeatureUploaded = osm::Editor::Instance().IsFeatureUploaded(fid.m_mwmId, fid.m_index); self.isFeatureUploaded = osm::Editor::Instance().IsFeatureUploaded(fid.m_mwmId, fid.m_index);
NSIndexPath * ip = [self.tableView indexPathForCell:cell]; NSIndexPath * ip = [self.tableView indexPathForCell:cell];
[self.tableView reloadRowsAtIndexPaths:@[ ip ] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView reloadRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade];
auto placeDoesntExistAction = ^{ auto placeDoesntExistAction = ^{
[self.alertController presentPlaceDoesntExistAlertWithBlock:^(NSString * additionalMessage) { [self.alertController presentPlaceDoesntExistAlertWithBlock:^(NSString * additionalMessage) {
std::string const additional = additionalMessage.length ? additionalMessage.UTF8String : ""; std::string const additional = additionalMessage.length ? additionalMessage.UTF8String : "";
GetFramework().CreateNote(self->m_mapObject, osm::Editor::NoteProblemType::PlaceDoesNotExist, GetFramework().CreateNote(self->m_mapObject, osm::Editor::NoteProblemType::PlaceDoesNotExist, additional);
additional);
[self goBack]; [self goBack];
[self showNotesQueuedToast]; [self showNotesQueuedToast];
}]; }];
@@ -1098,16 +1053,12 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
case FeatureStatus::Untouched: placeDoesntExistAction(); break; case FeatureStatus::Untouched: placeDoesntExistAction(); break;
case FeatureStatus::Modified: case FeatureStatus::Modified:
{ {
[self.alertController presentResetChangesAlertWithBlock:^{ [self.alertController presentResetChangesAlertWithBlock:^{ revertAction(NO); }];
revertAction(NO);
}];
break; break;
} }
case FeatureStatus::Created: case FeatureStatus::Created:
{ {
[self.alertController presentDeleteFeatureAlertWithBlock:^{ [self.alertController presentDeleteFeatureAlertWithBlock:^{ revertAction(YES); }];
revertAction(YES);
}];
break; break;
} }
case FeatureStatus::Deleted: break; case FeatureStatus::Deleted: break;
@@ -1133,13 +1084,28 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
#pragma mark - MWMCuisineEditorProtocol #pragma mark - MWMCuisineEditorProtocol
- (std::vector<std::string>)selectedCuisines { return m_mapObject.GetCuisines(); } - (std::vector<std::string>)selectedCuisines
- (void)setSelectedCuisines:(std::vector<std::string> const &)cuisines { m_mapObject.SetCuisines(cuisines); } {
return m_mapObject.GetCuisines();
}
- (void)setSelectedCuisines:(std::vector<std::string> const &)cuisines
{
m_mapObject.SetCuisines(cuisines);
}
#pragma mark - MWMStreetEditorProtocol #pragma mark - MWMStreetEditorProtocol
- (void)setNearbyStreet:(osm::LocalizedStreet const &)street { m_mapObject.SetStreet(street); } - (void)setNearbyStreet:(osm::LocalizedStreet const &)street
- (osm::LocalizedStreet const &)currentStreet { return m_mapObject.GetStreet(); } {
- (std::vector<osm::LocalizedStreet> const &)nearbyStreets { return m_mapObject.GetNearbyStreets(); } m_mapObject.SetStreet(street);
}
- (osm::LocalizedStreet const &)currentStreet
{
return m_mapObject.GetStreet();
}
- (std::vector<osm::LocalizedStreet> const &)nearbyStreets
{
return m_mapObject.GetNearbyStreets();
}
#pragma mark - Segue #pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
@@ -1173,7 +1139,9 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
else if ([segue.identifier isEqualToString:kAdditionalNamesEditorSegue]) else if ([segue.identifier isEqualToString:kAdditionalNamesEditorSegue])
{ {
MWMEditorAdditionalNamesTableViewController * dvc = segue.destinationViewController; MWMEditorAdditionalNamesTableViewController * dvc = segue.destinationViewController;
[dvc configWithDelegate:self name:m_mapObject.GetNameMultilang() additionalSkipLanguageCodes:m_newAdditionalLanguages]; [dvc configWithDelegate:self
name:m_mapObject.GetNameMultilang()
additionalSkipLanguageCodes:m_newAdditionalLanguages];
} }
} }
@@ -1185,8 +1153,7 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
if ([ud boolForKey:kUDEditorPersonalInfoWarninWasShown]) if ([ud boolForKey:kUDEditorPersonalInfoWarninWasShown])
return NO; return NO;
[self.alertController presentPersonalInfoWarningAlertWithBlock:^ [self.alertController presentPersonalInfoWarningAlertWithBlock:^{
{
[ud setBool:YES forKey:kUDEditorPersonalInfoWarninWasShown]; [ud setBool:YES forKey:kUDEditorPersonalInfoWarninWasShown];
[self onSave]; [self onSave];
}]; }];

View File

@@ -1,7 +1,7 @@
#import "MWMObjectsCategorySelectorController.h" #import "MWMObjectsCategorySelectorController.h"
#import "MWMObjectsCategorySelectorDataSource.h"
#import "MWMEditorViewController.h" #import "MWMEditorViewController.h"
#import "MWMKeyboard.h" #import "MWMKeyboard.h"
#import "MWMObjectsCategorySelectorDataSource.h"
#import "MWMTableViewCell.h" #import "MWMTableViewCell.h"
#import "SwiftBridge.h" #import "SwiftBridge.h"
@@ -14,10 +14,11 @@ namespace
NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue"; NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
} // namespace } // namespace
@interface MWMObjectsCategorySelectorController ()<UISearchBarDelegate, UITableViewDelegate, @interface MWMObjectsCategorySelectorController () <UISearchBarDelegate,
UITableViewDataSource, MWMKeyboardObserver> UITableViewDelegate,
{ UITableViewDataSource,
} MWMKeyboardObserver>
{}
@property(weak, nonatomic) IBOutlet UITableView * tableView; @property(weak, nonatomic) IBOutlet UITableView * tableView;
@property(weak, nonatomic) IBOutlet UISearchBar * searchBar; @property(weak, nonatomic) IBOutlet UISearchBar * searchBar;
@@ -50,8 +51,7 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
- (void)configTable - (void)configTable
{ {
[self.tableView registerClass:[MWMTableViewCell class] [self.tableView registerClass:[MWMTableViewCell class] forCellReuseIdentifier:[UITableViewCell className]];
forCellReuseIdentifier:[UITableViewCell className]];
} }
- (void)setSelectedCategory:(std::string const &)type - (void)setSelectedCategory:(std::string const &)type
@@ -64,7 +64,10 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
return UIStatusBarStyleLightContent; return UIStatusBarStyleLightContent;
} }
- (void)configNavBar { self.title = L(@"editor_add_select_category"); } - (void)configNavBar
{
self.title = L(@"editor_add_select_category");
}
- (void)configSearchBar - (void)configSearchBar
{ {
self.searchBar.placeholder = L(@"search"); self.searchBar.placeholder = L(@"search");
@@ -79,7 +82,7 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
stackView.spacing = 12; stackView.spacing = 12;
self.searchResultsIsEmptyDisclaimer = stackView; self.searchResultsIsEmptyDisclaimer = stackView;
UILabel *titleLabel = [[UILabel alloc] init]; UILabel * titleLabel = [[UILabel alloc] init];
titleLabel.text = L(@"editor_category_unsuitable_title"); titleLabel.text = L(@"editor_category_unsuitable_title");
titleLabel.font = [UIFont boldSystemFontOfSize:20]; titleLabel.font = [UIFont boldSystemFontOfSize:20];
titleLabel.textAlignment = NSTextAlignmentCenter; titleLabel.textAlignment = NSTextAlignmentCenter;
@@ -94,31 +97,38 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
subtitleTextView.backgroundColor = [UIColor clearColor]; subtitleTextView.backgroundColor = [UIColor clearColor];
subtitleTextView.textContainerInset = UIEdgeInsetsZero; subtitleTextView.textContainerInset = UIEdgeInsetsZero;
NSString *subtitleHTML = L(@"editor_category_unsuitable_text"); NSString * subtitleHTML = L(@"editor_category_unsuitable_text");
NSData *htmlData = [subtitleHTML dataUsingEncoding:NSUnicodeStringEncoding]; NSData * htmlData = [subtitleHTML dataUsingEncoding:NSUnicodeStringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}; NSDictionary * options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSError *error = nil; NSError * error = nil;
NSAttributedString *attributedText = NSAttributedString * attributedText = [[NSAttributedString alloc] initWithData:htmlData
[[NSAttributedString alloc] initWithData:htmlData options:options
options:options documentAttributes:nil
documentAttributes:nil error:&error];
error:&error]; if (error)
if (error) { {
LOG(LERROR, ("Error parsing HTML:", error.localizedDescription)); LOG(LERROR, ("Error parsing HTML:", error.localizedDescription));
} else { }
else
{
UIColor * textColor; UIColor * textColor;
if (@available(iOS 13.0, *)) { if (@available(iOS 13.0, *))
textColor = [[UIColor alloc] initWithDynamicProvider:^UIColor * (UITraitCollection * traitCollection) { {
return traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? UIColor.whitePrimaryText : UIColor.blackPrimaryText; textColor = [[UIColor alloc] initWithDynamicProvider:^UIColor *(UITraitCollection * traitCollection) {
return traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? UIColor.whitePrimaryText
: UIColor.blackPrimaryText;
}]; }];
} else { }
else
{
textColor = UIColor.blackPrimaryText; textColor = UIColor.blackPrimaryText;
} }
NSMutableAttributedString *mutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText]; NSMutableAttributedString * mutableAttributedText =
[mutableAttributedText addAttributes:@{ NSForegroundColorAttributeName: textColor, [[NSMutableAttributedString alloc] initWithAttributedString:attributedText];
NSFontAttributeName: UIFont.regular14} [mutableAttributedText
range:NSMakeRange(0, mutableAttributedText.length)]; addAttributes:@{NSForegroundColorAttributeName: textColor, NSFontAttributeName: UIFont.regular14}
range:NSMakeRange(0, mutableAttributedText.length)];
subtitleTextView.attributedText = mutableAttributedText; subtitleTextView.attributedText = mutableAttributedText;
subtitleTextView.textAlignment = NSTextAlignmentCenter; subtitleTextView.textAlignment = NSTextAlignmentCenter;
} }
@@ -149,8 +159,7 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
NSAssert(false, @"incorrect segue"); NSAssert(false, @"incorrect segue");
return; return;
} }
MWMEditorViewController * dest = MWMEditorViewController * dest = static_cast<MWMEditorViewController *>(segue.destinationViewController);
static_cast<MWMEditorViewController *>(segue.destinationViewController);
dest.isCreating = YES; dest.isCreating = YES;
auto const object = self.createdObject; auto const object = self.createdObject;
[dest setEditableMapObject:object]; [dest setEditableMapObject:object];
@@ -180,11 +189,9 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
#pragma mark - UITableView #pragma mark - UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
auto cell = auto cell = [tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
[tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
cell.textLabel.text = [self.dataSource getTranslation:indexPath.row]; cell.textLabel.text = [self.dataSource getTranslation:indexPath.row];
auto const type = [self.dataSource getType:indexPath.row]; auto const type = [self.dataSource getType:indexPath.row];
if ([type isEqualToString:self.selectedType]) if ([type isEqualToString:self.selectedType])
@@ -269,8 +276,14 @@ NSString * const kToEditorSegue = @"CategorySelectorToEditorSegue";
[self.tableView reloadData]; [self.tableView reloadData];
} }
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; } {
[searchBar resignFirstResponder];
}
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
- (void)searchBar:(UISearchBar *)searchBar setActiveState:(BOOL)isActiveState - (void)searchBar:(UISearchBar *)searchBar setActiveState:(BOOL)isActiveState
{ {
[searchBar setShowsCancelButton:isActiveState animated:YES]; [searchBar setShowsCancelButton:isActiveState animated:YES];

View File

@@ -6,7 +6,6 @@
#include "platform/localization.hpp" #include "platform/localization.hpp"
namespace namespace
{ {
using Category = std::pair<std::string, osm::NewFeatureCategories::TypeName>; using Category = std::pair<std::string, osm::NewFeatureCategories::TypeName>;
@@ -18,7 +17,7 @@ std::string locale()
} }
} // namespace } // namespace
@interface MWMObjectsCategorySelectorDataSource() @interface MWMObjectsCategorySelectorDataSource ()
{ {
osm::NewFeatureCategories m_categories; osm::NewFeatureCategories m_categories;
Categories m_categoriesList; Categories m_categoriesList;
@@ -33,7 +32,7 @@ std::string locale()
self = [super init]; self = [super init];
if (self) if (self)
[self load]; [self load];
return self; return self;
} }
@@ -55,15 +54,15 @@ std::string locale()
auto const & types = m_categories.GetAllCreatableTypeNames(); auto const & types = m_categories.GetAllCreatableTypeNames();
m_categoriesList.reserve(types.size()); m_categoriesList.reserve(types.size());
[self initializeList: types]; [self initializeList:types];
} }
- (void)search:(NSString *)query - (void)search:(NSString *)query
{ {
if (query.length == 0) if (query.length == 0)
[self initializeList: m_categories.GetAllCreatableTypeNames()]; [self initializeList:m_categories.GetAllCreatableTypeNames()];
else else
[self initializeList: m_categories.Search([query UTF8String])]; [self initializeList:m_categories.Search([query UTF8String])];
} }
- (NSString *)getTranslation:(NSInteger)row - (NSString *)getTranslation:(NSInteger)row

View File

@@ -2,7 +2,7 @@
@interface MWMOpeningHoursAddClosedTableViewCell () @interface MWMOpeningHoursAddClosedTableViewCell ()
@property (weak, nonatomic) IBOutlet UIButton * addClosedButton; @property(weak, nonatomic) IBOutlet UIButton * addClosedButton;
@end @end

View File

@@ -3,7 +3,7 @@
@interface MWMOpeningHoursAddScheduleTableViewCell () @interface MWMOpeningHoursAddScheduleTableViewCell ()
@property (weak, nonatomic) IBOutlet UIButton * addScheduleButton; @property(weak, nonatomic) IBOutlet UIButton * addScheduleButton;
@end @end
@@ -22,8 +22,8 @@
- (void)refresh - (void)refresh
{ {
NSString * title = [NSString stringWithFormat:@"%@ %@", L(@"editor_time_add"), NSString * title =
stringFromOpeningDays([self.model unhandledDays])]; [NSString stringWithFormat:@"%@ %@", L(@"editor_time_add"), stringFromOpeningDays([self.model unhandledDays])];
[self.addScheduleButton setTitle:title forState:UIControlStateNormal]; [self.addScheduleButton setTitle:title forState:UIControlStateNormal];
} }

View File

@@ -2,8 +2,8 @@
@interface MWMOpeningHoursAllDayTableViewCell () @interface MWMOpeningHoursAllDayTableViewCell ()
@property (weak, nonatomic) IBOutlet UISwitch * switcher; @property(weak, nonatomic) IBOutlet UISwitch * switcher;
@property (weak, nonatomic) IBOutlet UILabel * label; @property(weak, nonatomic) IBOutlet UILabel * label;
@end @end

View File

@@ -36,7 +36,10 @@ BOOL isCompactForCellWidth(CGFloat width)
@implementation MWMOpeningHoursClosedSpanTableViewCell @implementation MWMOpeningHoursClosedSpanTableViewCell
+ (CGFloat)heightForWidth:(CGFloat)width { return isCompactForCellWidth(width) ? 44.0 : 64.0; } + (CGFloat)heightForWidth:(CGFloat)width
{
return isCompactForCellWidth(width) ? 44.0 : 64.0;
}
- (void)awakeFromNib - (void)awakeFromNib
{ {
[super awakeFromNib]; [super awakeFromNib];
@@ -92,7 +95,10 @@ BOOL isCompactForCellWidth(CGFloat width)
#pragma mark - Actions #pragma mark - Actions
- (IBAction)cancelTap { [self.section removeClosedTime:self.row]; } - (IBAction)cancelTap
{
[self.section removeClosedTime:self.row];
}
- (IBAction)expandTap - (IBAction)expandTap
{ {
if (!self.isVisible) if (!self.isVisible)

View File

@@ -3,11 +3,11 @@
@interface MWMOpeningHoursDaysSelectorTableViewCell () @interface MWMOpeningHoursDaysSelectorTableViewCell ()
@property (nonatomic) IBOutletCollection(UIButton) NSArray * buttons; @property(nonatomic) IBOutletCollection(UIButton) NSArray * buttons;
@property (nonatomic) IBOutletCollection(UILabel) NSArray * labels; @property(nonatomic) IBOutletCollection(UILabel) NSArray * labels;
@property (nonatomic) IBOutletCollection(UIImageView) NSArray * images; @property(nonatomic) IBOutletCollection(UIImageView) NSArray * images;
@property (nonatomic) NSUInteger firstWeekday; @property(nonatomic) NSUInteger firstWeekday;
@end @end
@@ -28,9 +28,7 @@ using namespace osmoh;
self.firstWeekday = cal.firstWeekday; self.firstWeekday = cal.firstWeekday;
NSArray<NSString *> * weekdaySymbols = cal.shortStandaloneWeekdaySymbols; NSArray<NSString *> * weekdaySymbols = cal.shortStandaloneWeekdaySymbols;
for (UILabel * label in self.labels) for (UILabel * label in self.labels)
{
label.text = weekdaySymbols[[self tag2SymbolIndex:label.tag]]; label.text = weekdaySymbols[[self tag2SymbolIndex:label.tag]];
}
} }
- (NSUInteger)tag2SymbolIndex:(NSUInteger)tag - (NSUInteger)tag2SymbolIndex:(NSUInteger)tag
@@ -59,21 +57,17 @@ using namespace osmoh;
[section removeSelectedDay:wd]; [section removeSelectedDay:wd];
} }
for (UIButton * btn in self.buttons) for (UIButton * btn in self.buttons)
{
if (btn.tag == tag) if (btn.tag == tag)
btn.selected = selected; btn.selected = selected;
}
for (UILabel * label in self.labels) for (UILabel * label in self.labels)
{
if (label.tag == tag) if (label.tag == tag)
label.textColor = (selected ? [UIColor blackPrimaryText] : [UIColor blackHintText]); label.textColor = (selected ? [UIColor blackPrimaryText] : [UIColor blackHintText]);
}
for (UIImageView * image in self.images) for (UIImageView * image in self.images)
{ {
if (image.tag == tag) if (image.tag == tag)
{ {
image.image = [UIImage imageNamed:selected ? @"radioBtnOn" : @"radioBtnOff"]; image.image = [UIImage imageNamed:selected ? @"radioBtnOn" : @"radioBtnOff"];
[image setStyleNameAndApply: selected ? @"MWMBlue" : @"MWMGray"]; [image setStyleNameAndApply:selected ? @"MWMBlue" : @"MWMGray"];
} }
} }
} }

View File

@@ -8,12 +8,10 @@
} }
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{ {}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated - (void)setSelected:(BOOL)selected animated:(BOOL)animated
{ {}
}
- (void)hide - (void)hide
{ {

View File

@@ -2,10 +2,10 @@
@interface MWMOpeningHoursTimeSelectorTableViewCell () @interface MWMOpeningHoursTimeSelectorTableViewCell ()
@property (weak, nonatomic) IBOutlet UIDatePicker * openTimePicker; @property(weak, nonatomic) IBOutlet UIDatePicker * openTimePicker;
@property (weak, nonatomic) IBOutlet UIDatePicker * closeTimePicker; @property(weak, nonatomic) IBOutlet UIDatePicker * closeTimePicker;
@property (nonatomic) NSCalendar * calendar; @property(nonatomic) NSCalendar * calendar;
@end @end
@@ -40,7 +40,7 @@
- (IBAction)openValueChanged - (IBAction)openValueChanged
{ {
NSDate * date = self.openTimePicker.date; NSDate * date = self.openTimePicker.date;
NSCalendarUnit const components = NSCalendarUnitHour | NSCalendarUnitMinute; NSCalendarUnit const components = NSCalendarUnitHour | NSCalendarUnitMinute;
self.section.cachedStartTime = [self.calendar components:components fromDate:date]; self.section.cachedStartTime = [self.calendar components:components fromDate:date];
} }

View File

@@ -2,8 +2,8 @@
@interface MWMOpeningHoursTimeSpanTableViewCell () @interface MWMOpeningHoursTimeSpanTableViewCell ()
@property (weak, nonatomic) IBOutlet UILabel * openTimeLabel; @property(weak, nonatomic) IBOutlet UILabel * openTimeLabel;
@property (weak, nonatomic) IBOutlet UILabel * closeTimeLabel; @property(weak, nonatomic) IBOutlet UILabel * closeTimeLabel;
@end @end

View File

@@ -10,18 +10,20 @@
#import "SwiftBridge.h" #import "SwiftBridge.h"
extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
@(MWMOpeningHoursEditorDaysSelectorCell) : [MWMOpeningHoursDaysSelectorTableViewCell class], @(MWMOpeningHoursEditorDaysSelectorCell): [MWMOpeningHoursDaysSelectorTableViewCell class],
@(MWMOpeningHoursEditorAllDayCell) : [MWMOpeningHoursAllDayTableViewCell class], @(MWMOpeningHoursEditorAllDayCell): [MWMOpeningHoursAllDayTableViewCell class],
@(MWMOpeningHoursEditorTimeSpanCell) : [MWMOpeningHoursTimeSpanTableViewCell class], @(MWMOpeningHoursEditorTimeSpanCell): [MWMOpeningHoursTimeSpanTableViewCell class],
@(MWMOpeningHoursEditorTimeSelectorCell) : [MWMOpeningHoursTimeSelectorTableViewCell class], @(MWMOpeningHoursEditorTimeSelectorCell): [MWMOpeningHoursTimeSelectorTableViewCell class],
@(MWMOpeningHoursEditorClosedSpanCell) : [MWMOpeningHoursClosedSpanTableViewCell class], @(MWMOpeningHoursEditorClosedSpanCell): [MWMOpeningHoursClosedSpanTableViewCell class],
@(MWMOpeningHoursEditorAddClosedCell) : [MWMOpeningHoursAddClosedTableViewCell class], @(MWMOpeningHoursEditorAddClosedCell): [MWMOpeningHoursAddClosedTableViewCell class],
@(MWMOpeningHoursEditorDeleteScheduleCell) : [MWMOpeningHoursDeleteScheduleTableViewCell class], @(MWMOpeningHoursEditorDeleteScheduleCell): [MWMOpeningHoursDeleteScheduleTableViewCell class],
@(MWMOpeningHoursEditorAddScheduleCell) : [MWMOpeningHoursAddScheduleTableViewCell class], @(MWMOpeningHoursEditorAddScheduleCell): [MWMOpeningHoursAddScheduleTableViewCell class],
}; };
@interface MWMOpeningHoursEditorViewController ()<UITableViewDelegate, UITableViewDataSource, @interface MWMOpeningHoursEditorViewController () <UITableViewDelegate,
UITextViewDelegate, MWMOpeningHoursModelProtocol> UITableViewDataSource,
UITextViewDelegate,
MWMOpeningHoursModelProtocol>
@property(weak, nonatomic, readwrite) IBOutlet UITableView * tableView; @property(weak, nonatomic, readwrite) IBOutlet UITableView * tableView;
@property(weak, nonatomic, readwrite) IBOutlet UIView * advancedEditor; @property(weak, nonatomic, readwrite) IBOutlet UIView * advancedEditor;
@@ -74,12 +76,9 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
- (void)configAdvancedEditor - (void)configAdvancedEditor
{ {
[self.editorView setTextContainerInset:{.top = 12, .left = 10, .bottom = 12, .right = 10}]; [self.editorView setTextContainerInset:{.top = 12, .left = 10, .bottom = 12, .right = 10}];
self.editorView.keyboardAppearance = self.editorView.keyboardAppearance = [UIColor isNightMode] ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault;
[UIColor isNightMode] ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault; NSString * path = [NSBundle.mainBundle pathForResource:@"opening_hours_how_to_edit" ofType:@"html"];
NSString * path = NSString * html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[NSBundle.mainBundle pathForResource:@"opening_hours_how_to_edit" ofType:@"html"];
NSString * html =
[[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSURL * baseURL = [NSURL fileURLWithPath:path]; NSURL * baseURL = [NSURL fileURLWithPath:path];
[self.help loadHTMLString:html baseURL:baseURL]; [self.help loadHTMLString:html baseURL:baseURL];
} }
@@ -92,7 +91,10 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
#pragma mark - Actions #pragma mark - Actions
- (void)onCancel { [self.navigationController popViewControllerAnimated:YES]; } - (void)onCancel
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)onDone - (void)onDone
{ {
[self.model storeCachedData]; [self.model storeCachedData];
@@ -122,8 +124,7 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
#pragma mark - Fill cells with data #pragma mark - Fill cells with data
- (void)fillCell:(MWMOpeningHoursTableViewCell * _Nonnull)cell - (void)fillCell:(MWMOpeningHoursTableViewCell * _Nonnull)cell atIndexPath:(NSIndexPath * _Nonnull)indexPath
atIndexPath:(NSIndexPath * _Nonnull)indexPath
{ {
if (!self.parentViewController) if (!self.parentViewController)
return; return;
@@ -157,8 +158,7 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
#pragma mark - UITableViewDelegate #pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView * _Nonnull)tableView - (CGFloat)tableView:(UITableView * _Nonnull)tableView heightForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
heightForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{ {
return [self heightForRowAtIndexPath:indexPath]; return [self heightForRowAtIndexPath:indexPath];
} }
@@ -182,8 +182,7 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
{ {
_exampleExpanded = exampleExpanded; _exampleExpanded = exampleExpanded;
self.help.hidden = !exampleExpanded; self.help.hidden = !exampleExpanded;
self.examplesButtonBottomOffset.priority = self.examplesButtonBottomOffset.priority = exampleExpanded ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh;
exampleExpanded ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh;
self.exampleValuesSeparator.hidden = !exampleExpanded; self.exampleValuesSeparator.hidden = !exampleExpanded;
self.exampleValuesExpandView.image = self.exampleValuesExpandView.image =
[UIImage imageNamed:exampleExpanded ? @"ic_arrow_gray_up" : @"ic_arrow_gray_down"]; [UIImage imageNamed:exampleExpanded ? @"ic_arrow_gray_up" : @"ic_arrow_gray_down"];
@@ -193,8 +192,14 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
[self.editorView becomeFirstResponder]; [self.editorView becomeFirstResponder];
} }
- (IBAction)toggleExample { self.exampleExpanded = !self.exampleExpanded; } - (IBAction)toggleExample
- (IBAction)toggleMode { self.isSimpleMode = !self.isSimpleMode; } {
self.exampleExpanded = !self.exampleExpanded;
}
- (IBAction)toggleMode
{
self.isSimpleMode = !self.isSimpleMode;
}
#pragma mark - UITextViewDelegate #pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView - (void)textViewDidChange:(UITextView *)textView
@@ -214,5 +219,8 @@ extern NSDictionary * const kMWMOpeningHoursEditorTableCells = @{
self.toggleModeButton.enabled = self.model.isSimpleModeCapable; self.toggleModeButton.enabled = self.model.isSimpleModeCapable;
} }
- (BOOL)isSimpleMode { return self.model.isSimpleMode; } - (BOOL)isSimpleMode
{
return self.model.isSimpleMode;
}
@end @end

View File

@@ -1,5 +1,5 @@
#import <CoreApi/MWMOpeningHoursCommon.h>
#import "MWMOpeningHoursModel.h" #import "MWMOpeningHoursModel.h"
#import <CoreApi/MWMOpeningHoursCommon.h>
#include "editor/ui2oh.hpp" #include "editor/ui2oh.hpp"
@@ -7,9 +7,9 @@ extern UITableViewRowAnimation const kMWMOpeningHoursEditorRowAnimation = UITabl
@interface MWMOpeningHoursModel () <MWMOpeningHoursSectionProtocol> @interface MWMOpeningHoursModel () <MWMOpeningHoursSectionProtocol>
@property (weak, nonatomic) id<MWMOpeningHoursModelProtocol> delegate; @property(weak, nonatomic) id<MWMOpeningHoursModelProtocol> delegate;
@property (nonatomic) NSMutableArray<MWMOpeningHoursSection *> * sections; @property(nonatomic) NSMutableArray<MWMOpeningHoursSection *> * sections;
@end @end
@@ -37,11 +37,8 @@ using namespace osmoh;
- (void)refreshSectionsIndexes - (void)refreshSectionsIndexes
{ {
[self.sections enumerateObjectsUsingBlock:^(MWMOpeningHoursSection * _Nonnull section, [self.sections enumerateObjectsUsingBlock:^(MWMOpeningHoursSection * _Nonnull section, NSUInteger idx,
NSUInteger idx, BOOL * _Nonnull stop) BOOL * _Nonnull stop) { [section refreshIndex:idx]; }];
{
[section refreshIndex:idx];
}];
} }
- (void)addSchedule - (void)addSchedule
@@ -81,10 +78,8 @@ using namespace osmoh;
- (void)updateActiveSection:(NSUInteger)index - (void)updateActiveSection:(NSUInteger)index
{ {
for (MWMOpeningHoursSection * section in self.sections) for (MWMOpeningHoursSection * section in self.sections)
{
if (section.index != index) if (section.index != index)
section.selectedRow = nil; section.selectedRow = nil;
}
} }
- (ui::TimeTableSet::Proxy)timeTableProxy:(NSUInteger)index - (ui::TimeTableSet::Proxy)timeTableProxy:(NSUInteger)index

Some files were not shown because too many files have changed in this diff Show More