Compare commits

...

2 Commits

Author SHA1 Message Date
Konstantin Pastbin
aea784ddd7 [ios] Format all Obj C code via clang-format
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-08-17 16:37:15 +07:00
Konstantin Pastbin
52e9ddc038 [ios] Enable clang-format for Obj C sources
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-08-17 16:29:41 +07:00
110 changed files with 5115 additions and 4272 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,15 @@
#import "RecentlyDeletedCategory+Core.h"
#include <map/bookmark_helpers.hpp>
#include <platform/platform_ios.h>
#include <map/bookmark_helpers.hpp>
@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];
if (self) {
if (self)
{
_title = title;
_fileURL = fileURL;
_deletionDate = deletionDate;
@@ -19,9 +21,11 @@
@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];
if (self) {
if (self)
{
auto const name = GetPreferredBookmarkStr(data.m_name);
_title = [NSString stringWithCString:name.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 "TrackInfo+Core.h"
@implementation TrackInfo
+ (TrackInfo *)emptyInfo {
+ (TrackInfo *)emptyInfo
{
return [[TrackInfo alloc] initWithTrackStatistics:TrackStatistics()];
}
@@ -11,17 +12,17 @@
@implementation TrackInfo (Core)
- (instancetype)initWithTrackStatistics:(TrackStatistics const &)statistics {
if (self = [super init]) {
- (instancetype)initWithTrackStatistics:(TrackStatistics const &)statistics
{
if (self = [super init])
{
_distance = ToNSString(statistics.GetFormattedLength());
_duration = ToNSString(statistics.GetFormattedDuration());
_ascent = ToNSString(statistics.GetFormattedAscent());
_descent = ToNSString(statistics.GetFormattedDescent());
_maxElevation = ToNSString(statistics.GetFormattedMaxElevation());
_minElevation = ToNSString(statistics.GetFormattedMinElevation());
_hasElevationInfo = statistics.m_ascent != 0 ||
statistics.m_descent != 0 ||
statistics.m_maxElevation != 0 ||
_hasElevationInfo = statistics.m_ascent != 0 || statistics.m_descent != 0 || statistics.m_maxElevation != 0 ||
statistics.m_minElevation != 0;
}
return self;

View File

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

View File

@@ -1,12 +1,12 @@
#import "MWMGeoUtil.h"
#include "geometry/mercator.hpp"
#include "geometry/angles.hpp"
#include "geometry/mercator.hpp"
#include "platform/locale.hpp"
#include "platform/localization.hpp"
#include "platform/settings.hpp"
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
@implementation Measure
@@ -31,34 +31,39 @@
let speedString = formatter.string(from: speedMeasurement)
*/
- (NSString*) valueAsString {
- (NSString *)valueAsString
{
auto const outString = measurement_utils::ToStringPrecision(self.value, self.value >= 10.0 ? 0 : 1);
return [NSString stringWithUTF8String:outString.c_str()];
}
- (instancetype)initAsSpeed:(double) mps {
self = [super init];
if (self) {
auto units = measurement_utils::Units::Metric;
settings::TryGet(settings::kMeasurementUnits, units);
_value = measurement_utils::MpsToUnits(mps, units);
- (instancetype)initAsSpeed:(double)mps
{
self = [super init];
if (self)
{
auto units = measurement_utils::Units::Metric;
settings::TryGet(settings::kMeasurementUnits, units);
_value = measurement_utils::MpsToUnits(mps, units);
_unit = @(platform::GetLocalizedSpeedUnits(units).c_str());
}
return self;
_unit = @(platform::GetLocalizedSpeedUnits(units).c_str());
}
return self;
}
@end
@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 mp2 = mercator::FromLatLon(p2.latitude, p2.longitude);
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);
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;
switch (type)
{
case InAppFeatureHighlightRequest::InAppFeatureType::None: return InAppFeatureHighlightTypeNone;
case InAppFeatureHighlightRequest::InAppFeatureType::TrackRecorder: return InAppFeatureHighlightTypeTrackRecorder;
case InAppFeatureHighlightRequest::InAppFeatureType::iCloud: return InAppFeatureHighlightTypeICloud;
case InAppFeatureHighlightRequest::InAppFeatureType::None: return InAppFeatureHighlightTypeNone;
case InAppFeatureHighlightRequest::InAppFeatureType::TrackRecorder: return InAppFeatureHighlightTypeTrackRecorder;
case InAppFeatureHighlightRequest::InAppFeatureType::iCloud: return InAppFeatureHighlightTypeICloud;
}
}
@implementation DeepLinkInAppFeatureHighlightData
- (instancetype)init:(DeeplinkUrlType)urlType {
- (instancetype)init:(DeeplinkUrlType)urlType
{
self = [super init];
if (self) {
if (self)
{
_urlType = urlType;
_feature = FeatureTypeFrom(GetFramework().GetInAppFeatureHighlightRequest().m_feature);
}

View File

@@ -9,29 +9,32 @@ static inline DeeplinkUrlType deeplinkUrlType(url_scheme::ParsedMapApi::UrlType
using namespace url_scheme;
switch (type)
{
case ParsedMapApi::UrlType::Incorrect: return DeeplinkUrlTypeIncorrect;
case ParsedMapApi::UrlType::Map: return DeeplinkUrlTypeMap;
case ParsedMapApi::UrlType::Route: return DeeplinkUrlTypeRoute;
case ParsedMapApi::UrlType::Search: return DeeplinkUrlTypeSearch;
case ParsedMapApi::UrlType::Crosshair: return DeeplinkUrlTypeCrosshair;
case ParsedMapApi::UrlType::OAuth2: return DeeplinkUrlTypeOAuth2;
case ParsedMapApi::UrlType::Menu: return DeeplinkUrlTypeMenu;
case ParsedMapApi::UrlType::Settings: return DeeplinkUrlTypeSettings;
case ParsedMapApi::UrlType::Incorrect: return DeeplinkUrlTypeIncorrect;
case ParsedMapApi::UrlType::Map: return DeeplinkUrlTypeMap;
case ParsedMapApi::UrlType::Route: return DeeplinkUrlTypeRoute;
case ParsedMapApi::UrlType::Search: return DeeplinkUrlTypeSearch;
case ParsedMapApi::UrlType::Crosshair: return DeeplinkUrlTypeCrosshair;
case ParsedMapApi::UrlType::OAuth2: return DeeplinkUrlTypeOAuth2;
case ParsedMapApi::UrlType::Menu: return DeeplinkUrlTypeMenu;
case ParsedMapApi::UrlType::Settings: return DeeplinkUrlTypeSettings;
}
}
@implementation DeepLinkParser
+ (DeeplinkUrlType)parseAndSetApiURL:(NSURL *)url {
Framework &f = GetFramework();
+ (DeeplinkUrlType)parseAndSetApiURL:(NSURL *)url
{
Framework & f = GetFramework();
return deeplinkUrlType(f.ParseAndSetApiURL(url.absoluteString.UTF8String));
}
+ (void)executeMapApiRequest {
+ (void)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.
GetFramework().AddBookmarksFile(url.path.UTF8String, false /* isTemporaryFile */);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,7 @@ namespace
{
NSString * stringFromTimeSpan(Timespan const & timeSpan)
{
return [NSString stringWithFormat:@"%@-%@", stringFromTime(timeSpan.GetStart()),
stringFromTime(timeSpan.GetEnd())];
return [NSString stringWithFormat:@"%@-%@", stringFromTime(timeSpan.GetStart()), stringFromTime(timeSpan.GetEnd())];
}
NSString * breaksFromClosedTime(TTimespans const & closedTimes, id<IOpeningHoursLocalization> localization)
@@ -22,8 +21,8 @@ NSString * breaksFromClosedTime(TTimespans const & closedTimes, id<IOpeningHours
{
if (i)
[breaks appendString:@"\n"];
[breaks appendString:[NSString stringWithFormat:@"%@ %@", localization.breakString,
stringFromTimeSpan(closedTimes[i])]];
[breaks appendString:[NSString
stringWithFormat:@"%@ %@", localization.breakString, stringFromTimeSpan(closedTimes[i])]];
}
return [breaks copy];
}
@@ -81,9 +80,10 @@ void addUnhandledDays(ui::OpeningDays const & days, std::vector<Day> & allDays)
} // 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);
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;
auto const timeTablesSize = timeTableSet.Size();
auto const today =
static_cast<Weekday>([cal components:NSCalendarUnitWeekday fromDate:[NSDate date]].weekday);
auto const today = static_cast<Weekday>([cal components:NSCalendarUnitWeekday fromDate:[NSDate date]].weekday);
auto const unhandledDays = timeTableSet.GetUnhandledDays();
/// 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};
}
} // 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 *> * spans = [NSMutableArray array];
auto weekdayFromDay = ^(NSUInteger day)
{
auto weekdayFromDay = ^(NSUInteger day) {
NSUInteger idx = day + 1;
if (idx > static_cast<NSUInteger>(osmoh::Weekday::Saturday))
idx -= static_cast<NSUInteger>(osmoh::Weekday::Saturday);
return static_cast<osmoh::Weekday>(idx);
};
auto joinSpanNames = ^
{
auto joinSpanNames = ^{
NSUInteger const spanNamesCount = spanNames.count;
if (spanNamesCount == 0)
return;

View File

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

View File

@@ -1,5 +1,5 @@
#import "PlacePageBookmarkData+Core.h"
#import "MWMBookmarkColor+Core.h"
#import "PlacePageBookmarkData+Core.h"
@implementation PlacePageBookmarkData
@@ -7,13 +7,16 @@
@implementation PlacePageBookmarkData (Core)
- (instancetype)initWithRawData:(place_page::Info const &)rawData {
- (instancetype)initWithRawData:(place_page::Info const &)rawData
{
self = [super init];
if (self) {
if (self)
{
_bookmarkId = rawData.GetBookmarkId();
_bookmarkGroupId = rawData.GetBookmarkCategoryId();
_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;
_isHtmlDescription = strings::IsHTML(GetPreferredBookmarkStr(rawData.GetBookmarkData().m_description));
_color = convertKmlColor(rawData.GetBookmarkData().m_color.m_predefinedColor);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,92 +19,110 @@ using namespace storage;
@interface MWMStorage ()
@property(nonatomic, strong) NSHashTable<id<MWMStorageObserver>> *observers;
@property(nonatomic, strong) NSHashTable<id<MWMStorageObserver>> * observers;
@end
@implementation MWMStorage
+ (instancetype)sharedStorage {
static MWMStorage *instance;
+ (instancetype)sharedStorage
{
static MWMStorage * instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; });
return instance;
}
- (instancetype)init {
- (instancetype)init
{
self = [super init];
if (self) {
if (self)
{
_observers = [NSHashTable weakObjectsHashTable];
NSHashTable *observers = _observers;
NSHashTable * observers = _observers;
GetFramework().GetStorage().Subscribe(
[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.'
NSHashTable *observersCopy = [observers copy];
for (id<MWMStorageObserver> observer in observersCopy) {
[observer processCountryEvent:@(countryId.c_str())];
[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.'
NSHashTable * observersCopy = [observers copy];
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;
}
- (void)addObserver:(id<MWMStorageObserver>)observer {
- (void)addObserver:(id<MWMStorageObserver>)observer
{
[self.observers addObject:observer];
}
- (void)removeObserver:(id<MWMStorageObserver>)observer {
- (void)removeObserver:(id<MWMStorageObserver>)observer
{
[self.observers removeObject:observer];
}
- (BOOL)downloadNode:(NSString *)countryId error:(NSError *__autoreleasing _Nullable *)error {
if (IsEnoughSpaceForDownload(countryId.UTF8String, GetFramework().GetStorage())) {
NSError *connectionError;
if ([self checkConnection:&connectionError]) {
- (BOOL)downloadNode:(NSString *)countryId error:(NSError * __autoreleasing _Nullable *)error
{
if (IsEnoughSpaceForDownload(countryId.UTF8String, GetFramework().GetStorage()))
{
NSError * connectionError;
if ([self checkConnection:&connectionError])
{
GetFramework().GetStorage().DownloadNode(countryId.UTF8String);
return YES;
} else if (error) {
}
else if (error)
{
*error = connectionError;
}
} else if (error) {
}
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
}
return NO;
}
- (void)retryDownloadNode:(NSString *)countryId {
if ([self checkConnection:nil]) {
- (void)retryDownloadNode:(NSString *)countryId
{
if ([self checkConnection:nil])
GetFramework().GetStorage().RetryDownloadNode(countryId.UTF8String);
}
}
- (BOOL)updateNode:(NSString *)countryId error:(NSError *__autoreleasing _Nullable *)error {
if (IsEnoughSpaceForUpdate(countryId.UTF8String, GetFramework().GetStorage())) {
NSError *connectionError;
if ([self checkConnection:&connectionError]) {
- (BOOL)updateNode:(NSString *)countryId error:(NSError * __autoreleasing _Nullable *)error
{
if (IsEnoughSpaceForUpdate(countryId.UTF8String, GetFramework().GetStorage()))
{
NSError * connectionError;
if ([self checkConnection:&connectionError])
{
GetFramework().GetStorage().UpdateNode(countryId.UTF8String);
return YES;
} else if (error) {
}
else if (error)
{
*error = connectionError;
}
} else if (error) {
}
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
}
@@ -112,21 +130,24 @@ using namespace storage;
}
- (BOOL)deleteNode:(NSString *)countryId
ignoreUnsavedEdits:(BOOL)force
error:(NSError *__autoreleasing _Nullable *)error {
auto &f = GetFramework();
if (f.GetRoutingManager().IsRoutingActive()) {
if (error) {
ignoreUnsavedEdits:(BOOL)force
error:(NSError * __autoreleasing _Nullable *)error
{
auto & f = GetFramework();
if (f.GetRoutingManager().IsRoutingActive())
{
if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageRoutingActive userInfo:nil];
}
return NO;
}
if (!force && f.HasUnsavedEdits(countryId.UTF8String)) {
if (error) {
if (!force && f.HasUnsavedEdits(countryId.UTF8String))
{
if (error)
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageHaveUnsavedEdits userInfo:nil];
}
} else {
}
else
{
f.GetStorage().DeleteNode(countryId.UTF8String);
return YES;
}
@@ -134,135 +155,152 @@ using namespace storage;
return NO;
}
- (void)cancelDownloadNode:(NSString *)countryId {
- (void)cancelDownloadNode:(NSString *)countryId
{
GetFramework().GetStorage().CancelDownloadNode(countryId.UTF8String);
}
- (void)showNode:(NSString *)countryId {
- (void)showNode:(NSString *)countryId
{
GetFramework().ShowNode(countryId.UTF8String);
}
- (BOOL)downloadNodes:(NSArray<NSString *> *)countryIds error:(NSError *__autoreleasing _Nullable *)error {
auto &s = GetFramework().GetStorage();
- (BOOL)downloadNodes:(NSArray<NSString *> *)countryIds error:(NSError * __autoreleasing _Nullable *)error
{
auto & s = GetFramework().GetStorage();
MwmSize requiredSize = 0;
for (NSString *countryId in countryIds) {
for (NSString * countryId in countryIds)
{
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(countryId.UTF8String, nodeAttrs);
requiredSize += nodeAttrs.m_mwmSize;
}
if (storage::IsEnoughSpaceForDownload(requiredSize)) {
NSError *connectionError;
if ([self checkConnection:&connectionError]) {
for (NSString *countryId in countryIds) {
if (storage::IsEnoughSpaceForDownload(requiredSize))
{
NSError * connectionError;
if ([self checkConnection:&connectionError])
{
for (NSString * countryId in countryIds)
s.DownloadNode(countryId.UTF8String);
}
return YES;
} else if (error) {
}
else if (error)
{
*error = connectionError;
}
} else if (error) {
}
else if (error)
{
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNotEnoughSpace userInfo:nil];
}
return NO;
}
- (BOOL)checkConnection:(NSError *__autoreleasing *)error {
switch (Platform::ConnectionStatus()) {
case Platform::EConnectionType::CONNECTION_NONE:
if (error) {
*error = [NSError errorWithDomain:kStorageErrorDomain code:kStorageNoConnection userInfo:nil];
}
- (BOOL)checkConnection:(NSError * __autoreleasing *)error
{
switch (Platform::ConnectionStatus())
{
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;
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();
}
- (BOOL)downloadInProgress {
- (BOOL)downloadInProgress
{
return GetFramework().GetStorage().IsDownloadInProgress();
}
- (void)enableCellularDownload:(BOOL)enable {
- (void)enableCellularDownload:(BOOL)enable
{
GetFramework().GetDownloadingPolicy().EnableCellularDownload(enable);
}
#pragma mark - Attributes
- (NSArray<NSString *> *)allCountries {
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str());
- (NSArray<NSString *> *)allCountries
{
NSString * rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self allCountriesWithParent:rootId];
}
- (NSArray<NSString *> *)allCountriesWithParent:(NSString *)countryId {
- (NSArray<NSString *> *)allCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren,
true /* keepAvailableChildren */);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const &cid : availableChildren) {
NSMutableArray * result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const & cid : availableChildren)
[result addObject:@(cid.c_str())];
}
return [result copy];
}
- (NSArray<NSString *> *)availableCountriesWithParent:(NSString *)countryId {
- (NSArray<NSString *> *)availableCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const &cid : availableChildren) {
NSMutableArray * result = [NSMutableArray arrayWithCapacity:availableChildren.size()];
for (auto const & cid : availableChildren)
[result addObject:@(cid.c_str())];
}
return [result copy];
}
- (NSArray<NSString *> *)downloadedCountries {
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str());
- (NSArray<NSString *> *)downloadedCountries
{
NSString * rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self downloadedCountriesWithParent:rootId];
}
- (NSArray<NSString *> *)downloadedCountriesWithParent:(NSString *)countryId {
- (NSArray<NSString *> *)downloadedCountriesWithParent:(NSString *)countryId
{
storage::CountriesVec downloadedChildren;
storage::CountriesVec availableChildren;
GetFramework().GetStorage().GetChildrenInGroups(countryId.UTF8String, downloadedChildren, availableChildren);
NSMutableArray *result = [NSMutableArray arrayWithCapacity:downloadedChildren.size()];
for (auto const &cid : downloadedChildren) {
NSMutableArray * result = [NSMutableArray arrayWithCapacity:downloadedChildren.size()];
for (auto const & cid : downloadedChildren)
[result addObject:@(cid.c_str())];
}
return [result copy];
}
- (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId {
auto const &s = GetFramework().GetStorage();
- (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId
{
auto const & s = GetFramework().GetStorage();
storage::NodeAttrs nodeAttrs;
s.GetNodeAttrs(countryId.UTF8String, nodeAttrs);
storage::CountriesVec children;
@@ -274,25 +312,30 @@ using namespace storage;
hasChildren:!children.empty()];
}
- (MWMMapNodeAttributes *)attributesForRoot {
- (MWMMapNodeAttributes *)attributesForRoot
{
return [self attributesForCountry:@(GetFramework().GetStorage().GetRootId().c_str())];
}
- (NSString *)getRootId {
- (NSString *)getRootId
{
return @(GetFramework().GetStorage().GetRootId().c_str());
}
- (NSString *)nameForCountry:(NSString *)countryId {
- (NSString *)nameForCountry:(NSString *)countryId
{
return @(GetFramework().GetStorage().GetNodeLocalName(countryId.UTF8String).c_str());
}
- (NSArray<NSString *> *)nearbyAvailableCountries:(CLLocationCoordinate2D)location {
auto &f = GetFramework();
- (NSArray<NSString *> *)nearbyAvailableCountries:(CLLocationCoordinate2D)location
{
auto & f = GetFramework();
storage::CountriesVec closestCoutryIds;
f.GetCountryInfoGetter().GetRegionsCountryId(mercator::FromLatLon(location.latitude, location.longitude),
closestCoutryIds);
NSMutableArray *nearmeCountries = [NSMutableArray array];
for (auto const &countryId : closestCoutryIds) {
NSMutableArray * nearmeCountries = [NSMutableArray array];
for (auto const & countryId : closestCoutryIds)
{
storage::NodeStatuses nodeStatuses;
f.GetStorage().GetNodeStatuses(countryId, nodeStatuses);
if (nodeStatuses.m_status != storage::NodeStatus::OnDisk)
@@ -302,14 +345,14 @@ using namespace storage;
return nearmeCountries.count > 0 ? [nearmeCountries copy] : nil;
}
- (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId {
auto const &s = GetFramework().GetStorage();
- (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId
{
auto const & s = GetFramework().GetStorage();
Storage::UpdateInfo updateInfo;
if (countryId.length > 0) {
if (countryId.length > 0)
s.GetUpdateInfo(countryId.UTF8String, updateInfo);
} else {
else
s.GetUpdateInfo(s.GetRootId(), updateInfo);
}
return [[MWMMapUpdateInfo alloc] initWithUpdateInfo:updateInfo];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,22 +2,20 @@
#import "MWMZoomButtonsView.h"
#import "Statistics.h"
#include "Framework.h"
#include "platform/settings.hpp"
#include "indexer/scales.hpp"
#include "platform/settings.hpp"
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 (weak, nonatomic) IBOutlet UIButton * zoomInButton;
@property (weak, nonatomic) IBOutlet UIButton * zoomOutButton;
@property (nonatomic) BOOL zoomSwipeEnabled;
@property (nonatomic, readonly) BOOL isZoomEnabled;
@property(nonatomic) BOOL zoomSwipeEnabled;
@property(nonatomic, readonly) BOOL isZoomEnabled;
@end

View File

@@ -1,5 +1,5 @@
#import "Common.h"
#import "MWMZoomButtonsView.h"
#import "Common.h"
#import "MWMMapViewControlsCommon.h"
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 kZoomViewHideBoundPercent = 0.4;
@interface MWMZoomButtonsView()
@interface MWMZoomButtonsView ()
@property (nonatomic) CGRect defaultBounds;
@property(nonatomic) CGRect defaultBounds;
@end
@@ -39,7 +39,8 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
- (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);
}
@@ -59,7 +60,8 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
{
CGFloat const hideBound = kZoomViewHideBoundPercent * self.superview.height;
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 (!isHidden)
@@ -84,15 +86,12 @@ static CGFloat const kZoomViewHideBoundPercent = 0.4;
if (!hidden)
self.hidden = NO;
[self layoutXPosition:!hidden];
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^
{
[self layoutXPosition:hidden];
}
completion:^(BOOL finished)
{
if (hidden)
self.hidden = YES;
}];
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount)
animations:^{ [self layoutXPosition:hidden]; }
completion:^(BOOL finished) {
if (hidden)
self.hidden = YES;
}];
}
else
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,33 +22,34 @@
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
#endif
#import "FirstSession.h"
#include <utility> // std::pair
#include <sys/xattr.h>
#include <utility> // std::pair
#import <CoreFoundation/CoreFoundation.h>
#import <CoreFoundation/CFURL.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/NSURL.h>
#if (TARGET_OS_IPHONE > 0) // Works for all iOS devices, including iPad.
#import <UIKit/UIApplication.h>
#import <UIKit/UIDevice.h>
#import <UIKit/UIScreen.h>
#import <UIKit/UIApplication.h>
#import <UIKit/UIWebView.h>
#endif // TARGET_OS_IPHONE
#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
#import <sys/socket.h>
namespace {
namespace
{
// Key for app unique installation id in standardUserDefaults.
NSString * const kAlohalyticsInstallationId = @"AlohalyticsInstallationId";
} // namespace
} // namespace
// Keys for NSUserDefaults.
static NSString * const kInstalledVersionKey = @"AlohalyticsInstalledVersion";
@@ -64,38 +65,49 @@ static NSString * gInstallationId = nil;
@implementation FirstSession
+ (void)setup:(NSArray *)serverUrls withLaunchOptions:(NSDictionary *)options {
+ (void)setup:(NSArray *)serverUrls withLaunchOptions:(NSDictionary *)options
{
#if (TARGET_OS_IPHONE > 0)
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
Class cls = [FirstSession class];
[nc addObserver:cls selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[nc addObserver:cls selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
#endif // TARGET_OS_IPHONE
[nc addObserver:cls
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[nc addObserver:cls
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
#endif // TARGET_OS_IPHONE
// INIT
[self installationId];
}
#if (TARGET_OS_IPHONE > 0)
+ (void)applicationDidEnterBackground:(NSNotification *)notification {
if (gIsFirstSession) {
+ (void)applicationDidEnterBackground:(NSNotification *)notification
{
if (gIsFirstSession)
gIsFirstSession = NO;
}
}
+ (void)applicationWillTerminate:(NSNotification *)notification {
+ (void)applicationWillTerminate:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#endif // TARGET_OS_IPHONE
#endif // TARGET_OS_IPHONE
#pragma mark Utility methods
+ (BOOL)isFirstSession {
+ (BOOL)isFirstSession
{
return [self installationId] != nil && gIsFirstSession;
}
+ (NSDate *)firstLaunchDate {
+ (NSDate *)firstLaunchDate
{
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
NSDate * date = [ud objectForKey:kFirstLaunchDateKey];
if (!date) {
if (!date)
{
// Non-standard situation: this method is called before calling setup. Return current date.
date = [NSDate date];
[ud setObject:date forKey:kFirstLaunchDateKey];
@@ -103,42 +115,51 @@ static NSString * gInstallationId = nil;
return date;
}
+ (NSInteger)totalSecondsSpentInTheApp {
+ (NSInteger)totalSecondsSpentInTheApp
{
NSInteger seconds = [[NSUserDefaults standardUserDefaults] integerForKey:kTotalSecondsInTheApp];
// Take into an account currently active session.
if (gSessionStartTime) {
if (gSessionStartTime)
seconds += static_cast<NSInteger>(-gSessionStartTime.timeIntervalSinceNow);
}
return seconds;
}
// Internal helper, returns nil for invalid paths.
+ (NSDate *)fileCreationDate:(NSString *)fullPath {
+ (NSDate *)fileCreationDate:(NSString *)fullPath
{
NSDictionary * attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:nil];
return attributes ? [attributes objectForKey:NSFileCreationDate] : nil;
}
+ (NSDate *)installDate {
return [FirstSession fileCreationDate:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
+ (NSDate *)installDate
{
return [FirstSession
fileCreationDate:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
}
+ (NSDate *)updateDate {
+ (NSDate *)updateDate
{
return [FirstSession fileCreationDate:[[NSBundle mainBundle] resourcePath]];
}
+ (NSDate *)buildDate {
+ (NSDate *)buildDate
{
return [FirstSession fileCreationDate:[[NSBundle mainBundle] executablePath]];
}
+ (NSString *)installationId {
if (gInstallationId == nil) {
+ (NSString *)installationId
{
if (gInstallationId == nil)
{
gIsFirstSession = NO;
NSUserDefaults * ud = [NSUserDefaults standardUserDefaults];
gInstallationId = [ud stringForKey:kAlohalyticsInstallationId];
if (gInstallationId == nil) {
if (gInstallationId == nil)
{
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
// All iOS IDs start with I:
gInstallationId = [@"I:" stringByAppendingString:(NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid))];
gInstallationId =
[@"I:" stringByAppendingString:(NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid))];
CFRelease(uuid);
[ud setValue:gInstallationId forKey:kAlohalyticsInstallationId];
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
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])
return "zh-Hans"; // Chinese simplified
return "zh-Hans"; // Chinese simplified
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
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 "SwiftBridge.h"
#import <CarPlay/CarPlay.h>
#import <CoreSpotlight/CoreSpotlight.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
// folder.
namespace {
NSString *const kUDLastLaunchDateKey = @"LastLaunchDate";
NSString *const kUDSessionsCountKey = @"SessionsCount";
NSString *const kUDFirstVersionKey = @"FirstVersion";
NSString *const kUDLastShareRequstDate = @"LastShareRequestDate";
NSString *const kUDAutoNightModeOff = @"AutoNightModeOff";
NSString *const kIOSIDFA = @"IFA";
NSString *const kBundleVersion = @"BundleVersion";
namespace
{
NSString * const kUDLastLaunchDateKey = @"LastLaunchDate";
NSString * const kUDSessionsCountKey = @"SessionsCount";
NSString * const kUDFirstVersionKey = @"FirstVersion";
NSString * const kUDLastShareRequstDate = @"LastShareRequestDate";
NSString * const kUDAutoNightModeOff = @"AutoNightModeOff";
NSString * const kIOSIDFA = @"IFA";
NSString * const kBundleVersion = @"BundleVersion";
/// Adds needed localized strings to C++ code
/// @TODO Refactor localization mechanism to make it simpler
void InitLocalizedStrings() {
Framework &f = GetFramework();
void InitLocalizedStrings()
{
Framework & f = GetFramework();
f.AddString("core_entrance", L(@"core_entrance").UTF8String);
f.AddString("core_exit", L(@"core_exit").UTF8String);
@@ -57,30 +58,30 @@ void InitLocalizedStrings() {
}
} // namespace
@interface MapsAppDelegate () <MWMStorageObserver,
CPApplicationDelegate>
@interface MapsAppDelegate () <MWMStorageObserver, CPApplicationDelegate>
@property(nonatomic) NSInteger standbyCounter;
@property(nonatomic) MWMBackgroundFetchScheduler *backgroundFetchScheduler;
@property(nonatomic) MWMBackgroundFetchScheduler * backgroundFetchScheduler;
@end
@implementation MapsAppDelegate
+ (MapsAppDelegate *)theApp {
+ (MapsAppDelegate *)theApp
{
return (MapsAppDelegate *)UIApplication.sharedApplication.delegate;
}
- (BOOL)isDrapeEngineCreated {
- (BOOL)isDrapeEngineCreated
{
return self.mapViewController.mapView.drapeEngineCreated;
}
- (void)searchText:(NSString *)searchString {
if (!self.isDrapeEngineCreated) {
dispatch_async(dispatch_get_main_queue(), ^{
[self searchText:searchString];
});
- (void)searchText:(NSString *)searchString
{
if (!self.isDrapeEngineCreated)
{
dispatch_async(dispatch_get_main_queue(), ^{ [self searchText:searchString]; });
return;
}
SearchQuery * query = [[SearchQuery alloc] init:[searchString stringByAppendingString:@" "]
@@ -89,7 +90,8 @@ void InitLocalizedStrings() {
[[MWMMapViewControlsManager manager] search:query];
}
- (void)commonInit {
- (void)commonInit
{
[HttpThreadImpl setDownloadIndicatorProtocol:self];
InitLocalizedStrings();
GetFramework().SetupMeasurementSystem();
@@ -103,7 +105,8 @@ void InitLocalizedStrings() {
[TrackRecordingManager.shared setup];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"application:didFinishLaunchingWithOptions: %@", launchOptions);
[HttpThreadImpl setDownloadIndicatorProtocol:self];
@@ -113,30 +116,31 @@ void InitLocalizedStrings() {
[self commonInit];
if ([FirstSession isFirstSession]) {
if ([FirstSession isFirstSession])
[self firstLaunchSetup];
} else {
else
[self incrementSessionCount];
}
[self enableTTSForTheFirstTime];
if (![MapsAppDelegate isTestsEnvironment])
[[iCloudSynchronizaionManager shared] start];
[[DeepLinkHandler shared] applicationDidFinishLaunching:launchOptions];
// application:openUrl:options is called later for deep links if YES is returned.
return YES;
}
- (void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
completionHandler:(void (^)(BOOL))completionHandler {
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
completionHandler:(void (^)(BOOL))completionHandler
{
[self.mapViewController performAction:shortcutItem.type];
completionHandler(YES);
}
- (void)runBackgroundTasks:(NSArray<BackgroundFetchTask *> *_Nonnull)tasks
completionHandler:(void (^_Nullable)(UIBackgroundFetchResult))completionHandler {
- (void)runBackgroundTasks:(NSArray<BackgroundFetchTask *> * _Nonnull)tasks
completionHandler:(void (^_Nullable)(UIBackgroundFetchResult))completionHandler
{
self.backgroundFetchScheduler = [[MWMBackgroundFetchScheduler alloc] initWithTasks:tasks
completionHandler:^(UIBackgroundFetchResult result) {
if (completionHandler)
@@ -145,16 +149,19 @@ void InitLocalizedStrings() {
[self.backgroundFetchScheduler run];
}
- (void)applicationWillTerminate:(UIApplication *)application {
- (void)applicationWillTerminate:(UIApplication *)application
{
[self.mapViewController onTerminate];
// Global cleanup
DeleteFramework();
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
- (void)applicationDidEnterBackground:(UIApplication *)application
{
LOG(LINFO, ("applicationDidEnterBackground - begin"));
[DeepLinkHandler.shared reset];
if (m_activeDownloadsCounter) {
if (m_activeDownloadsCounter)
{
m_backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:self->m_backgroundTask];
self->m_backgroundTask = UIBackgroundTaskInvalid;
@@ -168,16 +175,20 @@ void InitLocalizedStrings() {
LOG(LINFO, ("applicationDidEnterBackground - end"));
}
- (void)applicationWillResignActive:(UIApplication *)application {
- (void)applicationWillResignActive:(UIApplication *)application
{
LOG(LINFO, ("applicationWillResignActive - begin"));
[self.mapViewController onGetFocus:NO];
auto &f = GetFramework();
auto & f = GetFramework();
// On some devices we have to free all belong-to-graphics memory
// because of new OpenGL driver powered by Metal.
if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103) {
if ([AppInfo sharedInfo].openGLDriver == MWMOpenGLDriverMetalPre103)
{
f.SetRenderingDisabled(true);
f.OnDestroySurface();
} else {
}
else
{
f.SetRenderingDisabled(false);
}
[MWMLocationManager applicationWillResignActive];
@@ -185,28 +196,28 @@ void InitLocalizedStrings() {
LOG(LINFO, ("applicationWillResignActive - end"));
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
- (void)applicationWillEnterForeground:(UIApplication *)application
{
LOG(LINFO, ("applicationWillEnterForeground - begin"));
if (!GpsTracker::Instance().IsEnabled())
return;
MWMViewController *topVc =
static_cast<MWMViewController *>(self.mapViewController.navigationController.topViewController);
MWMViewController * topVc =
static_cast<MWMViewController *>(self.mapViewController.navigationController.topViewController);
if (![topVc isKindOfClass:[MWMViewController class]])
return;
if ([MWMSettings isTrackWarningAlertShown])
return;
[topVc.alertController presentTrackWarningAlertWithCancelBlock:^{
GpsTracker::Instance().SetEnabled(false);
}];
[topVc.alertController presentTrackWarningAlertWithCancelBlock:^{ GpsTracker::Instance().SetEnabled(false); }];
[MWMSettings setTrackWarningAlertShown:YES];
LOG(LINFO, ("applicationWillEnterForeground - end"));
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
- (void)applicationDidBecomeActive:(UIApplication *)application
{
LOG(LINFO, ("applicationDidBecomeActive - begin"));
auto & f = GetFramework();
@@ -215,7 +226,8 @@ void InitLocalizedStrings() {
f.SetRenderingEnabled();
// On some devices we have to free all belong-to-graphics memory
// 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;
f.OnRecoverSurface(static_cast<int>(objcSize.width), static_cast<int>(objcSize.height),
true /* recreateContextDependentResources */);
@@ -227,8 +239,10 @@ void InitLocalizedStrings() {
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.
+ (BOOL)isTestsEnvironment {
// 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.
+ (BOOL)isTestsEnvironment
{
NSProcessInfo * processInfo = [NSProcessInfo processInfo];
NSArray<NSString *> * launchArguments = [processInfo arguments];
BOOL isTests = [launchArguments containsObject:@"-IsTests"];
@@ -236,17 +250,21 @@ void InitLocalizedStrings() {
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler {
if ([userActivity.activityType isEqualToString:CSSearchableItemActionType]) {
NSString *searchStringKey = userActivity.userInfo[CSSearchableItemActivityIdentifier];
NSString *searchString = L(searchStringKey);
if (searchString) {
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:CSSearchableItemActionType])
{
NSString * searchStringKey = userActivity.userInfo[CSSearchableItemActivityIdentifier];
NSString * searchString = L(searchStringKey);
if (searchString)
{
[self searchText:searchString];
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));
return [DeepLinkHandler.shared applicationDidReceiveUniversalLink:userActivity.webpageURL];
}
@@ -254,49 +272,58 @@ void InitLocalizedStrings() {
return NO;
}
- (void)disableDownloadIndicator {
- (void)disableDownloadIndicator
{
--m_activeDownloadsCounter;
if (m_activeDownloadsCounter <= 0) {
if (m_activeDownloadsCounter <= 0)
{
m_activeDownloadsCounter = 0;
if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground)
{
[UIApplication.sharedApplication endBackgroundTask:m_backgroundTask];
m_backgroundTask = UIBackgroundTaskInvalid;
}
}
}
- (void)enableDownloadIndicator {
- (void)enableDownloadIndicator
{
++m_activeDownloadsCounter;
}
+ (void)customizeAppearanceForNavigationBar:(UINavigationBar *)navigationBar {
+ (void)customizeAppearanceForNavigationBar:(UINavigationBar *)navigationBar
{
auto backImage =
[[UIImage imageNamed:@"ic_nav_bar_back_sys"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[[UIImage imageNamed:@"ic_nav_bar_back_sys"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
navigationBar.backIndicatorImage = backImage;
navigationBar.backIndicatorTransitionMaskImage = backImage;
}
+ (void)customizeAppearance {
+ (void)customizeAppearance
{
[UIButton appearance].exclusiveTouch = YES;
[self customizeAppearanceForNavigationBar:[UINavigationBar appearance]];
UITextField *textField = [UITextField appearance];
UITextField * textField = [UITextField appearance];
textField.keyboardAppearance = [UIColor isNightMode] ? UIKeyboardAppearanceDark : UIKeyboardAppearanceDefault;
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
NSLog(@"application:openURL: %@ options: %@", url, options);
return [DeepLinkHandler.shared applicationDidOpenUrl:url];
}
- (void)showMap {
- (void)showMap
{
[(UINavigationController *)self.window.rootViewController popToRootViewControllerAnimated:YES];
}
- (void)updateApplicationIconBadgeNumber {
- (void)updateApplicationIconBadgeNumber
{
auto const number = [self badgeNumber];
// Delay init because BottomTabBarViewController.controller is null here.
@@ -306,22 +333,25 @@ void InitLocalizedStrings() {
});
}
- (NSUInteger)badgeNumber {
auto &s = GetFramework().GetStorage();
- (NSUInteger)badgeNumber
{
auto & s = GetFramework().GetStorage();
storage::Storage::UpdateInfo updateInfo{};
s.GetUpdateInfo(s.GetRootId(), updateInfo);
return updateInfo.m_numberOfMwmFilesToUpdate;
}
- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler
{
[BackgroundDownloader sharedBackgroundMapDownloader].backgroundCompletionHandler = completionHandler;
}
#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.
// We do not need to update badge frequently.
// Update after 1 second delay (after last country event) is sure enough for app badge.
@@ -332,60 +362,67 @@ void InitLocalizedStrings() {
#pragma mark - Properties
- (MapViewController *)mapViewController {
for (id vc in [(UINavigationController *)self.window.rootViewController viewControllers]) {
- (MapViewController *)mapViewController
{
for (id vc in [(UINavigationController *)self.window.rootViewController viewControllers])
if ([vc isKindOfClass:[MapViewController class]])
return vc;
}
NSAssert(false, @"Please check the logic");
return nil;
}
- (MWMCarPlayService *)carplayService {
- (MWMCarPlayService *)carplayService
{
return [MWMCarPlayService shared];
}
#pragma mark - TTS
- (void)enableTTSForTheFirstTime {
- (void)enableTTSForTheFirstTime
{
if (![MWMTextToSpeech savedLanguage].length)
[MWMTextToSpeech setTTSEnabled:YES];
}
#pragma mark - Standby
- (void)enableStandby {
- (void)enableStandby
{
self.standbyCounter--;
}
- (void)disableStandby {
- (void)disableStandby
{
self.standbyCounter++;
}
- (void)setStandbyCounter:(NSInteger)standbyCounter {
- (void)setStandbyCounter:(NSInteger)standbyCounter
{
_standbyCounter = MAX(0, standbyCounter);
dispatch_async(dispatch_get_main_queue(), ^{
[UIApplication sharedApplication].idleTimerDisabled = (self.standbyCounter != 0);
});
dispatch_async(dispatch_get_main_queue(),
^{ [UIApplication sharedApplication].idleTimerDisabled = (self.standbyCounter != 0); });
}
#pragma mark - Alert logic
- (void)firstLaunchSetup {
NSString *currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSUserDefaults *standartDefaults = NSUserDefaults.standardUserDefaults;
- (void)firstLaunchSetup
{
NSString * currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSUserDefaults * standartDefaults = NSUserDefaults.standardUserDefaults;
[standartDefaults setObject:currentVersion forKey:kUDFirstVersionKey];
[standartDefaults setInteger:1 forKey:kUDSessionsCountKey];
[standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey];
}
- (void)incrementSessionCount {
NSUserDefaults *standartDefaults = NSUserDefaults.standardUserDefaults;
- (void)incrementSessionCount
{
NSUserDefaults * standartDefaults = NSUserDefaults.standardUserDefaults;
NSUInteger sessionCount = [standartDefaults integerForKey:kUDSessionsCountKey];
NSUInteger const kMaximumSessionCountForShowingShareAlert = 50;
if (sessionCount > kMaximumSessionCountForShowingShareAlert)
return;
NSDate *lastLaunchDate = [standartDefaults objectForKey:kUDLastLaunchDateKey];
if (lastLaunchDate.daysToNow > 0) {
NSDate * lastLaunchDate = [standartDefaults objectForKey:kUDLastLaunchDateKey];
if (lastLaunchDate.daysToNow > 0)
{
sessionCount++;
[standartDefaults setInteger:sessionCount forKey:kUDSessionsCountKey];
[standartDefaults setObject:NSDate.date forKey:kUDLastLaunchDateKey];
@@ -394,9 +431,10 @@ void InitLocalizedStrings() {
#pragma mark - Rate
- (BOOL)userIsNew {
NSString *currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSString *firstVersion = [NSUserDefaults.standardUserDefaults stringForKey:kUDFirstVersionKey];
- (BOOL)userIsNew
{
NSString * currentVersion = [NSBundle.mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
NSString * firstVersion = [NSUserDefaults.standardUserDefaults stringForKey:kUDFirstVersionKey];
if (!firstVersion.length || firstVersionIsLessThanSecond(firstVersion, currentVersion))
return NO;
@@ -406,14 +444,16 @@ void InitLocalizedStrings() {
#pragma mark - CPApplicationDelegate implementation
- (void)application:(UIApplication *)application
didConnectCarInterfaceController:(CPInterfaceController *)interfaceController
toWindow:(CPWindow *)window API_AVAILABLE(ios(12.0)) {
didConnectCarInterfaceController:(CPInterfaceController *)interfaceController
toWindow:(CPWindow *)window API_AVAILABLE(ios(12.0))
{
[self.carplayService setupWithWindow:window interfaceController:interfaceController];
}
- (void)application:(UIApplication *)application
didDisconnectCarInterfaceController:(CPInterfaceController *)interfaceController
fromWindow:(CPWindow *)window API_AVAILABLE(ios(12.0)) {
didDisconnectCarInterfaceController:(CPInterfaceController *)interfaceController
fromWindow:(CPWindow *)window API_AVAILABLE(ios(12.0))
{
[self.carplayService destroy];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,8 +2,7 @@
size_t constexpr kGLThreadsCount = 2;
iosOGLContextFactory::iosOGLContextFactory(CAEAGLLayer * layer, dp::ApiVersion apiVersion,
bool presentAvailable)
iosOGLContextFactory::iosOGLContextFactory(CAEAGLLayer * layer, dp::ApiVersion apiVersion, bool presentAvailable)
: m_layer(layer)
, m_apiVersion(apiVersion)
, 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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
#import "SearchResult+Core.h"
#import "CLLocation+Mercator.h"
#import "MWMLocationManager.h"
#import "SearchResult+Core.h"
#import "SwiftBridge.h"
#import "platform/localization.hpp"
#import "platform/distance.hpp"
#import "platform/localization.hpp"
#include "map/bookmark_helpers.hpp"
@@ -12,9 +12,11 @@
@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];
if (self) {
if (self)
{
_titleText = titleText;
_itemType = type;
_suggestion = suggestion;
@@ -24,71 +26,87 @@
@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];
if (self) {
if (self)
{
_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());
_infoText = @(result.GetFeatureDescription().c_str());
if (result.IsSuggest())
_suggestion = @(result.GetSuggestionString().c_str());
_distanceText = nil;
if (result.HasPoint()) {
if (result.HasPoint())
{
auto const center = result.GetFeatureCenter();
_point = CGPointMake(center.x, center.y);
auto const [centerLat, centerLon] = mercator::ToLatLon(center);
_coordinate = CLLocationCoordinate2DMake(centerLat, centerLon);
CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (lastLocation) {
if (lastLocation)
{
double const distanceM = mercator::DistanceOnEarth(lastLocation.mercator, center);
std::string const distanceStr = platform::Distance::CreateFormatted(distanceM).ToString();
_distanceText = @(distanceStr.c_str());
}
}
switch (result.IsOpenNow()) {
case osm::Yes: {
const int minutes = result.GetMinutesUntilClosed();
if (minutes < 60) { // less than 1 hour
_openStatusColor = [UIColor colorNamed:@"Base Colors/Yellow Color"];
NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")];
_openStatusText = [NSString stringWithFormat:L(@"closes_in"), time];
} else {
_openStatusColor = [UIColor colorNamed:@"Base Colors/Green Color"];
_openStatusText = L(@"editor_time_open");
}
break;
switch (result.IsOpenNow())
{
case osm::Yes:
{
int const minutes = result.GetMinutesUntilClosed();
if (minutes < 60)
{ // less than 1 hour
_openStatusColor = [UIColor colorNamed:@"Base Colors/Yellow Color"];
NSString * time = [NSString stringWithFormat:@"%d %@", minutes, L(@"minute")];
_openStatusText = [NSString stringWithFormat:L(@"closes_in"), time];
}
case osm::No: {
const int 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;
else
{
_openStatusColor = [UIColor colorNamed:@"Base Colors/Green Color"];
_openStatusText = L(@"editor_time_open");
}
case osm::Unknown: {
_openStatusText = nil;
_openStatusColor = UIColor.clearColor;
break;
break;
}
case osm::No:
{
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;
NSMutableArray<NSValue *> * ranges = [NSMutableArray array];
size_t const rangesCount = result.GetHighlightRangesCount();
for (size_t i = 0; i < rangesCount; ++i) {
auto const &range = result.GetHighlightRange(i);
for (size_t i = 0; i < rangesCount; ++i)
{
auto const & range = result.GetHighlightRange(i);
NSRange nsRange = NSMakeRange(range.first, range.second);
[ranges addObject:[NSValue valueWithRange:nsRange]];
}
@@ -96,12 +114,12 @@
_itemType = itemType;
if (result.GetResultType() == search::Result::Type::Feature) {
if (result.GetResultType() == search::Result::Type::Feature)
{
auto const featureType = result.GetFeatureType();
auto const bookmarkImage = GetBookmarkIconByFeatureType(featureType);
_iconImageName = [NSString stringWithFormat:@"%@%@",
@"ic_bm_",
[@(kml::ToString(bookmarkImage).c_str()) lowercaseString]];
_iconImageName =
[NSString stringWithFormat:@"%@%@", @"ic_bm_", [@(kml::ToString(bookmarkImage).c_str()) lowercaseString]];
}
}
return self;

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,21 +7,25 @@
@implementation MWMTextToSpeechTest
- (void)testAvailableLanguages {
- (void)testAvailableLanguages
{
MWMTextToSpeech * tts = [MWMTextToSpeech tts];
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)");
XCTAssertTrue(std::find(langs.begin(), langs.end(), defaultLang) != langs.end());
}
- (void)testTranslateLocaleWithTwineString {
- (void)testTranslateLocaleWithTwineString
{
XCTAssertEqual(tts::translateLocale("en"), "English");
}
- (void)testTranslateLocaleWithBcp47String {
- (void)testTranslateLocaleWithBcp47String
{
XCTAssertEqual(tts::translateLocale("en-US"), "English (United States)");
}
- (void)testTranslateLocaleWithUnknownString {
- (void)testTranslateLocaleWithUnknownString
{
XCTAssertEqual(tts::translateLocale("unknown"), "");
}

View File

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

View File

@@ -5,7 +5,7 @@
@interface MWMEditorAdditionalNamesTableViewController ()
@property (weak, nonatomic) id<MWMEditorAdditionalNamesProtocol> delegate;
@property(weak, nonatomic) id<MWMEditorAdditionalNamesProtocol> delegate;
@end
@@ -19,8 +19,8 @@
#pragma mark - UITableViewDataSource
- (void)configWithDelegate:(id<MWMEditorAdditionalNamesProtocol>)delegate
name:(StringUtf8Multilang const &)name
additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes
name:(StringUtf8Multilang const &)name
additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes
{
self.delegate = delegate;
m_name = name;
@@ -52,15 +52,16 @@ additionalSkipLanguageCodes:(std::vector<NSInteger>)additionalSkipLanguageCodes
}
std::sort(m_languages.begin(), m_languages.end(),
[&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)
return false;
if (getIndex(lhs.m_code) != kDefaultCode && getIndex(rhs.m_code) == kDefaultCode)
return true;
[&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)
return false;
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

View File

@@ -22,23 +22,17 @@
self.icon.image = icon;
self.icon.styleName = @"MWMBlack";
self.label.text = text;
[self.segmentedControl setTitle:NSLocalizedString(@"no", nil) forSegmentAtIndex:0];
[self.segmentedControl setTitle:NSLocalizedString(@"yes", nil) forSegmentAtIndex:2];
switch(value)
switch (value)
{
case Yes:
self.segmentedControl.selectedSegmentIndex = 2;
break;
case No:
self.segmentedControl.selectedSegmentIndex = 0;
break;
case Unknown:
self.segmentedControl.selectedSegmentIndex = 1;
break;
case Yes: self.segmentedControl.selectedSegmentIndex = 2; break;
case No: self.segmentedControl.selectedSegmentIndex = 0; break;
case Unknown: self.segmentedControl.selectedSegmentIndex = 1; break;
}
[self setTextColorWithSegmentedValue:value];
}
@@ -46,13 +40,9 @@
{
switch (value)
{
case Yes:
case No:
self.label.textColor = [UIColor blackPrimaryText];
break;
case Unknown:
self.label.textColor = [UIColor blackHintText];
break;
case Yes:
case No: self.label.textColor = [UIColor blackPrimaryText]; break;
case Unknown: self.label.textColor = [UIColor blackHintText]; break;
}
}
@@ -61,18 +51,13 @@
YesNoUnknown value;
switch (self.segmentedControl.selectedSegmentIndex)
{
case 0:
value = No;
break;
case 1:
value = Unknown;
break;
case 2:
value = Yes;
break;
default:
value = Unknown;
NSAssert(false, @"Unexpected YesNoUnknown value %ld", static_cast<long>(self.segmentedControl.selectedSegmentIndex));
case 0: value = No; break;
case 1: value = Unknown; break;
case 2: value = Yes; break;
default:
value = Unknown;
NSAssert(false, @"Unexpected YesNoUnknown value %ld",
static_cast<long>(self.segmentedControl.selectedSegmentIndex));
}
[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
@interface MWMCuisineEditorViewController ()<UISearchBarDelegate, MWMKeyboardObserver>
@interface MWMCuisineEditorViewController () <UISearchBarDelegate, MWMKeyboardObserver>
{
osm::AllCuisines m_allCuisines;
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];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; }
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; }
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
- (void)searchBar:(UISearchBar *)searchBar setActiveState:(BOOL)isActiveState
{
[searchBar setShowsCancelButton:isActiveState animated:YES];
@@ -153,13 +159,15 @@ std::vector<std::string> SliceKeys(std::vector<std::pair<std::string, std::strin
- (void)configTable
{
[self.tableView registerClass:[MWMTableViewCell class]
forCellReuseIdentifier:[UITableViewCell className]];
[self.tableView registerClass:[MWMTableViewCell class] forCellReuseIdentifier:[UITableViewCell className]];
}
#pragma mark - Actions
- (void)onCancel { [self.navigationController popViewControllerAnimated:YES]; }
- (void)onCancel
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)onDone
{
[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
cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{
auto cell =
[tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
auto cell = [tableView dequeueReusableCellWithCellClass:[UITableViewCell class] indexPath:indexPath];
NSInteger const index = indexPath.row;
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
- (void)tableView:(UITableView * _Nonnull)tableView
didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
{
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setSelected:NO animated:YES];
BOOL const isAlreadySelected = cell.accessoryType == UITableViewCellAccessoryCheckmark;
cell.accessoryType =
isAlreadySelected ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark;
[self change:[self dataSourceForSection:indexPath.section][indexPath.row]
selected:!isAlreadySelected];
cell.accessoryType = isAlreadySelected ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark;
[self change:[self dataSourceForSection:indexPath.section][indexPath.row] selected:!isAlreadySelected];
}
@end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,7 +36,10 @@ BOOL isCompactForCellWidth(CGFloat width)
@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
{
[super awakeFromNib];
@@ -92,7 +95,10 @@ BOOL isCompactForCellWidth(CGFloat width)
#pragma mark - Actions
- (IBAction)cancelTap { [self.section removeClosedTime:self.row]; }
- (IBAction)cancelTap
{
[self.section removeClosedTime:self.row];
}
- (IBAction)expandTap
{
if (!self.isVisible)

View File

@@ -3,11 +3,11 @@
@interface MWMOpeningHoursDaysSelectorTableViewCell ()
@property (nonatomic) IBOutletCollection(UIButton) NSArray * buttons;
@property (nonatomic) IBOutletCollection(UILabel) NSArray * labels;
@property (nonatomic) IBOutletCollection(UIImageView) NSArray * images;
@property(nonatomic) IBOutletCollection(UIButton) NSArray * buttons;
@property(nonatomic) IBOutletCollection(UILabel) NSArray * labels;
@property(nonatomic) IBOutletCollection(UIImageView) NSArray * images;
@property (nonatomic) NSUInteger firstWeekday;
@property(nonatomic) NSUInteger firstWeekday;
@end
@@ -28,9 +28,7 @@ using namespace osmoh;
self.firstWeekday = cal.firstWeekday;
NSArray<NSString *> * weekdaySymbols = cal.shortStandaloneWeekdaySymbols;
for (UILabel * label in self.labels)
{
label.text = weekdaySymbols[[self tag2SymbolIndex:label.tag]];
}
}
- (NSUInteger)tag2SymbolIndex:(NSUInteger)tag
@@ -59,21 +57,17 @@ using namespace osmoh;
[section removeSelectedDay:wd];
}
for (UIButton * btn in self.buttons)
{
if (btn.tag == tag)
btn.selected = selected;
}
for (UILabel * label in self.labels)
{
if (label.tag == tag)
label.textColor = (selected ? [UIColor blackPrimaryText] : [UIColor blackHintText]);
}
for (UIImageView * image in self.images)
{
if (image.tag == tag)
{
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)setSelected:(BOOL)selected animated:(BOOL)animated
{
}
{}
- (void)hide
{

View File

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

View File

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

View File

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

View File

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

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