[iOS] [refactoring] refactor map downloader screen

https://jira.mail.ru/browse/MAPSME-12359
This commit is contained in:
Aleksey Belouosv 2019-12-20 13:27:58 +03:00 committed by Alexander Boriskov
parent 5fb6f781ef
commit adaae55e53
67 changed files with 1665 additions and 2398 deletions

View file

@ -14,6 +14,9 @@
470016102342579200EBF03D /* MWMTagGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 470016032342540E00EBF03D /* MWMTagGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
4718C4322355FC3C00640DF1 /* MWMNetworkPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4718C4302355FC3C00640DF1 /* MWMNetworkPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4718C4332355FC3C00640DF1 /* MWMNetworkPolicy.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4718C4312355FC3C00640DF1 /* MWMNetworkPolicy.mm */; };
471AB98D23AB925D00F56D49 /* MWMMapSearchResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 471AB98B23AB925D00F56D49 /* MWMMapSearchResult.h */; settings = {ATTRIBUTES = (Public, ); }; };
471AB98E23AB925D00F56D49 /* MWMMapSearchResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = 471AB98C23AB925D00F56D49 /* MWMMapSearchResult.mm */; };
471AB99123AB931000F56D49 /* MWMMapSearchResult+Core.h in Headers */ = {isa = PBXBuildFile; fileRef = 471AB98F23AB931000F56D49 /* MWMMapSearchResult+Core.h */; };
475784C22344B422008291A4 /* Framework.h in Headers */ = {isa = PBXBuildFile; fileRef = 475784C02344B421008291A4 /* Framework.h */; settings = {ATTRIBUTES = (Public, ); }; };
475784C32344B422008291A4 /* Framework.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 475784C12344B422008291A4 /* Framework.cpp */; };
479834EA2342697400724D1E /* MWMTag+Convenience.mm in Sources */ = {isa = PBXBuildFile; fileRef = 479834E62342697100724D1E /* MWMTag+Convenience.mm */; };
@ -43,9 +46,15 @@
47C637DC2354B79B00E12DE0 /* MWMSearchFrameworkHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47C637DA2354B79A00E12DE0 /* MWMSearchFrameworkHelper.mm */; };
47C637DD2354B79B00E12DE0 /* MWMSearchFrameworkHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 47C637DB2354B79B00E12DE0 /* MWMSearchFrameworkHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };
47D609DC234FE625008ECC47 /* MWMBookmarksObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 47D609DB234FE625008ECC47 /* MWMBookmarksObserver.h */; settings = {ATTRIBUTES = (Public, ); }; };
47D9019523AC22E500D9364C /* MWMMapUpdateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 47D9019323AC22E500D9364C /* MWMMapUpdateInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
47D9019623AC22E500D9364C /* MWMMapUpdateInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47D9019423AC22E500D9364C /* MWMMapUpdateInfo.mm */; };
47D9019923AC236100D9364C /* MWMMapUpdateInfo+Core.h in Headers */ = {isa = PBXBuildFile; fileRef = 47D9019723AC236100D9364C /* MWMMapUpdateInfo+Core.h */; settings = {ATTRIBUTES = (Public, ); }; };
47EEAFF42350CEDB005CF316 /* AppInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47EEAFF22350CEDA005CF316 /* AppInfo.mm */; };
47EEAFF62350CF48005CF316 /* AppInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 47EEAFF32350CEDB005CF316 /* AppInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
47EEAFF72350D060005CF316 /* MWMCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 47EEAFF52350CEF6005CF316 /* MWMCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
47F4F1F923A3336C0022FD56 /* MWMMapNodeAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 47F4F1F723A3336B0022FD56 /* MWMMapNodeAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; };
47F4F1FA23A3336C0022FD56 /* MWMMapNodeAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47F4F1F823A3336C0022FD56 /* MWMMapNodeAttributes.mm */; };
47F4F1FD23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h in Headers */ = {isa = PBXBuildFile; fileRef = 47F4F1FB23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h */; settings = {ATTRIBUTES = (Public, ); }; };
99103843237EDFA200893C9F /* DeepLinkData.h in Headers */ = {isa = PBXBuildFile; fileRef = 99103841237EDFA200893C9F /* DeepLinkData.h */; settings = {ATTRIBUTES = (Public, ); }; };
99103844237EDFA200893C9F /* DeepLinkData.m in Sources */ = {isa = PBXBuildFile; fileRef = 99103842237EDFA200893C9F /* DeepLinkData.m */; };
993F54F2237C5D1100545511 /* PromoDiscoveryCampaignAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 993F54EE237C5D1000545511 /* PromoDiscoveryCampaignAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -75,6 +84,9 @@
470016142342633D00EBF03D /* CoreApi.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = CoreApi.modulemap; sourceTree = "<group>"; };
4718C4302355FC3C00640DF1 /* MWMNetworkPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMNetworkPolicy.h; sourceTree = "<group>"; };
4718C4312355FC3C00640DF1 /* MWMNetworkPolicy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMNetworkPolicy.mm; sourceTree = "<group>"; };
471AB98B23AB925D00F56D49 /* MWMMapSearchResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapSearchResult.h; sourceTree = "<group>"; };
471AB98C23AB925D00F56D49 /* MWMMapSearchResult.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapSearchResult.mm; sourceTree = "<group>"; };
471AB98F23AB931000F56D49 /* MWMMapSearchResult+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapSearchResult+Core.h"; sourceTree = "<group>"; };
475784C02344B421008291A4 /* Framework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Framework.h; sourceTree = "<group>"; };
475784C12344B422008291A4 /* Framework.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Framework.cpp; sourceTree = "<group>"; };
479834E62342697100724D1E /* MWMTag+Convenience.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "MWMTag+Convenience.mm"; sourceTree = "<group>"; };
@ -104,9 +116,15 @@
47C637DA2354B79A00E12DE0 /* MWMSearchFrameworkHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSearchFrameworkHelper.mm; sourceTree = "<group>"; };
47C637DB2354B79B00E12DE0 /* MWMSearchFrameworkHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchFrameworkHelper.h; sourceTree = "<group>"; };
47D609DB234FE625008ECC47 /* MWMBookmarksObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMBookmarksObserver.h; sourceTree = "<group>"; };
47D9019323AC22E500D9364C /* MWMMapUpdateInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapUpdateInfo.h; sourceTree = "<group>"; };
47D9019423AC22E500D9364C /* MWMMapUpdateInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapUpdateInfo.mm; sourceTree = "<group>"; };
47D9019723AC236100D9364C /* MWMMapUpdateInfo+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapUpdateInfo+Core.h"; sourceTree = "<group>"; };
47EEAFF22350CEDA005CF316 /* AppInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = AppInfo.mm; sourceTree = "<group>"; };
47EEAFF32350CEDB005CF316 /* AppInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppInfo.h; sourceTree = "<group>"; };
47EEAFF52350CEF6005CF316 /* MWMCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMCommon.h; sourceTree = "<group>"; };
47F4F1F723A3336B0022FD56 /* MWMMapNodeAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapNodeAttributes.h; sourceTree = "<group>"; };
47F4F1F823A3336C0022FD56 /* MWMMapNodeAttributes.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapNodeAttributes.mm; sourceTree = "<group>"; };
47F4F1FB23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapNodeAttributes+Core.h"; sourceTree = "<group>"; };
99103841237EDFA200893C9F /* DeepLinkData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeepLinkData.h; sourceTree = "<group>"; };
99103842237EDFA200893C9F /* DeepLinkData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeepLinkData.m; sourceTree = "<group>"; };
991CE2E82375AF19009EB02A /* PromoAfterBookingCampaignAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PromoAfterBookingCampaignAdapter.mm; sourceTree = "<group>"; };
@ -163,6 +181,7 @@
470015F12342509C00EBF03D /* CoreApi */ = {
isa = PBXGroup;
children = (
47F4F1F623A333280022FD56 /* Storage */,
993F54ED237C5D1000545511 /* Promo */,
9957FAE5237AE59C00855F48 /* Logger */,
9957FAC1237AABD800855F48 /* DeepLink */,
@ -296,6 +315,22 @@
path = Search;
sourceTree = "<group>";
};
47F4F1F623A333280022FD56 /* Storage */ = {
isa = PBXGroup;
children = (
47F4F1F723A3336B0022FD56 /* MWMMapNodeAttributes.h */,
47F4F1FB23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h */,
47F4F1F823A3336C0022FD56 /* MWMMapNodeAttributes.mm */,
471AB98B23AB925D00F56D49 /* MWMMapSearchResult.h */,
471AB98F23AB931000F56D49 /* MWMMapSearchResult+Core.h */,
471AB98C23AB925D00F56D49 /* MWMMapSearchResult.mm */,
47D9019323AC22E500D9364C /* MWMMapUpdateInfo.h */,
47D9019723AC236100D9364C /* MWMMapUpdateInfo+Core.h */,
47D9019423AC22E500D9364C /* MWMMapUpdateInfo.mm */,
);
path = Storage;
sourceTree = "<group>";
};
99103840237ED97600893C9F /* Data */ = {
isa = PBXGroup;
children = (
@ -361,31 +396,37 @@
9957FAE8237AE5B000855F48 /* Logger.h in Headers */,
470015F42342509C00EBF03D /* CoreApi.h in Headers */,
479F705F234FBB8F00011E2E /* MWMCategory.h in Headers */,
471AB99123AB931000F56D49 /* MWMMapSearchResult+Core.h in Headers */,
47A65CAF235008E100DCD85F /* CoreApi-swift.h in Headers */,
9957FACE237AB01400855F48 /* DeepLinkParser.h in Headers */,
993F54F5237C5D1100545511 /* PromoAfterBookingCampaignAdapter.h in Headers */,
479834F223426CCC00724D1E /* MWMTag+Convenience.h in Headers */,
479F704F234FB60400011E2E /* MWMCatalogObserver.h in Headers */,
47EEAFF72350D060005CF316 /* MWMCommon.h in Headers */,
47D9019523AC22E500D9364C /* MWMMapUpdateInfo.h in Headers */,
9957FADB237ACB1100855F48 /* DeepLinkSearchData.h in Headers */,
479F7056234FB7F200011E2E /* MWMBookmarksManager.h in Headers */,
4718C4322355FC3C00640DF1 /* MWMNetworkPolicy.h in Headers */,
99103843237EDFA200893C9F /* DeepLinkData.h in Headers */,
47F4F1FD23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h in Headers */,
47C637DD2354B79B00E12DE0 /* MWMSearchFrameworkHelper.h in Headers */,
479F704B234F78AB00011E2E /* MWMFrameworkHelper.h in Headers */,
479834F323426CD200724D1E /* MWMTagGroup+Convenience.h in Headers */,
47D9019923AC236100D9364C /* MWMMapUpdateInfo+Core.h in Headers */,
999D3A64237B097C00C5F7A8 /* DeepLinkSubscriptionData.h in Headers */,
470016102342579200EBF03D /* MWMTagGroup.h in Headers */,
479F7063234FBC5900011E2E /* MWMCarPlayBookmarkObject.h in Headers */,
47EEAFF62350CF48005CF316 /* AppInfo.h in Headers */,
479F7053234FB7BC00011E2E /* MWMCatalogCommon.h in Headers */,
4700160F2342579000EBF03D /* MWMTag.h in Headers */,
47F4F1F923A3336C0022FD56 /* MWMMapNodeAttributes.h in Headers */,
479F705B234FBB1100011E2E /* MWMUTM.h in Headers */,
479F704A234F785B00011E2E /* MWMTypes.h in Headers */,
47C637D72354AEBE00E12DE0 /* MWMTrafficManager.h in Headers */,
993F54F2237C5D1100545511 /* PromoDiscoveryCampaignAdapter.h in Headers */,
99447849238559F2004DAEE5 /* DeeplinkParsingResult.h in Headers */,
47D609DC234FE625008ECC47 /* MWMBookmarksObserver.h in Headers */,
471AB98D23AB925D00F56D49 /* MWMMapSearchResult.h in Headers */,
475784C22344B422008291A4 /* Framework.h in Headers */,
47C637D22354A6FB00E12DE0 /* MWMEye.h in Headers */,
);
@ -463,6 +504,7 @@
9957FADC237ACB1100855F48 /* DeepLinkSearchData.mm in Sources */,
479F7050234FB60400011E2E /* MWMCatalogObserver.mm in Sources */,
9957FACF237AB01400855F48 /* DeepLinkParser.mm in Sources */,
47F4F1FA23A3336C0022FD56 /* MWMMapNodeAttributes.mm in Sources */,
99103844237EDFA200893C9F /* DeepLinkData.m in Sources */,
47C637D12354A6FB00E12DE0 /* MWMEye.mm in Sources */,
47C637DC2354B79B00E12DE0 /* MWMSearchFrameworkHelper.mm in Sources */,
@ -474,6 +516,8 @@
479F7057234FB7F200011E2E /* MWMBookmarksManager.mm in Sources */,
479F7047234F774100011E2E /* MWMFrameworkHelper.mm in Sources */,
470016072342541100EBF03D /* MWMTag.m in Sources */,
47D9019623AC22E500D9364C /* MWMMapUpdateInfo.mm in Sources */,
471AB98E23AB925D00F56D49 /* MWMMapSearchResult.mm in Sources */,
479834EA2342697400724D1E /* MWMTag+Convenience.mm in Sources */,
47C637D62354AEBE00E12DE0 /* MWMTrafficManager.mm in Sources */,
475784C32344B422008291A4 /* Framework.cpp in Sources */,

View file

@ -1,5 +1,7 @@
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
static inline BOOL firstVersionIsLessThanSecond(NSString * first, NSString * second)
{
NSArray<NSString *> * f = [first componentsSeparatedByString:@"."];
@ -51,3 +53,5 @@ static inline CGFloat statusBarHeight()
CGSize const statusBarSize = UIApplication.sharedApplication.statusBarFrame.size;
return MIN(statusBarSize.height, statusBarSize.width);
}
NS_ASSUME_NONNULL_END

View file

@ -25,3 +25,6 @@ FOUNDATION_EXPORT const unsigned char CoreApiVersionString[];
#import <CoreApi/DeepLinkSearchData.h>
#import <CoreApi/DeepLinkSubscriptionData.h>
#import <CoreApi/Logger.h>
#import <CoreApi/MWMMapNodeAttributes.h>
#import <CoreApi/MWMMapSearchResult.h>
#import <CoreApi/MWMMapUpdateInfo.h>

View file

@ -3,6 +3,8 @@
#import "MWMTypes.h"
@class MWMMapSearchResult;
typedef NS_ENUM(NSUInteger, MWMZoomMode) {
MWMZoomModeIn = 0,
MWMZoomModeOut
@ -10,6 +12,8 @@ typedef NS_ENUM(NSUInteger, MWMZoomMode) {
NS_ASSUME_NONNULL_BEGIN
typedef void (^SearchInDownloaderCompletions)(NSArray<MWMMapSearchResult *> *results, BOOL finished);
NS_SWIFT_NAME(FrameworkHelper)
@interface MWMFrameworkHelper : NSObject
@ -35,6 +39,9 @@ NS_SWIFT_NAME(FrameworkHelper)
+ (NSString *)userAccessToken;
+ (NSString *)userAgent;
+ (NSNumber *)dataVersion;
+ (void)searchInDownloader:(NSString *)query
inputLocale:(NSString *)locale
completion:(SearchInDownloaderCompletions)completion;
@end

View file

@ -1,4 +1,5 @@
#import "MWMFrameworkHelper.h"
#import "MWMMapSearchResult+Core.h"
#include "Framework.h"
@ -154,4 +155,21 @@
return @(GetFramework().GetCurrentDataVersion());
}
+ (void)searchInDownloader:(NSString *)query
inputLocale:(NSString *)locale
completion:(SearchInDownloaderCompletions)completion {
storage::DownloaderSearchParams searchParams;
searchParams.m_query = query.UTF8String;
searchParams.m_inputLocale = locale.precomposedStringWithCompatibilityMapping.UTF8String;
searchParams.m_onResults = [completion](storage::DownloaderSearchResults const &results) {
NSMutableArray *resultsArray = [NSMutableArray arrayWithCapacity:results.m_results.size()];
for (auto const &searchResult : results.m_results) {
MWMMapSearchResult *result = [[MWMMapSearchResult alloc] initWithSearchResult:searchResult];
[resultsArray addObject:result];
}
completion([resultsArray copy], results.m_endMarker);
};
GetFramework().SearchInDownloader(searchParams);
}
@end

View file

@ -0,0 +1,16 @@
#import "MWMMapNodeAttributes.h"
#include <CoreApi/Framework.h>
NS_ASSUME_NONNULL_BEGIN
@interface MWMMapNodeAttributes (Core)
- (instancetype)initWithCoreAttributes:(storage::NodeAttrs const &)attributes
countryId:(NSString *)countryId
hasParent:(BOOL)hasParent
hasChildren:(BOOL)hasChildren;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,47 @@
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, MWMMapNodeStatus) {
MWMMapNodeStatusUndefined,
MWMMapNodeStatusDownloading,
MWMMapNodeStatusApplying,
MWMMapNodeStatusInQueue,
MWMMapNodeStatusError,
MWMMapNodeStatusOnDiskOutOfDate,
MWMMapNodeStatusOnDisk,
MWMMapNodeStatusNotDownloaded,
MWMMapNodeStatusPartly
};
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(CountryIdAndName)
@interface MWMCountryIdAndName: NSObject
@property(nonatomic, readonly) NSString *countryId;
@property(nonatomic, readonly) NSString *countryName;
- (instancetype)initWithCountryId:(NSString *)countryId name:(NSString *)countryName;
@end
NS_SWIFT_NAME(MapNodeAttributes)
@interface MWMMapNodeAttributes : NSObject
@property(nonatomic, readonly) NSString *countryId;
@property(nonatomic, readonly) NSUInteger totalMwmCount;
@property(nonatomic, readonly) NSUInteger downloadedMwmCount;
@property(nonatomic, readonly) NSUInteger downloadingMwmCount;
@property(nonatomic, readonly) uint64_t totalSize;
@property(nonatomic, readonly) uint64_t downloadedSize;
@property(nonatomic, readonly) uint64_t downloadingSize;
@property(nonatomic, readonly) NSString *nodeName;
@property(nonatomic, readonly) NSString *nodeDescription;
@property(nonatomic, readonly) MWMMapNodeStatus nodeStatus;
@property(nonatomic, readonly) BOOL hasChildren;
@property(nonatomic, readonly) BOOL hasParent;
@property(nonatomic, readonly) NSArray<MWMCountryIdAndName *> *parentInfo;
@property(nonatomic, readonly, nullable) NSArray<MWMCountryIdAndName *> *topmostParentInfo;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,97 @@
#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;
}
}
@interface MWMCountryIdAndName ()
@property(nonatomic, copy) NSString *countryId;
@property(nonatomic, copy) NSString *countryName;
@end
@implementation MWMCountryIdAndName
- (instancetype)initWithCountryId:(NSString *)countryId name:(NSString *)countryName {
self = [super init];
if (self) {
_countryId = countryId;
_countryName = countryName;
}
return self;
}
- (instancetype)initWithCountryAndName:(storage::CountryIdAndName const &)countryAndName {
self = [super init];
if (self) {
_countryId = @(countryAndName.m_id.c_str());
_countryName = @(countryAndName.m_localName.c_str());
}
return self;
}
@end
@implementation MWMMapNodeAttributes
@end
@implementation MWMMapNodeAttributes (Core)
- (instancetype)initWithCoreAttributes:(storage::NodeAttrs const &)attributes
countryId:(NSString *)countryId
hasParent:(BOOL)hasParent
hasChildren:(BOOL)hasChildren {
self = [super init];
if (self) {
_countryId = [countryId copy];
_totalMwmCount = attributes.m_mwmCounter;
_downloadedMwmCount = attributes.m_localMwmCounter;
_downloadingMwmCount = attributes.m_downloadingMwmCounter - attributes.m_localMwmCounter;
_totalSize = attributes.m_mwmSize;
_downloadedSize = attributes.m_localMwmSize;
_downloadingSize = attributes.m_downloadingMwmSize - attributes.m_localMwmSize;
_nodeName = @(attributes.m_nodeLocalName.c_str());
_nodeDescription = @(attributes.m_nodeLocalDescription.c_str());
_nodeStatus = convertStatus(attributes.m_status);
_hasChildren = hasChildren;
_hasParent = hasParent;
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];
[topmostInfoArray addObject:cn];
}
_topmostParentInfo = topmostInfoArray.count > 0 ? [topmostInfoArray copy] : nil;
}
return self;
}
@end

View file

@ -0,0 +1,13 @@
#import "MWMMapSearchResult.h"
#include <CoreApi/Framework.h>
NS_ASSUME_NONNULL_BEGIN
@interface MWMMapSearchResult (Core)
- (instancetype)initWithSearchResult:(storage::DownloaderSearchResult const &)searchResult;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(MapSearchResult)
@interface MWMMapSearchResult : NSObject
@property(nonatomic, readonly) NSString *countryId;
@property(nonatomic, readonly) NSString *matchedName;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,18 @@
#import "MWMMapSearchResult+Core.h"
@implementation MWMMapSearchResult
@end
@implementation MWMMapSearchResult (Core)
- (instancetype)initWithSearchResult:(storage::DownloaderSearchResult const &)searchResult {
self = [super init];
if (self) {
_countryId = @(searchResult.m_countryId.c_str());
_matchedName = @(searchResult.m_matchedName.c_str());
}
return self;
}
@end

View file

@ -0,0 +1,13 @@
#import "MWMMapUpdateInfo.h"
#include <CoreApi/Framework.h>
NS_ASSUME_NONNULL_BEGIN
@interface MWMMapUpdateInfo (Core)
- (instancetype)initWithUpdateInfo:(storage::Storage::UpdateInfo const &)updateInfo;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,14 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(MapUpdateInfo)
@interface MWMMapUpdateInfo : NSObject
@property(nonatomic, readonly) uint32_t numberOfFiles;
@property(nonatomic, readonly) uint64_t updateSize;
@property(nonatomic, readonly) uint64_t differenceSize;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,19 @@
#import "MWMMapUpdateInfo+Core.h"
@implementation MWMMapUpdateInfo
@end
@implementation MWMMapUpdateInfo (Core)
- (instancetype)initWithUpdateInfo:(storage::Storage::UpdateInfo const &)updateInfo {
self = [super init];
if (self) {
_numberOfFiles = updateInfo.m_numberOfMwmFilesToUpdate;
_updateSize = updateInfo.m_totalUpdateSizeInBytes;
_differenceSize = updateInfo.m_sizeDifference;
}
return self;
}
@end

View file

@ -38,10 +38,17 @@
#import "MWMConsts.h"
#import "MWMController.h"
#import "MWMEditorHelper.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMGeoTrackerCore.h"
#import "MWMKeyboard.h"
#import "MWMLocationManager.h"
#import "MWMMapWidgetsHelper.h"
#import "MWMMapDownloaderTableViewCell.h"
#import "MWMMapDownloaderPlaceTableViewCell.h"
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
#import "MWMMapDownloaderSubplaceTableViewCell.h"
#import "MWMMapDownloaderCellHeader.h"
#import "MWMNavigationController.h"
#import "MWMNavigationDashboardEntity.h"
#import "MWMNavigationDashboardManager.h"
@ -62,6 +69,7 @@
#import "MWMSearchNoResults.h"
#import "MWMSettings.h"
#import "MWMSideButtons.h"
#import "MWMStorage.h"
#import "MWMTableViewCell.h"
#import "MWMTableViewController.h"
#import "MWMTextToSpeech.h"

View file

@ -3,6 +3,7 @@
#import "MWMDownloaderDialogCell.h"
#import "MWMDownloaderDialogHeader.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMStorage.h"
#import "Statistics.h"
#import "SwiftBridge.h"
@ -118,7 +119,7 @@ CGFloat const kAnimationDuration = .05;
auto const & s = GetFramework().GetStorage();
m_countries.erase(
remove_if(m_countries.begin(), m_countries.end(),
[&s](CountryId const & countryId) { return s.HasLatestVersion(countryId); }),
[&s](storage::CountryId const & countryId) { return s.HasLatestVersion(countryId); }),
m_countries.end());
NSMutableArray<NSString *> * titles = [@[] mutableCopy];
MwmSize totalSize = 0;
@ -138,15 +139,15 @@ CGFloat const kAnimationDuration = .05;
- (void)progressButtonPressed:(nonnull MWMCircularProgress *)progress
{
for (auto const & countryId : m_countries)
[MWMStorage cancelDownloadNode:countryId];
[MWMStorage cancelDownloadNode:@(countryId.c_str())];
[self cancelButtonTap];
}
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
- (void)processCountryEvent:(NSString *)countryId
{
if (find(m_countries.begin(), m_countries.end(), countryId) == m_countries.end())
if (find(m_countries.begin(), m_countries.end(), countryId.UTF8String) == m_countries.end())
return;
if (self.rightButton.hidden)
{
@ -173,11 +174,12 @@ CGFloat const kAnimationDuration = .05;
}
}
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress
- (void)processCountry:(NSString *)countryId
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes
{
if (!self.rightButton.hidden ||
find(m_countries.begin(), m_countries.end(), countryId) == m_countries.end())
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.first) / overallProgress.second;

View file

@ -9,9 +9,10 @@
#import "MWMEditorViewController.h"
#import "MWMFacilitiesController.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMFrameworkObservers.h"
#import "MWMLocationHelpers.h"
#import "MWMMapDownloadDialog.h"
#import "MWMMapDownloaderViewController.h"
#import "MWMMapViewControlsManager.h"
#import "MWMPlacePageProtocol.h"
#import "MapsAppDelegate.h"
@ -630,9 +631,9 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
- (void)processCountryEvent:(NSString *)countryId
{
if (countryId.empty())
if (countryId.length == 0)
{
#ifdef OMIM_PRODUCTION
auto err = [[NSError alloc] initWithDomain:kMapsmeErrorDomain code:1
@ -643,7 +644,7 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
}
NodeStatuses nodeStatuses{};
GetFramework().GetStorage().GetNodeStatuses(countryId, nodeStatuses);
GetFramework().GetStorage().GetNodeStatuses(countryId.UTF8String, nodeStatuses);
if (nodeStatuses.m_status != NodeStatus::Error)
return;
switch (nodeStatuses.m_error)
@ -733,10 +734,9 @@ NSString * const kHotelFacilitiesSegue = @"Map2FacilitiesSegue";
}
else if ([segue.identifier isEqualToString:kDownloaderSegue])
{
MWMMapDownloaderViewController * dvc = segue.destinationViewController;
MWMDownloadMapsViewController * dvc = segue.destinationViewController;
NSNumber * mode = sender;
[dvc setParentCountryId:@(GetFramework().GetStorage().GetRootId().c_str())
mode:static_cast<MWMMapDownloaderMode>(mode.integerValue)];
dvc.mode = (MWMMapDownloaderMode)mode.integerValue;
}
else if ([segue.identifier isEqualToString:kMap2FBLoginSegue])
{

View file

@ -651,7 +651,7 @@ continueUserActivity:(NSUserActivity *)userActivity
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(storage::CountryId const &)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.

View file

@ -4,6 +4,7 @@
#import "MWMBookmarksBannerViewController.h"
#import "MWMCircularProgress.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMMegafonBannerViewController.h"
#import "MWMStorage.h"
#import "MapViewController.h"
@ -133,7 +134,7 @@ using namespace storage;
kStatScenario: kStatDownload
}];
m_autoDownloadCountryId = m_countryId;
[MWMStorage downloadNode:m_countryId
[MWMStorage downloadNode:@(m_countryId.c_str())
onSuccess:^{
[self showInQueue];
}
@ -211,11 +212,11 @@ using namespace storage;
kStatScenario: kStatDownload
}];
[self showInQueue];
[MWMStorage retryDownloadNode:self->m_countryId];
[MWMStorage retryDownloadNode:@(self->m_countryId.c_str())];
};
auto const cancelBlock = ^{
[Statistics logEvent:kStatDownloaderDownloadCancel withParameters:@{kStatFrom: kStatMap}];
[MWMStorage cancelDownloadNode:self->m_countryId];
[MWMStorage cancelDownloadNode:@(self->m_countryId.c_str())];
};
switch (errorCode) {
case NodeErrorCode::NoError:
@ -370,8 +371,8 @@ using namespace storage;
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId {
if (m_countryId != countryId)
- (void)processCountryEvent:(NSString *)countryId {
if (m_countryId != countryId.UTF8String)
return;
if (self.superview)
[self configDialog];
@ -379,9 +380,11 @@ using namespace storage;
[self removeFromSuperview];
}
- (void)processCountry:(CountryId const &)countryId progress:(MapFilesDownloader::Progress const &)progress {
if (self.superview && m_countryId == countryId)
[self showDownloading:(CGFloat)progress.first / progress.second];
- (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
@ -396,12 +399,12 @@ using namespace storage;
kStatScenario: kStatDownload
}];
[self showInQueue];
[MWMStorage retryDownloadNode:m_countryId];
[MWMStorage retryDownloadNode:@(m_countryId.c_str())];
} else {
[Statistics logEvent:kStatDownloaderDownloadCancel withParameters:@{kStatFrom: kStatMap}];
if (m_autoDownloadCountryId == m_countryId)
self.isAutoDownloadCancelled = YES;
[MWMStorage cancelDownloadNode:m_countryId];
[MWMStorage cancelDownloadNode:@(m_countryId.c_str())];
}
}
@ -424,7 +427,7 @@ using namespace storage;
kStatFrom: kStatMap,
kStatScenario: kStatDownload
}];
[MWMStorage downloadNode:m_countryId
[MWMStorage downloadNode:@(m_countryId.c_str())
onSuccess:^{ [self showInQueue]; }
onCancel:nil];
}

View file

@ -1,4 +1,6 @@
#import "MWMFrameworkObservers.h"
#import "MWMFrameworkObserver.h"
NS_ASSUME_NONNULL_BEGIN
@interface MWMFrameworkListener : NSObject
@ -14,3 +16,5 @@
+ (instancetype) new __attribute__((unavailable("call +listener instead")));
@end
NS_ASSUME_NONNULL_END

View file

@ -1,4 +1,5 @@
#import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h"
#include <CoreApi/Framework.h>
@ -144,13 +145,13 @@ void loopWrappers(Observers * observers, TLoopBlock block)
s.Subscribe(
[observers](CountryId const & countryId) {
for (TStorageObserver observer in observers)
[observer processCountryEvent:countryId];
[observer processCountryEvent:@(countryId.c_str())];
},
[observers](CountryId const & countryId, MapFilesDownloader::Progress const & progress) {
for (TStorageObserver observer in observers)
{
if ([observer respondsToSelector:@selector(processCountry:progress:)])
[observer processCountry:countryId progress:progress];
if ([observer respondsToSelector:@selector(processCountry:downloadedBytes:totalBytes:)])
[observer processCountry:@(countryId.c_str()) downloadedBytes:progress.first totalBytes:progress.second];
}
});
}

View file

@ -0,0 +1,3 @@
@protocol MWMFrameworkObserver<NSObject>
@end

View file

@ -1,3 +1,5 @@
#import "MWMFrameworkObserver.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMRouterRecommendation.h"
#include "routing/router.hpp"
@ -7,10 +9,6 @@
using namespace storage;
@protocol MWMFrameworkObserver<NSObject>
@end
@protocol MWMFrameworkRouteBuilderObserver<MWMFrameworkObserver>
- (void)processRouteBuilderEvent:(routing::RouterResultCode)code
@ -25,17 +23,6 @@ using namespace storage;
@end
@protocol MWMFrameworkStorageObserver<MWMFrameworkObserver>
- (void)processCountryEvent:(CountryId const &)countryId;
@optional
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress;
@end
@protocol MWMFrameworkDrapeObserver<MWMFrameworkObserver>
@optional

View file

@ -0,0 +1,17 @@
#import "MWMFrameworkObserver.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MWMFrameworkStorageObserver<MWMFrameworkObserver>
- (void)processCountryEvent:(NSString *)countryId;
@optional
- (void)processCountry:(NSString *)countryId
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes;
@end
NS_ASSUME_NONNULL_END

View file

@ -2,6 +2,7 @@
#import "MWMLocationManager.h"
#import "MWMLocationObserver.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h"
#import "MWMCoreRouterType.h"
#import "MWMRoutePoint+CPP.h"
#import "MWMCoreUnits.h"

View file

@ -3,6 +3,7 @@
#import "MWMAlertViewController+CPP.h"
#import "MWMCoreRouterType.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h"
#import "MWMLocationHelpers.h"
#import "MWMLocationObserver.h"
#import "MWMMapViewControlsManager.h"
@ -721,7 +722,11 @@ void logPointEvent(MWMRoutePoint * point, NSString * eventType)
[MWMRouter stopRouting];
}
downloadBlock:^(storage::CountriesVec const & downloadCountries, MWMVoidBlock onSuccess) {
[MWMStorage downloadNodes:downloadCountries
NSMutableArray *array = [NSMutableArray arrayWithCapacity:downloadCountries.size()];
for (auto const &cid : downloadCountries) {
[array addObject:@(cid.c_str())];
}
[MWMStorage downloadNodes:array
onSuccess:onSuccess
onCancel:nil];
}

View file

@ -1,6 +1,7 @@
#import "MWMSearch.h"
#import "MWMBannerHelpers.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkObservers.h"
#import "SwiftBridge.h"
#include <CoreApi/Framework.h>

View file

@ -1,19 +1,41 @@
#include "storage/storage_defines.hpp"
@class MWMMapNodeAttributes;
@class MWMMapUpdateInfo;
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(Storage)
@interface MWMStorage : NSObject
+ (void)downloadNode:(storage::CountryId const &)countryId
onSuccess:(MWMVoidBlock)onSuccess
onCancel:(MWMVoidBlock)onCancel;
+ (void)retryDownloadNode:(storage::CountryId const &)countryId;
+ (void)updateNode:(storage::CountryId const &)countryId
onCancel:(MWMVoidBlock)onCancel;
+ (void)deleteNode:(storage::CountryId const &)countryId;
+ (void)cancelDownloadNode:(storage::CountryId const &)countryId;
+ (void)showNode:(storage::CountryId const &)countryId;
+ (void)downloadNode:(NSString *)countryId
onSuccess:(nullable MWMVoidBlock)onSuccess
onCancel:(nullable MWMVoidBlock)onCancel;
+ (void)retryDownloadNode:(NSString *)countryId;
+ (void)updateNode:(NSString *)countryId
onCancel:(nullable MWMVoidBlock)onCancel;
+ (void)deleteNode:(NSString *)countryId;
+ (void)cancelDownloadNode:(NSString *)countryId;
+ (void)showNode:(NSString *)countryId;
+ (void)downloadNodes:(storage::CountriesVec const &)countryIds
onSuccess:(MWMVoidBlock)onSuccess
onCancel:(MWMVoidBlock)onCancel;
+ (void)downloadNodes:(NSArray<NSString *> *)countryIds
onSuccess:(nullable MWMVoidBlock)onSuccess
onCancel:(nullable MWMVoidBlock)onCancel;
+ (BOOL)haveDownloadedCountries;
+ (BOOL)downloadInProgress;
#pragma mark - Attributes
+ (NSArray<NSString *> *)allCountries;
+ (NSArray<NSString *> *)allCountriesWithParent:(NSString *)countryId;
+ (NSArray<NSString *> *)availableCountriesWithParent:(NSString *)countryId;
+ (NSArray<NSString *> *)downloadedCountries;
+ (NSArray<NSString *> *)downloadedCountriesWithParent:(NSString *)countryId;
+ (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId;
+ (MWMMapNodeAttributes *)attributesForRoot;
+ (NSString *)nameForCountry:(NSString *)countryId;
+ (nullable NSArray<NSString *> *)nearbyAvailableCountries:(CLLocationCoordinate2D)location;
+ (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId;
@end
NS_ASSUME_NONNULL_END

View file

@ -1,8 +1,9 @@
#import "MWMStorage.h"
#import "MWMAlertViewController.h"
#import "MWMRouter.h"
#include <CoreApi/Framework.h>
#import <CoreApi/MWMMapNodeAttributes+Core.h>
#import <CoreApi/MWMMapUpdateInfo+Core.h>
#include "storage/storage_helpers.hpp"
@ -10,12 +11,12 @@ using namespace storage;
@implementation MWMStorage
+ (void)downloadNode:(CountryId const &)countryId onSuccess:(MWMVoidBlock)onSuccess onCancel:(MWMVoidBlock)onCancel
+ (void)downloadNode:(NSString *)countryId onSuccess:(MWMVoidBlock)onSuccess onCancel:(MWMVoidBlock)onCancel
{
if (IsEnoughSpaceForDownload(countryId, GetFramework().GetStorage()))
if (IsEnoughSpaceForDownload(countryId.UTF8String, GetFramework().GetStorage()))
{
[self checkConnectionAndPerformAction:[countryId, onSuccess] {
GetFramework().GetStorage().DownloadNode(countryId);
GetFramework().GetStorage().DownloadNode(countryId.UTF8String);
if (onSuccess)
onSuccess();
} cancelAction:onCancel];
@ -28,19 +29,19 @@ using namespace storage;
}
}
+ (void)retryDownloadNode:(CountryId const &)countryId
+ (void)retryDownloadNode:(NSString *)countryId
{
[self checkConnectionAndPerformAction:[countryId] {
GetFramework().GetStorage().RetryDownloadNode(countryId);
GetFramework().GetStorage().RetryDownloadNode(countryId.UTF8String);
} cancelAction:nil];
}
+ (void)updateNode:(CountryId const &)countryId onCancel:(MWMVoidBlock)onCancel
+ (void)updateNode:(NSString *)countryId onCancel:(MWMVoidBlock)onCancel
{
if (IsEnoughSpaceForUpdate(countryId, GetFramework().GetStorage()))
if (IsEnoughSpaceForUpdate(countryId.UTF8String, GetFramework().GetStorage()))
{
[self checkConnectionAndPerformAction:[countryId] {
GetFramework().GetStorage().UpdateNode(countryId);
GetFramework().GetStorage().UpdateNode(countryId.UTF8String);
} cancelAction:onCancel];
}
else
@ -51,49 +52,49 @@ using namespace storage;
}
}
+ (void)deleteNode:(CountryId const &)countryId
+ (void)deleteNode:(NSString *)countryId
{
if ([MWMRouter isRoutingActive])
auto & f = GetFramework();
if (f.GetRoutingManager().IsRoutingActive())
{
[[MWMAlertViewController activeAlertController] presentDeleteMapProhibitedAlert];
return;
}
auto & f = GetFramework();
if (f.HasUnsavedEdits(countryId))
if (f.HasUnsavedEdits(countryId.UTF8String))
{
[[MWMAlertViewController activeAlertController]
presentUnsavedEditsAlertWithOkBlock:[countryId] {
GetFramework().GetStorage().DeleteNode(countryId);
GetFramework().GetStorage().DeleteNode(countryId.UTF8String);
}];
}
else
{
f.GetStorage().DeleteNode(countryId);
f.GetStorage().DeleteNode(countryId.UTF8String);
}
}
+ (void)cancelDownloadNode:(CountryId const &)countryId
+ (void)cancelDownloadNode:(NSString *)countryId
{
GetFramework().GetStorage().CancelDownloadNode(countryId);
GetFramework().GetStorage().CancelDownloadNode(countryId.UTF8String);
}
+ (void)showNode:(CountryId const &)countryId { GetFramework().ShowNode(countryId); }
+ (void)downloadNodes:(CountriesVec const &)countryIds onSuccess:(MWMVoidBlock)onSuccess onCancel:(MWMVoidBlock)onCancel
+ (void)showNode:(NSString *)countryId { GetFramework().ShowNode(countryId.UTF8String); }
+ (void)downloadNodes:(NSArray<NSString *> *)countryIds onSuccess:(MWMVoidBlock)onSuccess onCancel:(MWMVoidBlock)onCancel
{
auto & s = GetFramework().GetStorage();
MwmSize requiredSize =
std::accumulate(countryIds.begin(), countryIds.end(), s.GetMaxMwmSizeBytes(),
[](size_t const & size, CountryId const & countryId) {
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(countryId, nodeAttrs);
return size + nodeAttrs.m_mwmSize;
});
MwmSize requiredSize = s.GetMaxMwmSizeBytes();
for (NSString *countryId in countryIds) {
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(countryId.UTF8String, nodeAttrs);
requiredSize += nodeAttrs.m_mwmSize;
}
if (storage::IsEnoughSpaceForDownload(requiredSize))
{
[self checkConnectionAndPerformAction:[countryIds, onSuccess, &s] {
for (auto const & countryId : countryIds)
s.DownloadNode(countryId);
for (NSString *countryId in countryIds)
s.DownloadNode(countryId.UTF8String);
if (onSuccess)
onSuccess();
} cancelAction: onCancel];
@ -136,4 +137,115 @@ using namespace storage;
}
}
+ (BOOL)haveDownloadedCountries {
return GetFramework().GetStorage().HaveDownloadedCountries();
}
+ (BOOL)downloadInProgress {
return GetFramework().GetStorage().IsDownloadInProgress();
}
#pragma mark - Attributes
+ (NSArray<NSString *> *)allCountries {
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self allCountriesWithParent:rootId];
}
+ (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) {
[result addObject:@(cid.c_str())];
}
return [result copy];
}
+ (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) {
[result addObject:@(cid.c_str())];
}
return [result copy];
}
+ (NSArray<NSString *> *)downloadedCountries {
NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str());
return [self downloadedCountriesWithParent:rootId];
}
+ (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) {
[result addObject:@(cid.c_str())];
}
return [result copy];
}
+ (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId {
auto const &s = GetFramework().GetStorage();
storage::NodeAttrs nodeAttrs;
s.GetNodeAttrs(countryId.UTF8String, nodeAttrs);
storage::CountriesVec children;
s.GetChildren(countryId.UTF8String, children);
BOOL isParentRoot = nodeAttrs.m_parentInfo.size() == 1 && nodeAttrs.m_parentInfo[0].m_id == s.GetRootId();
return [[MWMMapNodeAttributes alloc] initWithCoreAttributes:nodeAttrs
countryId:countryId
hasParent:!isParentRoot
hasChildren:!children.empty()];
}
+ (MWMMapNodeAttributes *)attributesForRoot {
return [self attributesForCountry:@(GetFramework().GetStorage().GetRootId().c_str())];
}
+ (NSString *)nameForCountry:(NSString *)countryId {
return @(GetFramework().GetStorage().GetNodeLocalName(countryId.UTF8String).c_str());
}
+ (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) {
storage::NodeStatuses nodeStatuses;
f.GetStorage().GetNodeStatuses(countryId, nodeStatuses);
if (nodeStatuses.m_status != storage::NodeStatus::OnDisk)
[nearmeCountries addObject:@(countryId.c_str())];
}
return nearmeCountries.count > 0 ? [nearmeCountries copy] : nil;
}
+ (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId {
auto const &s = GetFramework().GetStorage();
Storage::UpdateInfo updateInfo;
if (countryId.length > 0) {
s.GetUpdateInfo(countryId.UTF8String, updateInfo);
} else {
s.GetUpdateInfo(s.GetRootId(), updateInfo);
}
return [[MWMMapUpdateInfo alloc] initWithUpdateInfo:updateInfo];
}
@end

View file

@ -357,6 +357,8 @@
4719A645219CBD65009F9AA7 /* IPendingTransactionsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4719A644219CBD65009F9AA7 /* IPendingTransactionsHandler.swift */; };
4719A647219CBD7F009F9AA7 /* IBillingPendingTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4719A646219CBD7F009F9AA7 /* IBillingPendingTransaction.swift */; };
4719A64E21A30C3B009F9AA7 /* PaidRouteStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4719A64D21A30C3B009F9AA7 /* PaidRouteStatistics.swift */; };
471AB98923AA8A3500F56D49 /* IDownloaderDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471AB98823AA8A3500F56D49 /* IDownloaderDataSource.swift */; };
471AB99423ABA3BD00F56D49 /* SearchMapsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471AB99323ABA3BD00F56D49 /* SearchMapsDataSource.swift */; };
471BBD942130390F00EB17C9 /* TutorialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471BBD932130390F00EB17C9 /* TutorialViewController.swift */; };
471C448C2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471C448A2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift */; };
471C448D2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 471C448B2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib */; };
@ -372,6 +374,7 @@
472E3F4A2146C4CD0020E412 /* MWMPurchaseManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 472E3F492146C4CD0020E412 /* MWMPurchaseManager.mm */; };
472E3F4C2147D5700020E412 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472E3F4B2147D5700020E412 /* Subscription.swift */; };
473464A7218B0BC000D6AF5B /* MWMPurchaseValidation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 473464A6218B0BC000D6AF5B /* MWMPurchaseValidation.mm */; };
4735008A23A83CF700661A95 /* DownloadedMapsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4735008923A83CF700661A95 /* DownloadedMapsDataSource.swift */; };
473CBF9B2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */; };
474AC76C2139E4F2002F9BF9 /* RemoveAdsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */; };
474AC76D2139E4F2002F9BF9 /* RemoveAdsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */; };
@ -437,6 +440,8 @@
47E6CB0B2178BA3600EA102B /* SearchBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47E6CB092178BA3600EA102B /* SearchBannerCell.swift */; };
47E6CB0C2178BA3600EA102B /* SearchBannerCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47E6CB0A2178BA3600EA102B /* SearchBannerCell.xib */; };
47EF05B321504D8F00EAC269 /* RemoveAdsPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EF05B221504D8F00EAC269 /* RemoveAdsPresentationController.swift */; };
47F4F21323A6EC420022FD56 /* DownloadMapsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */; };
47F4F21523A6F06F0022FD56 /* AvailableMapsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */; };
47F67D1521CAB21B0069754E /* MWMImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 47F67D1421CAB21B0069754E /* MWMImageCoder.m */; };
47F6E51221F61908004580CA /* CoreNotificationWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47F6E51121F61908004580CA /* CoreNotificationWrapper.mm */; };
47F6E51721FB3C51004580CA /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F6E51621FB3C51004580CA /* Notifications.swift */; };
@ -710,26 +715,17 @@
F6D67CDE2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6D67CDD2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib */; };
F6D67CE9206929590032FD38 /* PPPSearchSimilarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D67CE8206929590032FD38 /* PPPSearchSimilarButton.swift */; };
F6D67CEB2069318B0032FD38 /* PPPSearchSimilarButton.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6D67CEA2069318B0032FD38 /* PPPSearchSimilarButton.xib */; };
F6E2FD501E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.m */; };
F6E2FD531E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC001E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.xib */; };
F6E2FD561E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC021E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.m */; };
F6E2FD591E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC031E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.xib */; };
F6E2FD5C1E097BA00083EBEC /* MWMMapDownloaderCellHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC051E097B9F0083EBEC /* MWMMapDownloaderCellHeader.m */; };
F6E2FD5F1E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm */; };
F6E2FD5F1E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m */; };
F6E2FD621E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC081E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.xib */; };
F6E2FD651E097BA00083EBEC /* MWMMapDownloaderPlaceTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC0A1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.mm */; };
F6E2FD681E097BA00083EBEC /* MWMMapDownloaderPlaceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC0B1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.xib */; };
F6E2FD6B1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm */; };
F6E2FD6B1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m */; };
F6E2FD6E1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC0E1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.xib */; };
F6E2FD711E097BA00083EBEC /* MWMMapDownloaderTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC101E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.mm */; };
F6E2FD741E097BA00083EBEC /* MWMMapDownloaderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC111E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.xib */; };
F6E2FD771E097BA00083EBEC /* MWMMapDownloaderDataSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC151E097B9F0083EBEC /* MWMMapDownloaderDataSource.mm */; };
F6E2FD7A1E097BA00083EBEC /* MWMMapDownloaderDefaultDataSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC171E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.mm */; };
F6E2FD7D1E097BA00083EBEC /* MWMMapDownloaderExtendedDataSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC191E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.mm */; };
F6E2FD801E097BA00083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC1B1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm */; };
F6E2FD831E097BA00083EBEC /* MWMMapDownloaderSearchDataSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC1D1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.mm */; };
F6E2FD861E097BA00083EBEC /* MWMBaseMapDownloaderViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC1F1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.mm */; };
F6E2FD891E097BA00083EBEC /* MWMMapDownloaderViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC231E097B9F0083EBEC /* MWMMapDownloaderViewController.mm */; };
F6E2FD8C1E097BA00083EBEC /* MWMNoMapsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC261E097B9F0083EBEC /* MWMNoMapsView.m */; };
F6E2FD8F1E097BA00083EBEC /* MWMNoMapsViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC281E097B9F0083EBEC /* MWMNoMapsViewController.mm */; };
F6E2FD921E097BA00083EBEC /* MWMBookmarkColorViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC2B1E097B9F0083EBEC /* MWMBookmarkColorViewController.mm */; };
@ -1445,6 +1441,8 @@
4719A644219CBD65009F9AA7 /* IPendingTransactionsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPendingTransactionsHandler.swift; sourceTree = "<group>"; };
4719A646219CBD7F009F9AA7 /* IBillingPendingTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBillingPendingTransaction.swift; sourceTree = "<group>"; };
4719A64D21A30C3B009F9AA7 /* PaidRouteStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaidRouteStatistics.swift; sourceTree = "<group>"; };
471AB98823AA8A3500F56D49 /* IDownloaderDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IDownloaderDataSource.swift; sourceTree = "<group>"; };
471AB99323ABA3BD00F56D49 /* SearchMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchMapsDataSource.swift; sourceTree = "<group>"; };
471BBD932130390F00EB17C9 /* TutorialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TutorialViewController.swift; sourceTree = "<group>"; };
471C448A2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionGoToCatalogViewController.swift; sourceTree = "<group>"; };
471C448B2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SubscriptionGoToCatalogViewController.xib; sourceTree = "<group>"; };
@ -1464,6 +1462,9 @@
472E3F4B2147D5700020E412 /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = "<group>"; };
473464A5218B0BC000D6AF5B /* MWMPurchaseValidation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMPurchaseValidation.h; sourceTree = "<group>"; };
473464A6218B0BC000D6AF5B /* MWMPurchaseValidation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPurchaseValidation.mm; sourceTree = "<group>"; };
4735008923A83CF700661A95 /* DownloadedMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedMapsDataSource.swift; sourceTree = "<group>"; };
473500C023A8F81800661A95 /* MWMFrameworkObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkObserver.h; sourceTree = "<group>"; };
473500C123A8F85A00661A95 /* MWMFrameworkStorageObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkStorageObserver.h; sourceTree = "<group>"; };
473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSelectableProgressCell.swift; sourceTree = "<group>"; };
474902D8224A54EC008D71E0 /* MWMRoutingOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMRoutingOptions.h; sourceTree = "<group>"; };
474902D9224A54EC008D71E0 /* MWMRoutingOptions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMRoutingOptions.mm; sourceTree = "<group>"; };
@ -1545,6 +1546,8 @@
47E6CB092178BA3600EA102B /* SearchBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBannerCell.swift; sourceTree = "<group>"; };
47E6CB0A2178BA3600EA102B /* SearchBannerCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchBannerCell.xib; sourceTree = "<group>"; };
47EF05B221504D8F00EAC269 /* RemoveAdsPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsPresentationController.swift; sourceTree = "<group>"; };
47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadMapsViewController.swift; sourceTree = "<group>"; };
47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableMapsDataSource.swift; sourceTree = "<group>"; };
47F67D0F21CA8F800069754E /* IMWMWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMWMWebImage.h; sourceTree = "<group>"; };
47F67D1321CAB21B0069754E /* MWMImageCoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMImageCoder.h; sourceTree = "<group>"; };
47F67D1421CAB21B0069754E /* MWMImageCoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMImageCoder.m; sourceTree = "<group>"; };
@ -1894,43 +1897,24 @@
F6D67CE8206929590032FD38 /* PPPSearchSimilarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPPSearchSimilarButton.swift; sourceTree = "<group>"; };
F6D67CEA2069318B0032FD38 /* PPPSearchSimilarButton.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PPPSearchSimilarButton.xib; sourceTree = "<group>"; };
F6DF5F321CD1136800A87154 /* LocaleTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocaleTranslator.h; sourceTree = "<group>"; };
F6E2FBFE1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderAdsTableViewCell.h; sourceTree = "<group>"; };
F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderAdsTableViewCell.m; sourceTree = "<group>"; };
F6E2FC001E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderAdsTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC011E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderButtonTableViewCell.h; sourceTree = "<group>"; };
F6E2FC021E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderButtonTableViewCell.m; sourceTree = "<group>"; };
F6E2FC031E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderButtonTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC041E097B9F0083EBEC /* MWMMapDownloaderCellHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderCellHeader.h; sourceTree = "<group>"; };
F6E2FC051E097B9F0083EBEC /* MWMMapDownloaderCellHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderCellHeader.m; sourceTree = "<group>"; };
F6E2FC061E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderLargeCountryTableViewCell.h; sourceTree = "<group>"; };
F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderLargeCountryTableViewCell.mm; sourceTree = "<group>"; };
F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderLargeCountryTableViewCell.m; sourceTree = "<group>"; };
F6E2FC081E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderLargeCountryTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC091E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderPlaceTableViewCell.h; sourceTree = "<group>"; };
F6E2FC0A1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderPlaceTableViewCell.mm; sourceTree = "<group>"; };
F6E2FC0B1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderPlaceTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC0C1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderSubplaceTableViewCell.h; sourceTree = "<group>"; };
F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderSubplaceTableViewCell.mm; sourceTree = "<group>"; };
F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderSubplaceTableViewCell.m; sourceTree = "<group>"; };
F6E2FC0E1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderSubplaceTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC0F1E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderTableViewCell.h; sourceTree = "<group>"; };
F6E2FC101E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderTableViewCell.mm; sourceTree = "<group>"; };
F6E2FC111E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderTableViewCell.xib; sourceTree = "<group>"; };
F6E2FC121E097B9F0083EBEC /* MWMMapDownloaderTableViewCellProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderTableViewCellProtocol.h; sourceTree = "<group>"; };
F6E2FC141E097B9F0083EBEC /* MWMMapDownloaderDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderDataSource.h; sourceTree = "<group>"; };
F6E2FC151E097B9F0083EBEC /* MWMMapDownloaderDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMMapDownloaderDataSource.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
F6E2FC161E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderDefaultDataSource.h; sourceTree = "<group>"; };
F6E2FC171E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMMapDownloaderDefaultDataSource.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
F6E2FC181E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderExtendedDataSource.h; sourceTree = "<group>"; };
F6E2FC191E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderExtendedDataSource.mm; sourceTree = "<group>"; };
F6E2FC1A1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderExtendedDataSourceWithAds.h; sourceTree = "<group>"; };
F6E2FC1B1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderExtendedDataSourceWithAds.mm; sourceTree = "<group>"; };
F6E2FC1C1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderSearchDataSource.h; sourceTree = "<group>"; };
F6E2FC1D1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderSearchDataSource.mm; sourceTree = "<group>"; };
F6E2FC1E1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMBaseMapDownloaderViewController.h; sourceTree = "<group>"; };
F6E2FC1F1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMBaseMapDownloaderViewController.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
F6E2FC201E097B9F0083EBEC /* MWMMapDownloaderProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderProtocol.h; sourceTree = "<group>"; };
F6E2FC211E097B9F0083EBEC /* MWMMapDownloaderMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderMode.h; sourceTree = "<group>"; };
F6E2FC221E097B9F0083EBEC /* MWMMapDownloaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderViewController.h; sourceTree = "<group>"; };
F6E2FC231E097B9F0083EBEC /* MWMMapDownloaderViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderViewController.mm; sourceTree = "<group>"; };
F6E2FC251E097B9F0083EBEC /* MWMNoMapsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMNoMapsView.h; sourceTree = "<group>"; };
F6E2FC261E097B9F0083EBEC /* MWMNoMapsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMNoMapsView.m; sourceTree = "<group>"; };
F6E2FC271E097B9F0083EBEC /* MWMNoMapsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMNoMapsViewController.h; sourceTree = "<group>"; };
@ -3055,6 +3039,8 @@
3486B5121E27AD3B0069C126 /* MWMFrameworkListener.h */,
3486B5131E27AD3B0069C126 /* MWMFrameworkListener.mm */,
3486B5141E27AD3B0069C126 /* MWMFrameworkObservers.h */,
473500C023A8F81800661A95 /* MWMFrameworkObserver.h */,
473500C123A8F85A00661A95 /* MWMFrameworkStorageObserver.h */,
);
path = Framework;
sourceTree = "<group>";
@ -4268,14 +4254,13 @@
isa = PBXGroup;
children = (
F6E2FBFD1E097B9F0083EBEC /* Cells */,
F6E2FC131E097B9F0083EBEC /* DataSources */,
F6E2FC1E1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.h */,
F6E2FC1F1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.mm */,
F6E2FC201E097B9F0083EBEC /* MWMMapDownloaderProtocol.h */,
F6E2FC211E097B9F0083EBEC /* MWMMapDownloaderMode.h */,
F6E2FC221E097B9F0083EBEC /* MWMMapDownloaderViewController.h */,
F6E2FC231E097B9F0083EBEC /* MWMMapDownloaderViewController.mm */,
F6E2FC241E097B9F0083EBEC /* NoMaps */,
47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */,
471AB98823AA8A3500F56D49 /* IDownloaderDataSource.swift */,
47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */,
4735008923A83CF700661A95 /* DownloadedMapsDataSource.swift */,
471AB99323ABA3BD00F56D49 /* SearchMapsDataSource.swift */,
);
path = Downloader;
sourceTree = "<group>";
@ -4283,48 +4268,27 @@
F6E2FBFD1E097B9F0083EBEC /* Cells */ = {
isa = PBXGroup;
children = (
F6E2FBFE1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.h */,
F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.m */,
F6E2FC001E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.xib */,
F6E2FC011E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.h */,
F6E2FC021E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.m */,
F6E2FC031E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.xib */,
F6E2FC041E097B9F0083EBEC /* MWMMapDownloaderCellHeader.h */,
F6E2FC051E097B9F0083EBEC /* MWMMapDownloaderCellHeader.m */,
F6E2FC061E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.h */,
F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm */,
F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m */,
F6E2FC081E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.xib */,
F6E2FC091E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.h */,
F6E2FC0A1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.mm */,
F6E2FC0B1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.xib */,
F6E2FC0C1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.h */,
F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm */,
F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m */,
F6E2FC0E1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.xib */,
F6E2FC0F1E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.h */,
F6E2FC101E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.mm */,
F6E2FC111E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.xib */,
F6E2FC121E097B9F0083EBEC /* MWMMapDownloaderTableViewCellProtocol.h */,
);
path = Cells;
sourceTree = "<group>";
};
F6E2FC131E097B9F0083EBEC /* DataSources */ = {
isa = PBXGroup;
children = (
F6E2FC141E097B9F0083EBEC /* MWMMapDownloaderDataSource.h */,
F6E2FC151E097B9F0083EBEC /* MWMMapDownloaderDataSource.mm */,
F6E2FC161E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.h */,
F6E2FC171E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.mm */,
F6E2FC181E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.h */,
F6E2FC191E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.mm */,
F6E2FC1A1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.h */,
F6E2FC1B1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm */,
F6E2FC1C1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.h */,
F6E2FC1D1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.mm */,
);
path = DataSources;
sourceTree = "<group>";
};
F6E2FC241E097B9F0083EBEC /* NoMaps */ = {
isa = PBXGroup;
children = (
@ -5116,7 +5080,6 @@
6741A96D1BF340DE002C974C /* MWMLocationAlert.xib in Resources */,
3406FA191C6E0D8F00E9FAD2 /* MWMMapDownloadDialog.xib in Resources */,
A630D1EA207CA95900976DEA /* Localizable.stringsdict in Resources */,
F6E2FD531E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.xib in Resources */,
F6E2FD591E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.xib in Resources */,
F62607FF207B83C400176C5A /* MWMSpinnerAlert.xib in Resources */,
F6EBB2731FD7E4FD00B69B6A /* DiscoveryNoResultsCell.xib in Resources */,
@ -5339,6 +5302,7 @@
buildActionMask = 2147483647;
files = (
34845DB71E166084003D55B9 /* Common.swift in Sources */,
47F4F21323A6EC420022FD56 /* DownloadMapsViewController.swift in Sources */,
344BEAF31F66BDC30045DC45 /* RatingSummaryView.swift in Sources */,
6741A9A31BF340DE002C974C /* main.mm in Sources */,
34D3B04F1E38A20C004100F9 /* Bundle+Init.swift in Sources */,
@ -5431,7 +5395,6 @@
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */,
3404F48B202894EA0090E401 /* BMCViewController.swift in Sources */,
349D1ABC1E2D05EF004A2006 /* SearchBar.swift in Sources */,
F6E2FD7A1E097BA00083EBEC /* MWMMapDownloaderDefaultDataSource.mm in Sources */,
993F5511237C622700545511 /* DeepLinkCatalogueStrategy.swift in Sources */,
34E50DF81F6FCC96008EED49 /* UGCReviewCell.swift in Sources */,
F6E2FF3F1E097BA00083EBEC /* MWMSearchTableViewController.mm in Sources */,
@ -5502,7 +5465,7 @@
346DB8341E5C4F6700E3123E /* GalleryViewController.swift in Sources */,
F61757ED1FC73027000AD0D0 /* DiscoveryOnlineTemplateCell.swift in Sources */,
99425AF4236855BB00D005C0 /* PromoDiscoveryRouter.swift in Sources */,
F6E2FD5F1E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm in Sources */,
F6E2FD5F1E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m in Sources */,
34F4073B1E9E1AFF00E57AC0 /* MopubBanner.swift in Sources */,
47B9065421C7FA400079C85E /* UIImageView+WebImage.m in Sources */,
F6E2FF481E097BA00083EBEC /* SettingsTableViewSelectableCell.swift in Sources */,
@ -5537,11 +5500,11 @@
349D1CE41E3F836900A878FD /* UIViewController+Hierarchy.swift in Sources */,
CDB4D4E1222D70DF00104869 /* CarPlayMapViewController.swift in Sources */,
472C40EB232BAE20009AA777 /* CatalogPromoItem+Core.mm in Sources */,
471AB98923AA8A3500F56D49 /* IDownloaderDataSource.swift in Sources */,
F692F3831EA0FAF5001E82EB /* MWMAutoupdateController.mm in Sources */,
34574A671E3B85F80061E839 /* ThemeManager.swift in Sources */,
34BF0CC71C31304A00D097EB /* MWMAuthorizationCommon.mm in Sources */,
34AB664D1FC5AA330078E451 /* RouteManagerFooterView.swift in Sources */,
F6E2FD771E097BA00083EBEC /* MWMMapDownloaderDataSource.mm in Sources */,
6741A9E01BF340DE002C974C /* MWMDownloaderDialogHeader.mm in Sources */,
479D306822C66C8F00D18278 /* MWMBookmarksBannerViewController.m in Sources */,
CDCA2748223FD24600167D87 /* MWMCarPlaySearchResultObject.mm in Sources */,
@ -5592,14 +5555,13 @@
348A8DFB1F66775A00D83026 /* RatingViewSettings.swift in Sources */,
3472B5E1200F86C800DC6CD5 /* MWMEditorHelper.mm in Sources */,
47B06DF021B697230094CCAD /* MWMGeoTrackerCore.mm in Sources */,
F6E2FD501E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.m in Sources */,
99B6A74C2362F5AA002C94CB /* PromoButton.swift in Sources */,
4719A643219CB61D009F9AA7 /* BillingPendingTransaction.swift in Sources */,
4735008A23A83CF700661A95 /* DownloadedMapsDataSource.swift in Sources */,
CD9AD96F2281DF3600EC174A /* CategoryInfo.swift in Sources */,
F6E2FE881E097BA00083EBEC /* MWMPlacePageRegularCell.mm in Sources */,
3DEE1AEB21F72CD300054A91 /* MWMPowerManagmentViewController.mm in Sources */,
34AB66771FC5AA330078E451 /* TransportRoutePreviewStatus.swift in Sources */,
F6E2FD801E097BA00083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm in Sources */,
34BBD6641F8270AC0070CA50 /* AuthorizationTransitioning.swift in Sources */,
34D3AFEA1E378AF1004100F9 /* UINib+Init.swift in Sources */,
34F407321E9E1AFF00E57AC0 /* BannerType.swift in Sources */,
@ -5622,11 +5584,11 @@
F660DEE51EAF4F59004DC056 /* MWMLocationManager+SpeedAndAltitude.swift in Sources */,
F6E2FDF21E097BA00083EBEC /* MWMOpeningHoursAddScheduleTableViewCell.mm in Sources */,
3304306D21D4EAFB00317CA3 /* SearchCategoryCell.swift in Sources */,
F6E2FD831E097BA00083EBEC /* MWMMapDownloaderSearchDataSource.mm in Sources */,
34AB66111FC5AA320078E451 /* NavigationTurnsView.swift in Sources */,
348A8DF81F66775A00D83026 /* RatingViewDelegate.swift in Sources */,
4716EABA21A325310029B886 /* IPaidRouteStatistics.swift in Sources */,
3490D2E11CE9DD2500D0B838 /* MWMSideButtonsView.mm in Sources */,
47F4F21523A6F06F0022FD56 /* AvailableMapsDataSource.swift in Sources */,
995739062355CAC40019AEE7 /* ImageViewCrossDisolve.swift in Sources */,
47B9065221C7FA400079C85E /* MWMWebImage.m in Sources */,
F6664C021E6459DA00E703C2 /* PPReviewHeaderCell.swift in Sources */,
@ -5663,7 +5625,7 @@
F6E2FE821E097BA00083EBEC /* MWMPlacePageOpeningHoursDayView.m in Sources */,
340FDC092031C39E00F140AD /* BMCPermissionsPendingCell.swift in Sources */,
993F550C237C622700545511 /* DeepLinkSubscriptionStrategy.swift in Sources */,
F6E2FD6B1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm in Sources */,
F6E2FD6B1E097BA00083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m in Sources */,
CDCA27842245090900167D87 /* ListenerContainer.swift in Sources */,
47E3C7252111E41B008B3B27 /* DimmedModalPresentationController.swift in Sources */,
99CB34CD236B054B001D28AD /* DeepLinkInfoRouter.swift in Sources */,
@ -5711,7 +5673,6 @@
33BCDF8B218C976D00EF5B74 /* TagsCollectionViewLayout.swift in Sources */,
6741AA0B1BF340DE002C974C /* MWMMapViewControlsManager.mm in Sources */,
F6E2FED91E097BA00083EBEC /* MWMSearchContentView.m in Sources */,
F6E2FD891E097BA00083EBEC /* MWMMapDownloaderViewController.mm in Sources */,
F6BD1D211CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */,
34AB66321FC5AA330078E451 /* RouteManagerHeaderView.swift in Sources */,
347040301EA6470700038379 /* BorderedButton.swift in Sources */,
@ -5723,7 +5684,6 @@
47C7F97521930F5300C2760C /* IInAppBilling.swift in Sources */,
4719A64E21A30C3B009F9AA7 /* PaidRouteStatistics.swift in Sources */,
34BBD6601F8270360070CA50 /* AuthorizationiPadPresentationController.swift in Sources */,
F6E2FD7D1E097BA00083EBEC /* MWMMapDownloaderExtendedDataSource.mm in Sources */,
F6E2FED31E097BA00083EBEC /* MWMSearchHotelsFilterViewController.mm in Sources */,
340475741E081A4600C92850 /* MWMStorage.mm in Sources */,
347752901F7251C7000D46A3 /* UGCAddReviewTextCell.swift in Sources */,
@ -5744,7 +5704,6 @@
47289E5A2212DFFF002ABFC0 /* EditOnWebAlertViewController.swift in Sources */,
34763EE71F2F392300F4D2D3 /* MWMTextToSpeech.mm in Sources */,
34ABA6251C2D551900FE1BEC /* MWMInputValidatorFactory.m in Sources */,
F6E2FD861E097BA00083EBEC /* MWMBaseMapDownloaderViewController.mm in Sources */,
348F8A4F1F863A8500060C2A /* UGCYourReview.swift in Sources */,
F6E2FEE21E097BA00083EBEC /* MWMSearchManager.mm in Sources */,
F6E2FE221E097BA00083EBEC /* MWMOpeningHoursEditorViewController.mm in Sources */,
@ -5760,6 +5719,7 @@
347752881F725002000D46A3 /* UGCAddReviewRatingCell.swift in Sources */,
47E3C7332111F4D8008B3B27 /* CoverVerticalDismissalAnimator.swift in Sources */,
99E2B01E23698B0800FFABC5 /* WelcomeProtocols.swift in Sources */,
471AB99423ABA3BD00F56D49 /* SearchMapsDataSource.swift in Sources */,
993F550F237C622700545511 /* DeepLinkMapStrategy.swift in Sources */,
34AB661A1FC5AA330078E451 /* MWMTaxiCollectionLayout.m in Sources */,
345C2F8A1F86361B009DB8B4 /* MWMUGCViewModel.mm in Sources */,

View file

@ -1,13 +1,14 @@
#import "MWMAutoupdateController.h"
#import "MWMCircularProgress.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMStorage.h"
#import "Statistics.h"
#import "SwiftBridge.h"
namespace
{
std::string RootId() { return GetFramework().GetStorage().GetRootId(); }
NSString *RootId() { return @(GetFramework().GetStorage().GetRootId().c_str()); }
enum class State
{
Downloading,
@ -15,6 +16,8 @@ enum class State
};
} // namespace
using namespace storage;
@interface MWMAutoupdateView : UIView
@property(weak, nonatomic) IBOutlet UIImageView * image;
@ -246,7 +249,7 @@ enum class State
{
auto const & s = GetFramework().GetStorage();
NodeAttrs nodeAttrs;
s.GetNodeAttrs(RootId(), nodeAttrs);
s.GetNodeAttrs(RootId().UTF8String, nodeAttrs);
auto view = static_cast<MWMAutoupdateView *>(self.view);
NSString * nodeName = @(s.GetNodeLocalName(countryId).c_str());
[view setStatusForNodeName:nodeName rootAttributes:nodeAttrs];
@ -260,10 +263,10 @@ enum class State
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
- (void)processCountryEvent:(NSString *)countryId
{
NodeStatuses nodeStatuses;
GetFramework().GetStorage().GetNodeStatuses(countryId, nodeStatuses);
GetFramework().GetStorage().GetNodeStatuses(countryId.UTF8String, nodeStatuses);
if (nodeStatuses.m_status == NodeStatus::Error)
{
self.errorCode = nodeStatuses.m_error;
@ -277,15 +280,15 @@ enum class State
switch (nodeStatuses.m_status)
{
case NodeStatus::Error:
case NodeStatus::OnDisk: m_updatingCountries.erase(countryId); break;
default: m_updatingCountries.insert(countryId);
case NodeStatus::OnDisk: m_updatingCountries.erase(countryId.UTF8String); break;
default: m_updatingCountries.insert(countryId.UTF8String);
}
}
if (self.progressFinished && m_updatingCountries.empty())
[self dismiss];
else
[self updateProcessStatus:countryId];
[self updateProcessStatus:countryId.UTF8String];
}
- (void)processError
@ -312,11 +315,12 @@ enum class State
withParameters:@{kStatMapDataSize : @(self.sizeInMB), kStatType : errorType}];
}
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress
- (void)processCountry:(NSString *)countryId
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes
{
if (m_updatingCountries.find(countryId) != m_updatingCountries.end())
[self updateProcessStatus:countryId];
if (m_updatingCountries.find(countryId.UTF8String) != m_updatingCountries.end())
[self updateProcessStatus:countryId.UTF8String];
}
@end

View file

@ -0,0 +1,157 @@
class AvailableMapsDataSource {
struct Const {
static let locationArrow = ""
}
private let parentCountryId: String?
private var sections: [String]?
private var sectionsContent: [String: [String]]?
private var nearbySection: [String]?
fileprivate var searching = false
fileprivate lazy var searchDataSource: IDownloaderDataSource = {
SearchMapsDataSource()
}()
init(_ parentCountryId: String? = nil, location: CLLocationCoordinate2D? = nil) {
self.parentCountryId = parentCountryId
let countryIds: [String]
if let parentCountryId = parentCountryId {
countryIds = Storage.allCountries(withParent: parentCountryId)
} else {
countryIds = Storage.allCountries()
}
configSections(countryIds, location: location)
}
private func configSections(_ countryIds: [String], location: CLLocationCoordinate2D?) {
let countries = countryIds.map {
CountryIdAndName(countryId: $0, name: Storage.name(forCountry: $0))
}.sorted {
$0.countryName.compare($1.countryName) == .orderedAscending
}
sections = []
sectionsContent = [:]
if let location = location {
nearbySection = Storage.nearbyAvailableCountries(location)
sections?.append(Const.locationArrow)
sectionsContent![Const.locationArrow] = nearbySection
}
for country in countries {
let section = parentCountryId == nil ? String(country.countryName.prefix(1)) : L("downloader_available_maps")
if sections!.last != section {
sections!.append(section)
sectionsContent![section] = []
}
var sectionCountries = sectionsContent![section]
sectionCountries?.append(country.countryId)
sectionsContent![section] = sectionCountries
}
}
}
extension AvailableMapsDataSource: IDownloaderDataSource {
var isEmpty: Bool {
searching ? searchDataSource.isEmpty : false
}
var title: String {
guard let parentCountryId = parentCountryId else {
return L("download_maps")
}
return Storage.name(forCountry: parentCountryId)
}
var isRoot: Bool {
parentCountryId == nil
}
var isSearching: Bool {
searching
}
func parentAttributes() -> MapNodeAttributes {
guard let parentId = parentCountryId else {
return Storage.attributesForRoot()
}
return Storage.attributes(forCountry: parentId)
}
func numberOfSections() -> Int {
searching ? searchDataSource.numberOfSections() : (sections?.count ?? 0)
}
func numberOfItems(in section: Int) -> Int {
if searching {
return searchDataSource.numberOfItems(in: section)
}
let index = sections![section]
return sectionsContent![index]!.count
}
func item(at indexPath: IndexPath) -> MapNodeAttributes {
if searching {
return searchDataSource.item(at: indexPath)
}
let sectionIndex = sections![indexPath.section]
let sectionItems = sectionsContent![sectionIndex]
let countryId = sectionItems![indexPath.item]
return Storage.attributes(forCountry: countryId)
}
func matchedName(at indexPath: IndexPath) -> String? {
searching ? searchDataSource.matchedName(at: indexPath) : nil
}
func title(for section: Int) -> String {
if searching {
return searchDataSource.title(for: section)
}
let title = sections![section]
if title == Const.locationArrow {
return L("downloader_near_me_subtitle")
}
return title
}
func indexTitles() -> [String]? {
if searching {
return nil
}
if parentCountryId != nil {
return nil
}
return sections
}
func dataSourceFor(_ childId: String) -> IDownloaderDataSource {
searching ? searchDataSource.dataSourceFor(childId) : AvailableMapsDataSource(childId)
}
func reload(_ completion: () -> Void) {
if searching {
searchDataSource.reload(completion)
}
// do nothing.
}
func search(_ query: String, locale: String, update: @escaping (Bool) -> Void) {
if query.isEmpty {
cancelSearch()
update(true)
return
}
searching = true
searchDataSource.search(query, locale: locale, update: update)
}
func cancelSearch() {
searching = false
searchDataSource.cancelSearch()
}
}

View file

@ -1,10 +0,0 @@
#import <MyTargetSDK/MTRGAppwallBannerAdView.h>
#import "MWMMapDownloaderTableViewCellProtocol.h"
#import "MWMTableViewCell.h"
@interface MWMMapDownloaderAdsTableViewCell
: MWMTableViewCell<MWMMapDownloaderTableViewCellProtocol>
@property(nonatomic) MTRGAppwallBannerAdView * adView;
@end

View file

@ -1,21 +0,0 @@
#import "MWMMapDownloaderAdsTableViewCell.h"
@implementation MWMMapDownloaderAdsTableViewCell
+ (CGFloat)estimatedHeight { return 68.0; }
- (void)setAdView:(MTRGAppwallBannerAdView *)view
{
if (_adView == view)
return;
[_adView removeFromSuperview];
[self addSubview:view];
_adView = view;
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.adView.frame = self.bounds;
}
@end

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MWMMapDownloaderAdsTableViewCell" id="KGk-i7-Jjw" customClass="MWMMapDownloaderAdsTableViewCell" propertyAccessControl="all">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</tableViewCell>
</objects>
</document>

View file

@ -1,4 +1,3 @@
#import "MWMMapDownloaderTableViewCellProtocol.h"
#import "MWMTableViewCell.h"
@protocol MWMMapDownloaderButtonTableViewCellProtocol <NSObject>
@ -7,7 +6,7 @@
@end
@interface MWMMapDownloaderButtonTableViewCell : MWMTableViewCell <MWMMapDownloaderTableViewCellProtocol>
@interface MWMMapDownloaderButtonTableViewCell : MWMTableViewCell
@property (weak, nonatomic) id<MWMMapDownloaderButtonTableViewCellProtocol> delegate;

View file

@ -1,16 +1,7 @@
#import "MWMMapDownloaderButtonTableViewCell.h"
//#include "storage/storage.hpp"
//
//using namespace storage;
@implementation MWMMapDownloaderButtonTableViewCell
+ (CGFloat)estimatedHeight
{
return 44.0;
}
- (void)awakeFromNib
{
[super awakeFromNib];

View file

@ -0,0 +1,22 @@
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
#import <CoreApi/MWMMapNodeAttributes.h>
@interface MWMMapDownloaderLargeCountryTableViewCell ()
@property (weak, nonatomic) IBOutlet UILabel * mapsCount;
@end
@implementation MWMMapDownloaderLargeCountryTableViewCell
#pragma mark - Config
- (void)config:(MWMMapNodeAttributes *)nodeAttrs searchQuery:(NSString *)searchQuery {
[super config:nodeAttrs searchQuery:searchQuery];
BOOL haveLocalMaps = (nodeAttrs.downloadedMwmCount != 0);
NSString *ofMaps = haveLocalMaps ? [NSString stringWithFormat:L(@"downloader_of"), nodeAttrs.downloadedMwmCount, nodeAttrs.totalMwmCount] : @(nodeAttrs.totalMwmCount).stringValue;
self.mapsCount.text = [NSString stringWithFormat:@"%@: %@", L(@"downloader_status_maps"), ofMaps];
}
@end

View file

@ -1,26 +0,0 @@
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
@interface MWMMapDownloaderLargeCountryTableViewCell ()
@property (weak, nonatomic) IBOutlet UILabel * mapsCount;
@end
@implementation MWMMapDownloaderLargeCountryTableViewCell
+ (CGFloat)estimatedHeight
{
return 62.0;
}
#pragma mark - Config
- (void)config:(storage::NodeAttrs const &)nodeAttrs
{
[super config:nodeAttrs];
BOOL const haveLocalMaps = (nodeAttrs.m_downloadingMwmCounter != 0);
NSString * ofMaps = haveLocalMaps ? [NSString stringWithFormat:L(@"downloader_of"), nodeAttrs.m_downloadingMwmCounter, nodeAttrs.m_mwmCounter] : @(nodeAttrs.m_mwmCounter).stringValue;
self.mapsCount.text = [NSString stringWithFormat:@"%@: %@", L(@"downloader_status_maps"), ofMaps];
}
@end

View file

@ -1,6 +1,7 @@
#import "MWMMapDownloaderPlaceTableViewCell.h"
#include <CoreApi/Framework.h>
#import <CoreApi/MWMMapNodeAttributes.h>
@interface MWMMapDownloaderTableViewCell ()
@ -12,39 +13,36 @@
@interface MWMMapDownloaderPlaceTableViewCell ()
@property(weak, nonatomic) IBOutlet UILabel * descriptionLabel;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * titleBottomOffset;
@property(weak, nonatomic) IBOutlet UILabel *descriptionLabel;
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *titleBottomOffset;
@end
@implementation MWMMapDownloaderPlaceTableViewCell
+ (CGFloat)estimatedHeight { return 62.0; }
#pragma mark - Config
- (void)config:(storage::NodeAttrs const &)nodeAttrs
{
[super config:nodeAttrs];
- (void)config:(MWMMapNodeAttributes *)nodeAttrs searchQuery:(NSString *)searchQuery {
[super config:nodeAttrs searchQuery:searchQuery];
BOOL isDescriptionVisible = NO;
NSDictionary * const selectedAreaAttrs = @{NSFontAttributeName : [UIFont bold12]};
NSDictionary * const unselectedAreaAttrs = @{NSFontAttributeName : [UIFont regular12]};
if (self.needDisplayArea && nodeAttrs.m_topmostParentInfo.size() == 1)
{
std::string const & areaName = nodeAttrs.m_topmostParentInfo[0].m_localName;
isDescriptionVisible = (areaName != GetFramework().GetStorage().GetRootId());
if (isDescriptionVisible)
self.descriptionLabel.attributedText = [self matchedString:@(areaName.c_str())
NSDictionary *selectedAreaAttrs = @{NSFontAttributeName : [UIFont bold12]};
NSDictionary *unselectedAreaAttrs = @{NSFontAttributeName : [UIFont regular12]};
self.needDisplayArea = !nodeAttrs.hasParent;
if (self.needDisplayArea && nodeAttrs.topmostParentInfo.count == 1) {
NSString *areaName = nodeAttrs.topmostParentInfo[0].countryId;
isDescriptionVisible = ![areaName isEqualToString:@(GetFramework().GetStorage().GetRootId().c_str())];
if (isDescriptionVisible) {
self.descriptionLabel.attributedText = [self matchedString:nodeAttrs.topmostParentInfo[0].countryName
selectedAttrs:selectedAreaAttrs
unselectedAttrs:unselectedAreaAttrs];
}
}
else if (!nodeAttrs.m_nodeLocalDescription.empty())
else if (nodeAttrs.nodeDescription.length > 0)
{
isDescriptionVisible = YES;
self.descriptionLabel.attributedText =
[self matchedString:@(nodeAttrs.m_nodeLocalDescription.c_str())
selectedAttrs:selectedAreaAttrs
unselectedAttrs:unselectedAreaAttrs];
self.descriptionLabel.attributedText = [self matchedString:nodeAttrs.nodeDescription
selectedAttrs:selectedAreaAttrs
unselectedAttrs:unselectedAreaAttrs];
}
self.descriptionLabel.hidden = !isDescriptionVisible;
self.titleBottomOffset.priority =

View file

@ -0,0 +1,25 @@
#import "MWMMapDownloaderSubplaceTableViewCell.h"
@interface MWMMapDownloaderTableViewCell ()
- (NSAttributedString *)matchedString:(NSString *)str
selectedAttrs:(NSDictionary *)selectedAttrs
unselectedAttrs:(NSDictionary *)unselectedAttrs;
@end
@interface MWMMapDownloaderSubplaceTableViewCell ()
@property(weak, nonatomic) IBOutlet UILabel *subPlace;
@end
@implementation MWMMapDownloaderSubplaceTableViewCell
- (void)setSubplaceText:(NSString *)text {
self.subPlace.attributedText = [self matchedString:text
selectedAttrs:@{NSFontAttributeName : [UIFont bold14]}
unselectedAttrs:@{NSFontAttributeName : [UIFont regular14]}];
}
@end

View file

@ -1,30 +0,0 @@
#import "MWMMapDownloaderSubplaceTableViewCell.h"
@interface MWMMapDownloaderTableViewCell ()
- (NSAttributedString *)matchedString:(NSString *)str
selectedAttrs:(NSDictionary *)selectedAttrs
unselectedAttrs:(NSDictionary *)unselectedAttrs;
@end
@interface MWMMapDownloaderSubplaceTableViewCell ()
@property(weak, nonatomic) IBOutlet UILabel * subPlace;
@end
@implementation MWMMapDownloaderSubplaceTableViewCell
+ (CGFloat)estimatedHeight { return 82.0; }
- (void)setSubplaceText:(NSString *)text
{
NSDictionary * const selectedSubPlaceAttrs = @{NSFontAttributeName : [UIFont bold14]};
NSDictionary * const unselectedSubPlaceAttrs = @{NSFontAttributeName : [UIFont regular14]};
self.subPlace.attributedText = [self matchedString:text
selectedAttrs:selectedSubPlaceAttrs
unselectedAttrs:unselectedSubPlaceAttrs];
}
@end

View file

@ -1,21 +1,27 @@
#import "MWMFrameworkObservers.h"
#import "MWMMapDownloaderMode.h"
#import "MWMMapDownloaderProtocol.h"
#import "MWMMapDownloaderTableViewCellProtocol.h"
#import "MWMTableViewCell.h"
namespace storage
{
struct NodeAttrs;
} // storage
@class MWMMapNodeAttributes;
@class MWMMapDownloaderTableViewCell;
@interface MWMMapDownloaderTableViewCell : MWMTableViewCell <MWMMapDownloaderTableViewCellProtocol, MWMFrameworkStorageObserver>
NS_ASSUME_NONNULL_BEGIN
@property(nonatomic) BOOL isHeightCell;
@property(weak, nonatomic) id<MWMMapDownloaderProtocol> delegate;
@property(nonatomic) MWMMapDownloaderMode mode;
@protocol MWMMapDownloaderTableViewCellDelegate <NSObject>
- (void)config:(storage::NodeAttrs const &)nodeAttrs;
- (void)setCountryId:(NSString *)countryId searchQuery:(NSString *)query;
- (void)mapDownloaderCellDidPressProgress:(MWMMapDownloaderTableViewCell *)cell;
- (void)mapDownloaderCellDidLongPress:(MWMMapDownloaderTableViewCell *)cell;
@end
@interface MWMMapDownloaderTableViewCell : MWMTableViewCell
@property(weak, nonatomic) id<MWMMapDownloaderTableViewCellDelegate> delegate;
@property(nonatomic) MWMMapDownloaderMode mode;
@property(readonly, nonatomic) MWMMapNodeAttributes *nodeAttrs;
- (void)config:(MWMMapNodeAttributes *)nodeAttrs searchQuery:(nullable NSString *)searchQuery;
- (void)setDownloadProgress:(CGFloat)progress;
@end
NS_ASSUME_NONNULL_END

View file

@ -5,43 +5,49 @@
#include <CoreApi/Framework.h>
#import <CoreApi/MWMCommon.h>
#import <CoreApi/MWMFrameworkHelper.h>
#import <CoreApi/MWMMapNodeAttributes.h>
@interface MWMMapDownloaderTableViewCell ()<MWMCircularProgressProtocol>
@interface MWMMapDownloaderTableViewCell () <MWMCircularProgressProtocol>
@property(nonatomic) MWMCircularProgress * progress;
@property(copy, nonatomic) NSString * searchQuery;
@property(nonatomic) MWMCircularProgress *progress;
@property(copy, nonatomic) NSString *searchQuery;
@property(weak, nonatomic) IBOutlet UIView * stateWrapper;
@property(weak, nonatomic) IBOutlet UILabel * title;
@property(weak, nonatomic) IBOutlet UILabel * downloadSize;
@property(weak, nonatomic) IBOutlet UIView *stateWrapper;
@property(weak, nonatomic) IBOutlet UILabel *title;
@property(weak, nonatomic) IBOutlet UILabel *downloadSize;
@property(strong, nonatomic) MWMMapNodeAttributes *nodeAttrs;
@end
@implementation MWMMapDownloaderTableViewCell
{
storage::CountryId m_countryId;
}
+ (CGFloat)estimatedHeight { return 52.0; }
- (void)awakeFromNib
{
- (void)awakeFromNib {
[super awakeFromNib];
m_countryId = kInvalidCountryId;
UILongPressGestureRecognizer *lpGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:@selector(onLongPress:)];
[self addGestureRecognizer:lpGR];
}
- (void)prepareForReuse
{
- (void)prepareForReuse {
[super prepareForReuse];
m_countryId = kInvalidCountryId;
self.nodeAttrs = nil;
}
- (void)onLongPress:(UILongPressGestureRecognizer *)sender {
if (sender.state != UIGestureRecognizerStateBegan) {
return;
}
[self.delegate mapDownloaderCellDidLongPress:self];
}
#pragma mark - Search matching
- (NSAttributedString *)matchedString:(NSString *)str
selectedAttrs:(NSDictionary *)selectedAttrs
unselectedAttrs:(NSDictionary *)unselectedAttrs
{
NSMutableAttributedString * attrTitle = [[NSMutableAttributedString alloc] initWithString:str];
unselectedAttrs:(NSDictionary *)unselectedAttrs {
NSMutableAttributedString *attrTitle = [[NSMutableAttributedString alloc] initWithString:str];
[attrTitle addAttributes:unselectedAttrs range:{0, str.length}];
if (!self.searchQuery)
return [attrTitle copy];
@ -52,148 +58,94 @@
#pragma mark - Config
- (void)config:(storage::NodeAttrs const &)nodeAttrs
{
- (void)config:(MWMMapNodeAttributes *)nodeAttrs searchQuery:(NSString *)searchQuery {
self.searchQuery = searchQuery;
self.nodeAttrs = nodeAttrs;
[self configProgress:nodeAttrs];
NSDictionary * const selectedTitleAttrs = @{NSFontAttributeName : [UIFont bold17]};
NSDictionary * const unselectedTitleAttrs = @{NSFontAttributeName : [UIFont regular17]};
self.title.attributedText = [self matchedString:@(nodeAttrs.m_nodeLocalName.c_str())
selectedAttrs:selectedTitleAttrs
unselectedAttrs:unselectedTitleAttrs];
self.title.attributedText = [self matchedString:nodeAttrs.nodeName
selectedAttrs:@{NSFontAttributeName: [UIFont bold17]}
unselectedAttrs:@{NSFontAttributeName: [UIFont regular17]}];
MwmSize size;
bool const isModeDownloaded = self.mode == MWMMapDownloaderModeDownloaded;
uint64_t size = 0;
BOOL isModeDownloaded = self.mode == MWMMapDownloaderModeDownloaded;
switch (nodeAttrs.m_status)
{
case storage::NodeStatus::Error:
case storage::NodeStatus::Undefined:
case storage::NodeStatus::NotDownloaded:
case storage::NodeStatus::OnDiskOutOfDate:
size = isModeDownloaded ? nodeAttrs.m_localMwmSize : nodeAttrs.m_mwmSize;
break;
case storage::NodeStatus::Downloading:
size = isModeDownloaded ? nodeAttrs.m_downloadingMwmSize
: nodeAttrs.m_mwmSize - nodeAttrs.m_downloadingMwmSize;
break;
case storage::NodeStatus::Applying:
case storage::NodeStatus::InQueue:
case storage::NodeStatus::Partly:
size = isModeDownloaded ? nodeAttrs.m_localMwmSize : nodeAttrs.m_mwmSize;
break;
case storage::NodeStatus::OnDisk: size = isModeDownloaded ? nodeAttrs.m_mwmSize : 0; break;
switch (nodeAttrs.nodeStatus) {
case MWMMapNodeStatusUndefined:
case MWMMapNodeStatusError:
case MWMMapNodeStatusOnDiskOutOfDate:
case MWMMapNodeStatusNotDownloaded:
case MWMMapNodeStatusApplying:
case MWMMapNodeStatusInQueue:
case MWMMapNodeStatusPartly:
size = isModeDownloaded ? nodeAttrs.downloadedSize : nodeAttrs.totalSize;
break;
case MWMMapNodeStatusDownloading:
size = isModeDownloaded ? nodeAttrs.downloadingSize : nodeAttrs.totalSize - nodeAttrs.downloadingSize;
break;
case MWMMapNodeStatusOnDisk:
size = isModeDownloaded ? nodeAttrs.totalSize : 0;
break;
}
self.downloadSize.text = formattedSize(size);
self.downloadSize.hidden = (size == 0);
}
- (void)configProgress:(storage::NodeAttrs const &)nodeAttrs
{
MWMCircularProgress * progress = self.progress;
MWMButtonColoring const coloring =
self.mode == MWMMapDownloaderModeDownloaded ? MWMButtonColoringBlack : MWMButtonColoringBlue;
switch (nodeAttrs.m_status)
{
case NodeStatus::NotDownloaded:
case NodeStatus::Partly:
{
MWMCircularProgressStateVec const affectedStates = {MWMCircularProgressStateNormal,
MWMCircularProgressStateSelected};
NSString * imageName = [self isKindOfClass:[MWMMapDownloaderLargeCountryTableViewCell class]]
? @"ic_folder"
: @"ic_download";
[progress setImageName:imageName forStates:affectedStates];
[progress setColoring:coloring forStates:affectedStates];
progress.state = MWMCircularProgressStateNormal;
break;
}
case NodeStatus::Downloading:
{
auto const & prg = nodeAttrs.m_downloadingProgress;
progress.progress = kMaxProgress * static_cast<CGFloat>(prg.first) / prg.second;
break;
}
case NodeStatus::Applying:
case NodeStatus::InQueue: progress.state = MWMCircularProgressStateSpinner; break;
case NodeStatus::Undefined:
case NodeStatus::Error: progress.state = MWMCircularProgressStateFailed; break;
case NodeStatus::OnDisk: progress.state = MWMCircularProgressStateCompleted; break;
case NodeStatus::OnDiskOutOfDate:
{
MWMCircularProgressStateVec const affectedStates = {MWMCircularProgressStateNormal,
MWMCircularProgressStateSelected};
[progress setImageName:@"ic_update" forStates:affectedStates];
[progress setColoring:MWMButtonColoringOther forStates:affectedStates];
progress.state = MWMCircularProgressStateNormal;
break;
}
- (void)configProgress:(MWMMapNodeAttributes *)nodeAttrs {
MWMCircularProgress *progress = self.progress;
MWMButtonColoring coloring =
self.mode == MWMMapDownloaderModeDownloaded ? MWMButtonColoringBlack : MWMButtonColoringBlue;
switch (nodeAttrs.nodeStatus) {
case MWMMapNodeStatusNotDownloaded:
case MWMMapNodeStatusPartly: {
MWMCircularProgressStateVec const affectedStates = {MWMCircularProgressStateNormal,
MWMCircularProgressStateSelected};
NSString *imageName =
[self isKindOfClass:[MWMMapDownloaderLargeCountryTableViewCell class]] ? @"ic_folder" : @"ic_download";
[progress setImageName:imageName forStates:affectedStates];
[progress setColoring:coloring forStates:affectedStates];
progress.state = MWMCircularProgressStateNormal;
break;
}
case MWMMapNodeStatusDownloading:
progress.progress = kMaxProgress * nodeAttrs.downloadedSize / nodeAttrs.totalSize;
break;
case MWMMapNodeStatusApplying:
case MWMMapNodeStatusInQueue:
progress.state = MWMCircularProgressStateSpinner;
break;
case MWMMapNodeStatusUndefined:
case MWMMapNodeStatusError:
progress.state = MWMCircularProgressStateFailed;
break;
case MWMMapNodeStatusOnDisk:
progress.state = MWMCircularProgressStateCompleted;
break;
case MWMMapNodeStatusOnDiskOutOfDate: {
MWMCircularProgressStateVec affectedStates = {MWMCircularProgressStateNormal, MWMCircularProgressStateSelected};
[progress setImageName:@"ic_update" forStates:affectedStates];
[progress setColoring:MWMButtonColoringOther forStates:affectedStates];
progress.state = MWMCircularProgressStateNormal;
break;
}
}
}
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
{
if (countryId != m_countryId)
return;
storage::NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(m_countryId, nodeAttrs);
[self config:nodeAttrs];
}
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress
{
if (countryId != m_countryId)
return;
self.progress.progress = kMaxProgress * static_cast<CGFloat>(progress.first) / progress.second;
- (void)setDownloadProgress:(CGFloat)progress {
self.progress.progress = kMaxProgress * progress;
}
#pragma mark - MWMCircularProgressProtocol
- (void)progressButtonPressed:(nonnull MWMCircularProgress *)progress
{
storage::NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(m_countryId, nodeAttrs);
id<MWMMapDownloaderProtocol> delegate = self.delegate;
switch (nodeAttrs.m_status)
{
case NodeStatus::NotDownloaded:
case NodeStatus::Partly:
if ([self isKindOfClass:[MWMMapDownloaderLargeCountryTableViewCell class]])
[delegate openNodeSubtree:m_countryId];
else
[delegate downloadNode:m_countryId];
break;
case NodeStatus::Undefined:
case NodeStatus::Error: [delegate retryDownloadNode:m_countryId]; break;
case NodeStatus::OnDiskOutOfDate: [delegate updateNode:m_countryId]; break;
case NodeStatus::Downloading:
case NodeStatus::Applying:
case NodeStatus::InQueue: [delegate cancelNode:m_countryId]; break;
case NodeStatus::OnDisk: break;
}
- (void)progressButtonPressed:(nonnull MWMCircularProgress *)progress {
[self.delegate mapDownloaderCellDidPressProgress:self];
}
#pragma mark - Properties
- (void)setCountryId:(NSString *)countryId searchQuery:(NSString *)query
{
if (m_countryId == countryId.UTF8String && [query isEqualToString:self.searchQuery])
return;
self.searchQuery = query;
m_countryId = countryId.UTF8String;
storage::NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(m_countryId, nodeAttrs);
[self config:nodeAttrs];
}
- (MWMCircularProgress *)progress
{
if (!_progress && !self.isHeightCell)
{
- (MWMCircularProgress *)progress {
if (!_progress) {
_progress = [MWMCircularProgress downloaderProgressForParentView:self.stateWrapper];
_progress.delegate = self;
}

View file

@ -1,5 +0,0 @@
@protocol MWMMapDownloaderTableViewCellProtocol <NSObject>
+ (CGFloat)estimatedHeight;
@end

View file

@ -1,25 +0,0 @@
#import "MWMMapDownloaderButtonTableViewCell.h"
#import "MWMMapDownloaderMode.h"
#import "MWMMapDownloaderProtocol.h"
#import "MWMMapDownloaderTableViewCell.h"
@interface MWMMapDownloaderDataSource : NSObject <UITableViewDataSource>
@property(nonatomic, readonly) BOOL isParentRoot;
@property(nonatomic, readonly) MWMMapDownloaderMode mode;
@property(weak, nonatomic, readonly)
id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>
delegate;
- (instancetype)
initWithDelegate:(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate
mode:(MWMMapDownloaderMode)mode;
- (NSString *)parentCountryId;
- (NSString *)countryIdForIndexPath:(NSIndexPath *)indexPath;
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath;
- (void)fillCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (BOOL)isButtonCell:(NSInteger)section;
- (NSString *)searchMatchedResultForCountryId:(NSString *)countryId;
@end

View file

@ -1,111 +0,0 @@
#import "MWMMapDownloaderDataSource.h"
#import "MWMMapDownloaderPlaceTableViewCell.h"
#import "MWMMapDownloaderSubplaceTableViewCell.h"
#import "SwiftBridge.h"
using namespace storage;
@implementation MWMMapDownloaderDataSource
- (instancetype)
initWithDelegate:(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate
mode:(MWMMapDownloaderMode)mode
{
self = [super init];
if (self)
{
_delegate = delegate;
_mode = mode;
}
return self;
}
#pragma mark - Fill cells with data
- (void)fillCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
if (![cell isKindOfClass:[MWMMapDownloaderTableViewCell class]])
return;
NSString * countryId = [self countryIdForIndexPath:indexPath];
if ([cell isKindOfClass:[MWMMapDownloaderPlaceTableViewCell class]])
{
MWMMapDownloaderPlaceTableViewCell * placeCell = static_cast<MWMMapDownloaderPlaceTableViewCell *>(cell);
placeCell.needDisplayArea = self.isParentRoot;
}
if ([cell isKindOfClass:[MWMMapDownloaderSubplaceTableViewCell class]])
{
MWMMapDownloaderSubplaceTableViewCell * subplaceCell = static_cast<MWMMapDownloaderSubplaceTableViewCell *>(cell);
[subplaceCell setSubplaceText:[self searchMatchedResultForCountryId:countryId]];
}
MWMMapDownloaderTableViewCell * tCell = static_cast<MWMMapDownloaderTableViewCell *>(cell);
tCell.delegate = self.delegate;
tCell.mode = self.mode;
[tCell setCountryId:countryId searchQuery:[self searchQuery]];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Class cls = [self cellClassForIndexPath:indexPath];
auto cell = static_cast<MWMMapDownloaderTableViewCell *>(
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
[self fillCell:cell atIndexPath:indexPath];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
[self.delegate deleteNode:[self countryIdForIndexPath:indexPath].UTF8String];
}
#pragma mark - MWMMapDownloaderDataSource
- (BOOL)isParentRoot
{
return YES;
}
- (NSString *)parentCountryId
{
return @(kInvalidCountryId.c_str());
}
- (NSString *)countryIdForIndexPath:(NSIndexPath *)indexPath
{
return @(kInvalidCountryId.c_str());
}
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath { return nil; }
- (NSString *)searchMatchedResultForCountryId:(NSString *)countryId
{
return nil;
}
- (NSString *)searchQuery
{
return nil;
}
#pragma mark - Helpers
- (BOOL)isButtonCell:(NSInteger)section
{
return NO;
}
@end

View file

@ -1,12 +0,0 @@
#import "MWMMapDownloaderDataSource.h"
@interface MWMMapDownloaderDefaultDataSource : MWMMapDownloaderDataSource
- (instancetype)
initForRootCountryId:(NSString *)countryId
delegate:
(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate
mode:(MWMMapDownloaderMode)mode;
- (void)load;
@end

View file

@ -1,229 +0,0 @@
#import "MWMMapDownloaderDefaultDataSource.h"
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
#import "MWMMapDownloaderPlaceTableViewCell.h"
#import "SwiftBridge.h"
#include <CoreApi/Framework.h>
namespace
{
auto compareStrings = ^NSComparisonResult(NSString * s1, NSString * s2) {
return [s1 compare:s2
options:NSCaseInsensitiveSearch
range:{ 0, s1.length }
locale:NSLocale.currentLocale];
};
auto compareLocalNames = ^NSComparisonResult(NSString * s1, NSString * s2)
{
auto const & s = GetFramework().GetStorage();
std::string const l1 = s.GetNodeLocalName(s1.UTF8String);
std::string const l2 = s.GetNodeLocalName(s2.UTF8String);
return compareStrings(@(l1.c_str()), @(l2.c_str()));
};
} // namespace
using namespace storage;
@interface MWMMapDownloaderDefaultDataSource ()
@property (copy, nonatomic) NSArray<NSString *> * indexes;
@property (copy, nonatomic) NSDictionary<NSString *, NSArray<NSString *> *> * availableCountries;
@property (copy, nonatomic) NSArray<NSString *> * downloadedCountries;
@end
@implementation MWMMapDownloaderDefaultDataSource
{
CountryId m_parentId;
}
@synthesize isParentRoot = _isParentRoot;
- (instancetype)
initForRootCountryId:(NSString *)countryId
delegate:
(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate
mode:(MWMMapDownloaderMode)mode
{
self = [super initWithDelegate:delegate mode:mode];
if (self)
{
m_parentId = countryId.UTF8String;
_isParentRoot = (m_parentId == GetFramework().GetStorage().GetRootId());
[self load];
}
return self;
}
- (void)load
{
auto const & s = GetFramework().GetStorage();
CountriesVec downloadedChildren;
CountriesVec availableChildren;
s.GetChildrenInGroups(m_parentId, downloadedChildren, availableChildren, true /* keepAvailableChildren */);
if (self.mode == MWMMapDownloaderModeAvailable)
{
self.downloadedCountries = nil;
[self configAvailableSections:availableChildren];
}
else
{
self.indexes = nil;
self.availableCountries = nil;
[self configDownloadedSection:downloadedChildren];
}
}
- (void)configAvailableSections:(CountriesVec const &)availableChildren
{
NSMutableSet<NSString *> * indexSet = [NSMutableSet setWithCapacity:availableChildren.size()];
NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> * availableCountries = [@{} mutableCopy];
BOOL const isParentRoot = self.isParentRoot;
auto const & s = GetFramework().GetStorage();
for (auto const & countryId : availableChildren)
{
NSString * nsCountryId = @(countryId.c_str());
std::string localName = s.GetNodeLocalName(countryId);
NSString * index = isParentRoot ? [@(localName.c_str()) substringToIndex:1].capitalizedString : L(@"downloader_available_maps");
[indexSet addObject:index];
NSMutableArray<NSString *> * letterIds = availableCountries[index];
letterIds = letterIds ?: [@[] mutableCopy];
[letterIds addObject:nsCountryId];
availableCountries[index] = letterIds;
}
self.indexes = [[indexSet allObjects] sortedArrayUsingComparator:compareStrings];
[availableCountries enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSMutableArray<NSString *> * obj, BOOL * stop)
{
[obj sortUsingComparator:compareLocalNames];
}];
self.availableCountries = availableCountries;
}
- (void)configDownloadedSection:(CountriesVec const &)downloadedChildren
{
NSMutableArray<NSString *> * downloadedCountries = [@[] mutableCopy];
for (auto const & countryId : downloadedChildren)
[downloadedCountries addObject:@(countryId.c_str())];
self.downloadedCountries = [downloadedCountries sortedArrayUsingComparator:compareLocalNames];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (self.downloadedCountries && self.downloadedCountries.count)
return self.isParentRoot ? 2 : 1;
if (self.indexes)
return self.indexes.count;
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self isButtonCell:section])
return 1;
if (self.downloadedCountries && self.downloadedCountries.count)
return self.downloadedCountries.count;
NSString * index = self.indexes[section];
return self.availableCountries[index].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isButtonCell:indexPath.section])
{
Class cls = [MWMMapDownloaderButtonTableViewCell class];
auto cell = static_cast<MWMMapDownloaderButtonTableViewCell *>(
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
cell.delegate = self.delegate;
return cell;
}
else
{
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.isParentRoot ? self.indexes : nil;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return index;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (self.downloadedCountries)
{
if ([self isButtonCell:section])
return @"";
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(m_parentId, nodeAttrs);
if (nodeAttrs.m_localMwmSize == 0)
return [NSString stringWithFormat:@"%@", L(@"downloader_downloaded_subtitle")];
else
return [NSString stringWithFormat:@"%@ (%@)", L(@"downloader_downloaded_subtitle"), formattedSize(nodeAttrs.m_localMwmSize)];
}
return self.indexes[section];
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return nil;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isButtonCell:indexPath.section])
return NO;
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs([self countryIdForIndexPath:indexPath].UTF8String, nodeAttrs);
NodeStatus const status = nodeAttrs.m_status;
return (status == NodeStatus::OnDisk || status == NodeStatus::OnDiskOutOfDate || status == NodeStatus::Partly);
}
#pragma mark - MWMMapDownloaderDataSource
- (NSString *)parentCountryId
{
return @(m_parentId.c_str());
}
- (NSString *)countryIdForIndexPath:(NSIndexPath *)indexPath
{
NSInteger const section = indexPath.section;
NSInteger const row = indexPath.row;
if (row < self.downloadedCountries.count)
return self.downloadedCountries[row];
NSString * index = self.indexes[section];
NSArray<NSString *> * availableCountries = self.availableCountries[index];
NSString * nsCountryId = availableCountries[indexPath.row];
return nsCountryId;
}
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath
{
auto const & s = GetFramework().GetStorage();
CountriesVec children;
s.GetChildren([self countryIdForIndexPath:indexPath].UTF8String, children);
BOOL const haveChildren = !children.empty();
if (haveChildren)
return [MWMMapDownloaderLargeCountryTableViewCell class];
if (self.isParentRoot)
return [MWMMapDownloaderTableViewCell class];
return [MWMMapDownloaderPlaceTableViewCell class];
}
#pragma mark - Helpers
- (BOOL)isButtonCell:(NSInteger)section
{
return self.downloadedCountries && self.isParentRoot && section != 0;
}
@end

View file

@ -1,11 +0,0 @@
#import "MWMMapDownloaderDefaultDataSource.h"
enum class MWMMapDownloaderDataSourceExtraSection
{
NearMe,
Ads
};
@interface MWMMapDownloaderExtendedDataSource : MWMMapDownloaderDefaultDataSource
@end

View file

@ -1,129 +0,0 @@
#import "MWMMapDownloaderExtendedDataSource.h"
#import "CLLocation+Mercator.h"
#import "MWMLocationManager.h"
#include <CoreApi/Framework.h>
using namespace storage;
namespace
{
auto constexpr extraSection = MWMMapDownloaderDataSourceExtraSection::NearMe;
} // namespace
@interface MWMMapDownloaderDefaultDataSource ()
@property (nonatomic, readonly) NSInteger downloadedCountrySection;
- (void)load;
@end
@interface MWMMapDownloaderExtendedDataSource ()
@property(copy, nonatomic) NSArray<NSString *> * nearmeCountries;
@end
@implementation MWMMapDownloaderExtendedDataSource
{
std::vector<MWMMapDownloaderDataSourceExtraSection> m_extraSections;
}
- (void)load
{
[super load];
if (self.mode == MWMMapDownloaderModeAvailable)
[self configNearMeSection];
}
- (void)configNearMeSection
{
[self removeExtraSection:extraSection];
CLLocation * lastLocation = [MWMLocationManager lastLocation];
if (!lastLocation)
return;
auto & f = GetFramework();
auto & countryInfoGetter = f.GetCountryInfoGetter();
CountriesVec closestCoutryIds;
countryInfoGetter.GetRegionsCountryId(lastLocation.mercator, closestCoutryIds);
NSMutableArray<NSString *> * nearmeCountries = [@[] mutableCopy];
for (auto const & countryId : closestCoutryIds)
{
storage::NodeStatuses nodeStatuses;
f.GetStorage().GetNodeStatuses(countryId, nodeStatuses);
if (nodeStatuses.m_status != NodeStatus::OnDisk)
[nearmeCountries addObject:@(countryId.c_str())];
}
self.nearmeCountries = nearmeCountries;
if (nearmeCountries.count != 0)
[self addExtraSection:extraSection];
}
- (void)addExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection
{
auto const endIt = m_extraSections.end();
auto const findIt = find(m_extraSections.begin(), endIt, extraSection);
if (findIt == endIt)
{
m_extraSections.emplace_back(extraSection);
sort(m_extraSections.begin(), m_extraSections.end());
}
}
- (void)removeExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection
{
m_extraSections.erase(remove(m_extraSections.begin(), m_extraSections.end(), extraSection), m_extraSections.end());
}
- (BOOL)isExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection
atIndex:(NSInteger)sectionIndex
{
if (sectionIndex >= m_extraSections.size())
return NO;
return m_extraSections[sectionIndex] == extraSection;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [super numberOfSectionsInTableView:tableView] + m_extraSections.size();
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self isExtraSection:extraSection atIndex:section])
return self.nearmeCountries.count;
return [super tableView:tableView numberOfRowsInSection:section - m_extraSections.size()];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [super tableView:tableView sectionForSectionIndexTitle:title atIndex:index] +
m_extraSections.size();
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if ([self isExtraSection:extraSection atIndex:section])
return L(@"downloader_near_me_subtitle");
return [super tableView:tableView titleForHeaderInSection:section - m_extraSections.size()];
}
#pragma mark - MWMMapDownloaderDataSource
- (NSString *)countryIdForIndexPath:(NSIndexPath *)indexPath
{
NSInteger const row = indexPath.row;
NSInteger const section = indexPath.section;
if ([self isExtraSection:extraSection atIndex:section])
return self.nearmeCountries[row];
NSAssert(section >= m_extraSections.size(), @"Invalid section");
return
[super countryIdForIndexPath:[NSIndexPath indexPathForRow:row
inSection:section - m_extraSections.size()]];
}
@end

View file

@ -1,8 +0,0 @@
#import <MyTargetSDK/MTRGAppwallBannerAdView.h>
#import "MWMMapDownloaderExtendedDataSource.h"
@interface MWMMapDownloaderExtendedDataSourceWithAds : MWMMapDownloaderExtendedDataSource
- (MTRGAppwallBannerAdView *)viewForBannerAtIndex:(NSUInteger)index;
@end

View file

@ -1,114 +0,0 @@
#import "MWMMapDownloaderExtendedDataSourceWithAds.h"
#import "MWMMapDownloaderAdsTableViewCell.h"
#import "MWMMyTarget.h"
#include <CoreApi/Framework.h>
namespace
{
auto constexpr extraSection = MWMMapDownloaderDataSourceExtraSection::Ads;
} // namespace
@interface MWMMapDownloaderExtendedDataSource ()
- (void)load;
- (void)addExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection;
- (void)removeExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection;
- (BOOL)isExtraSection:(MWMMapDownloaderDataSourceExtraSection)extraSection
atIndex:(NSInteger)sectionIndex;
@end
@implementation MWMMapDownloaderExtendedDataSourceWithAds
- (void)load
{
[super load];
if (self.mode == MWMMapDownloaderModeAvailable)
[self configAdsSection];
}
- (void)configAdsSection
{
[self removeExtraSection:extraSection];
auto & purchase = GetFramework().GetPurchase();
bool hasSubscription = purchase && purchase->IsSubscriptionActive(SubscriptionType::RemoveAds);
if ([UIColor isNightMode] || !GetFramework().GetStorage().HaveDownloadedCountries() || hasSubscription)
return;
if ([MWMMyTarget manager].bannersCount != 0)
[self addExtraSection:extraSection];
}
- (MTRGAppwallBannerAdView *)viewForBannerAtIndex:(NSUInteger)index
{
MTRGAppwallBannerAdView * adView = [[MTRGAppwallBannerAdView alloc] initWithDelegate:nil];
adView.paddings = {.top = 12, .left = 16, .bottom = 12, .right = 16};
adView.touchColor = [UIColor white];
adView.normalColor = [UIColor white];
adView.iconSize = {24, 24};
UIEdgeInsets iconMargins = adView.iconMargins;
iconMargins.right += 8;
adView.iconMargins = iconMargins;
adView.showTopBorder = NO;
adView.showGotoAppIcon = NO;
adView.showRating = NO;
adView.showStatusIcon = NO;
adView.showBubbleIcon = NO;
adView.showCoins = NO;
adView.showCrossNotifIcon = NO;
adView.titleFont = [UIFont regular17];
adView.titleColor = [UIColor blackPrimaryText];
adView.descriptionColor = [UIColor blackSecondaryText];
adView.descriptionFont = [UIFont regular13];
[adView setAppWallBanner:[[MWMMyTarget manager] bannerAtIndex:index]];
return adView;
}
#pragma mark - MWMMapDownloaderDataSource
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath
{
if ([self isExtraSection:extraSection atIndex:indexPath.section])
return [MWMMapDownloaderAdsTableViewCell class];
return [super cellClassForIndexPath:indexPath];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isExtraSection:extraSection atIndex:indexPath.section])
return NO;
return [super tableView:tableView canEditRowAtIndexPath:indexPath];
}
#pragma mark - Fill cells with data
- (void)fillCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
if (![self isExtraSection:extraSection atIndex:indexPath.section])
return [super fillCell:cell atIndexPath:indexPath];
MWMMapDownloaderAdsTableViewCell * tCell = static_cast<MWMMapDownloaderAdsTableViewCell *>(cell);
tCell.adView = [self viewForBannerAtIndex:indexPath.row];
[[MWMMyTarget manager] handleBannerShowAtIndex:indexPath.row];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self isExtraSection:extraSection atIndex:section])
return [MWMMyTarget manager].bannersCount;
return [super tableView:tableView numberOfRowsInSection:section];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if ([self isExtraSection:extraSection atIndex:section])
return L(@"MY.COM");
return [super tableView:tableView titleForHeaderInSection:section];
}
@end

View file

@ -1,11 +0,0 @@
#import "MWMMapDownloaderDataSource.h"
#include "storage/downloader_search_params.hpp"
@interface MWMMapDownloaderSearchDataSource : MWMMapDownloaderDataSource
@property(nonatomic, readonly) BOOL isEmpty;
- (instancetype)initWithSearchResults:(DownloaderSearchResults const &)results delegate:(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate;
@end

View file

@ -1,95 +0,0 @@
#import "MWMMapDownloaderSearchDataSource.h"
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
#import "MWMMapDownloaderPlaceTableViewCell.h"
#import "MWMMapDownloaderSubplaceTableViewCell.h"
#include <CoreApi/Framework.h>
using namespace storage;
@interface MWMMapDownloaderSearchDataSource ()
@property (copy, nonatomic) NSArray<NSString *> * searchCountryIds;
@property (copy, nonatomic) NSDictionary<NSString *, NSString *> * searchMatchedResults;
@property (copy, nonatomic) NSString * searchQuery;
@end
@implementation MWMMapDownloaderSearchDataSource
- (instancetype)initWithSearchResults:(DownloaderSearchResults const &)results delegate:(id<MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>)delegate
{
self = [super initWithDelegate:delegate mode:MWMMapDownloaderModeAvailable];
if (self)
{
NSMutableOrderedSet<NSString *> * nsSearchCountryIds =
[NSMutableOrderedSet orderedSetWithCapacity:results.m_results.size()];
NSMutableDictionary<NSString *, NSString *> * nsSearchResults = [@{} mutableCopy];
for (auto const & result : results.m_results)
{
NSString * nsCountryId = @(result.m_countryId.c_str());
[nsSearchCountryIds addObject:nsCountryId];
nsSearchResults[nsCountryId] = @(result.m_matchedName.c_str());
}
_searchCountryIds = [nsSearchCountryIds array];
_searchMatchedResults = nsSearchResults;
_searchQuery = @(results.m_query.c_str());
}
return self;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.searchCountryIds.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return L(@"downloader_search_results");
}
#pragma mark - MWMMapDownloaderDataSource
- (NSString *)parentCountryId
{
return @(GetFramework().GetStorage().GetRootId().c_str());
}
- (NSString *)countryIdForIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row < self.searchCountryIds.count)
return self.searchCountryIds[indexPath.row];
return @(kInvalidCountryId.c_str());
}
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath
{
auto const & s = GetFramework().GetStorage();
NSString * countryId = [self countryIdForIndexPath:indexPath];
CountriesVec children;
s.GetChildren(countryId.UTF8String, children);
BOOL const haveChildren = !children.empty();
if (haveChildren)
return [MWMMapDownloaderLargeCountryTableViewCell class];
NodeAttrs nodeAttrs;
s.GetNodeAttrs(countryId.UTF8String, nodeAttrs);
NSString * nodeLocalName = @(nodeAttrs.m_nodeLocalName.c_str());
NSString * matchedResult = [self searchMatchedResultForCountryId:countryId];
if (![nodeLocalName isEqualToString:matchedResult])
return [MWMMapDownloaderSubplaceTableViewCell class];
if (nodeAttrs.m_parentInfo.size() == 1 && nodeAttrs.m_parentInfo[0].m_id == s.GetRootId())
return [MWMMapDownloaderTableViewCell class];
return [MWMMapDownloaderPlaceTableViewCell class];
}
- (NSString *)searchMatchedResultForCountryId:(NSString *)countryId
{
return self.searchMatchedResults[countryId];
}
#pragma mark - Properties
- (BOOL)isEmpty { return self.searchCountryIds.count == 0; }
@end

View file

@ -0,0 +1,433 @@
@objc(MWMDownloadMapsViewController)
class DownloadMapsViewController: MWMViewController {
// MARK: - Types
private enum NodeAction {
case showOnMap
case download
case update
case cancelDownload
case retryDownload
case delete
}
// MARK: - Outlets
@IBOutlet var tableView: UITableView!
@IBOutlet var allMapsView: UIView!
@IBOutlet var allMapsViewBottomOffset: NSLayoutConstraint!
@IBOutlet var allMapsButton: UIButton!
@IBOutlet var allMapsCancelButton: UIButton!
@IBOutlet var searchBar: UISearchBar!
@IBOutlet var statusBarBackground: UIView!
@IBOutlet var noMapsContainer: UIView!
// MARK: - Properties
var dataSource: IDownloaderDataSource!
@objc var mode: MWMMapDownloaderMode = .downloaded
private var skipCountryEvent = false
lazy var noSerchResultViewController: SearchNoResultsViewController = {
let vc = storyboard!.instantiateViewController(ofType: SearchNoResultsViewController.self)
view.insertSubview(vc.view, belowSubview: statusBarBackground)
vc.view.alignToSuperview()
vc.view.isHidden = true
addChild(vc)
vc.didMove(toParent: self)
return vc
}()
// MARK: - Methods
override func viewDidLoad() {
super.viewDidLoad()
if dataSource == nil {
switch mode {
case .downloaded:
dataSource = DownloadedMapsDataSource()
case .available:
dataSource = AvailableMapsDataSource()
@unknown default:
fatalError()
}
}
tableView.registerNib(cell: MWMMapDownloaderTableViewCell.self)
tableView.registerNib(cell: MWMMapDownloaderPlaceTableViewCell.self)
tableView.registerNib(cell: MWMMapDownloaderLargeCountryTableViewCell.self)
tableView.registerNib(cell: MWMMapDownloaderSubplaceTableViewCell.self)
title = dataSource.title
if mode == .downloaded {
let addMapsButton = button(with: UIImage(named: "ic_nav_bar_add"), action: #selector(onAddMaps))
navigationItem.rightBarButtonItem = addMapsButton
}
MWMFrameworkListener.add(self)
noMapsContainer.isHidden = !dataSource.isEmpty || Storage.downloadInProgress()
configButtons()
}
fileprivate func showChildren(_ nodeAttrs: MapNodeAttributes) {
let vc = storyboard!.instantiateViewController(ofType: DownloadMapsViewController.self)
vc.mode = mode
vc.dataSource = dataSource.dataSourceFor(nodeAttrs.countryId)
navigationController?.pushViewController(vc, animated: true)
}
fileprivate func showActions(_ nodeAttrs: MapNodeAttributes) {
let menuTitle = nodeAttrs.nodeName
let multiparent = nodeAttrs.parentInfo.count > 1
let message = dataSource.isRoot || multiparent ? nil : nodeAttrs.parentInfo.first?.countryName
let actionSheet = UIAlertController(title: menuTitle, message: message, preferredStyle: .actionSheet)
let actions: [NodeAction]
switch nodeAttrs.nodeStatus {
case .undefined:
actions = []
case .downloading, .applying, .inQueue:
actions = [.cancelDownload]
case .error:
actions = nodeAttrs.downloadedMwmCount > 0 ? [.retryDownload, .delete] : [.retryDownload]
case .onDiskOutOfDate:
actions = [.showOnMap, .update, .delete]
case .onDisk:
actions = [.showOnMap, .delete]
case .notDownloaded:
actions = [.download]
case .partly:
actions = [.download, .delete]
@unknown default:
fatalError()
}
addActions(actions, for: nodeAttrs, to: actionSheet)
actionSheet.addAction(UIAlertAction(title: L("cancel"), style: .cancel))
present(actionSheet, animated: true)
}
private func addActions(_ actions: [NodeAction], for nodeAttrs: MapNodeAttributes, to actionSheet: UIAlertController) {
actions.forEach { [unowned self] in
let action: UIAlertAction
switch $0 {
case .showOnMap:
action = UIAlertAction(title: L("zoom_to_country"), style: .default, handler: { _ in
Storage.showNode(nodeAttrs.countryId)
self.navigationController?.popToRootViewController(animated: true)
})
case .download:
let prefix = nodeAttrs.totalMwmCount == 1 ? L("downloader_download_map") : L("downloader_download_all_button")
action = UIAlertAction(title: "\(prefix) (\(formattedSize(nodeAttrs.totalSize)))",
style: .default,
handler: { _ in
Storage.downloadNode(nodeAttrs.countryId, onSuccess: nil)
})
case .update:
let title = "\(L("downloader_status_outdated")) (TODO: updated size)"
action = UIAlertAction(title: title, style: .default, handler: { _ in
Storage.updateNode(nodeAttrs.countryId)
})
case .cancelDownload:
action = UIAlertAction(title: L("cancel_download"), style: .destructive, handler: { _ in
Storage.cancelDownloadNode(nodeAttrs.countryId)
})
case .retryDownload:
action = UIAlertAction(title: L("downloader_retry"), style: .destructive, handler: { _ in
Storage.retryDownloadNode(nodeAttrs.countryId)
})
case .delete:
action = UIAlertAction(title: L("downloader_delete_map"), style: .destructive, handler: { _ in
Storage.deleteNode(nodeAttrs.countryId)
})
}
actionSheet.addAction(action)
}
}
fileprivate func configButtons() {
allMapsView.isHidden = true
if mode == .available {
if dataSource.isRoot {
allMapsView.isHidden = true
} else {
let parentAttributes = dataSource.parentAttributes()
if parentAttributes.downloadingMwmCount > 0 {
allMapsView.isHidden = false
allMapsButton.isHidden = true
allMapsCancelButton.isHidden = false
allMapsCancelButton.setTitle(
"\(L("downloader_cancel_all")) (\(formattedSize(parentAttributes.downloadingSize)))",
for: .normal)
} else if parentAttributes.downloadedMwmCount < parentAttributes.totalMwmCount {
allMapsView.isHidden = false
allMapsButton.isHidden = false
allMapsButton.setTitle(
"\(L("downloader_download_all_button")) (\(formattedSize(parentAttributes.totalSize - parentAttributes.downloadedSize)))",
for: .normal)
allMapsCancelButton.isHidden = true
}
}
} else {
let updateInfo = Storage.updateInfo(withParent: dataSource.parentAttributes().countryId)
if updateInfo.numberOfFiles > 0 {
allMapsView.isHidden = false
allMapsButton.isHidden = false
allMapsButton.setTitle(
"\(L("downloader_update_all_button")) (\(formattedSize(updateInfo.updateSize)))",
for: .normal)
allMapsCancelButton.isHidden = true
} else {
let parentAttributes = dataSource.parentAttributes()
if parentAttributes.downloadingMwmCount > 0 {
allMapsView.isHidden = false
allMapsButton.isHidden = true
allMapsCancelButton.isHidden = false
allMapsCancelButton.setTitle(L("downloader_cancel_all"), for: .normal)
}
}
}
}
@objc func onAddMaps() {
let vc = storyboard!.instantiateViewController(ofType: DownloadMapsViewController.self)
vc.mode = .available
navigationController?.pushViewController(vc, animated: true)
}
@IBAction func onAllMaps(_ sender: UIButton) {
skipCountryEvent = true
if mode == .downloaded {
Storage.updateNode(dataSource.parentAttributes().countryId, onCancel: nil)
} else {
Storage.downloadNode(dataSource.parentAttributes().countryId, onSuccess: nil, onCancel: nil)
}
skipCountryEvent = false
self.processCountryEvent(dataSource.parentAttributes().countryId)
}
@IBAction func onCancelAllMaps(_ sender: UIButton) {
skipCountryEvent = true
Storage.cancelDownloadNode(dataSource.parentAttributes().countryId)
skipCountryEvent = false
self.processCountryEvent(dataSource.parentAttributes().countryId)
tableView.reloadData()
}
}
// MARK: - UITableViewDataSource
extension DownloadMapsViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
dataSource.numberOfSections()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
dataSource.numberOfItems(in: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let nodeAttrs = dataSource.item(at: indexPath)
let cell: MWMMapDownloaderTableViewCell
if dataSource.item(at: indexPath).hasChildren {
let cellType = MWMMapDownloaderLargeCountryTableViewCell.self
let largeCountryCell = tableView.dequeueReusableCell(cell: cellType, indexPath: indexPath)
cell = largeCountryCell
} else if let matchedName = dataSource.matchedName(at: indexPath), matchedName != nodeAttrs.nodeName {
let cellType = MWMMapDownloaderSubplaceTableViewCell.self
let subplaceCell = tableView.dequeueReusableCell(cell: cellType, indexPath: indexPath)
subplaceCell.setSubplaceText(matchedName)
cell = subplaceCell
} else if !nodeAttrs.hasParent {
let cellType = MWMMapDownloaderTableViewCell.self
let downloaderCell = tableView.dequeueReusableCell(cell: cellType, indexPath: indexPath)
cell = downloaderCell
} else {
let cellType = MWMMapDownloaderPlaceTableViewCell.self
let placeCell = tableView.dequeueReusableCell(cell: cellType, indexPath: indexPath)
cell = placeCell
}
cell.mode = dataSource.isSearching ? .available : mode
cell.config(nodeAttrs, searchQuery: searchBar.text)
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
dataSource.title(for: section)
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
dataSource.indexTitles()
}
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
index
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
let nodeAttrs = dataSource.item(at: indexPath)
switch nodeAttrs.nodeStatus {
case .onDisk, .onDiskOutOfDate, .partly:
return true
default:
return false
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
let nodeAttrs = dataSource.item(at: indexPath)
Storage.deleteNode(nodeAttrs.countryId)
}
}
}
// MARK: - UITableViewDelegate
extension DownloadMapsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = MWMMapDownloaderCellHeader()
headerView.text = dataSource.title(for: section)
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
28
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
section == dataSource.numberOfSections() - 1 ? 68 : 0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let nodeAttrs = dataSource.item(at: indexPath)
if nodeAttrs.hasChildren {
showChildren(dataSource.item(at: indexPath))
return
}
showActions(nodeAttrs)
}
}
// MARK: - UIScrollViewDelegate
extension DownloadMapsViewController: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
searchBar.resignFirstResponder()
}
}
// MARK: - MWMMapDownloaderTableViewCellDelegate
extension DownloadMapsViewController: MWMMapDownloaderTableViewCellDelegate {
func mapDownloaderCellDidPressProgress(_ cell: MWMMapDownloaderTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let nodeAttrs = dataSource.item(at: indexPath)
switch (nodeAttrs.nodeStatus) {
case .undefined, .error:
Storage.retryDownloadNode(nodeAttrs.countryId)
break
case .downloading, .applying, .inQueue:
Storage.cancelDownloadNode(nodeAttrs.countryId)
break
case .onDiskOutOfDate:
Storage.updateNode(nodeAttrs.countryId)
break
case .onDisk:
//do nothing
break
case .notDownloaded, .partly:
if nodeAttrs.hasChildren {
showChildren(nodeAttrs)
} else {
Storage.downloadNode(nodeAttrs.countryId, onSuccess: nil)
}
break
@unknown default:
fatalError()
}
}
func mapDownloaderCellDidLongPress(_ cell: MWMMapDownloaderTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let nodeAttrs = dataSource.item(at: indexPath)
showActions(nodeAttrs)
}
}
// MARK: - MWMFrameworkStorageObserver
extension DownloadMapsViewController: MWMFrameworkStorageObserver {
func processCountryEvent(_ countryId: String) {
print("processCountryEvent: \(countryId)")
if skipCountryEvent && countryId == dataSource.parentAttributes().countryId {
return
}
dataSource.reload {
tableView.reloadData()
noMapsContainer.isHidden = !dataSource.isEmpty || Storage.downloadInProgress()
}
if countryId == dataSource.parentAttributes().countryId {
configButtons()
}
for cell in tableView.visibleCells {
guard let downloaderCell = cell as? MWMMapDownloaderTableViewCell else { continue }
if downloaderCell.nodeAttrs.countryId != countryId { continue }
guard let indexPath = tableView.indexPath(for: downloaderCell) else { return }
downloaderCell.config(dataSource.item(at: indexPath), searchQuery: searchBar.text)
}
}
func processCountry(_ countryId: String, downloadedBytes: UInt64, totalBytes: UInt64) {
for cell in tableView.visibleCells {
guard let downloaderCell = cell as? MWMMapDownloaderTableViewCell else { continue }
if downloaderCell.nodeAttrs.countryId != countryId { continue }
downloaderCell.setDownloadProgress(CGFloat(downloadedBytes) / CGFloat(totalBytes))
}
}
}
// MARK: - UISearchBarDelegate
extension DownloadMapsViewController: UISearchBarDelegate {
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
searchBar.setShowsCancelButton(true, animated: true)
navigationController?.setNavigationBarHidden(true, animated: true)
tableView.contentInset = .zero
tableView.scrollIndicatorInsets = .zero
return true
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
searchBar.setShowsCancelButton(false, animated: true)
navigationController?.setNavigationBarHidden(false, animated: true)
tableView.contentInset = .zero
tableView.scrollIndicatorInsets = .zero
return true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = nil
searchBar.resignFirstResponder()
dataSource.cancelSearch()
tableView.reloadData()
self.noSerchResultViewController.view.isHidden = true
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let locale = searchBar.textInputMode?.primaryLanguage
dataSource.search(searchText, locale: locale ?? "") { [weak self] (finished) in
guard let self = self else { return }
self.tableView.reloadData()
self.noSerchResultViewController.view.isHidden = !self.dataSource.isEmpty
}
}
}
// MARK: - UIBarPositioningDelegate
extension DownloadMapsViewController: UIBarPositioningDelegate {
func position(for bar: UIBarPositioning) -> UIBarPosition {
.topAttached
}
}

View file

@ -0,0 +1,128 @@
class DownloadedMapsDataSource {
private let parentCountryId: String?
private var countryIds: [String]
fileprivate var searching = false
fileprivate lazy var searchDataSource: IDownloaderDataSource = {
SearchMapsDataSource()
}()
init(_ parentId: String? = nil) {
self.parentCountryId = parentId
countryIds = DownloadedMapsDataSource.loadData(parentId)
}
private class func loadData(_ parentId: String?) -> [String] {
let countryIds: [String]
if let parentId = parentId {
countryIds = Storage.downloadedCountries(withParent: parentId)
} else {
countryIds = Storage.downloadedCountries()
}
return countryIds.map {
CountryIdAndName(countryId: $0, name: Storage.name(forCountry: $0))
}.sorted {
$0.countryName.compare($1.countryName) == .orderedAscending
}.map {
$0.countryId
}
}
fileprivate func reloadData() {
countryIds = DownloadedMapsDataSource.loadData(parentCountryId)
}
}
extension DownloadedMapsDataSource: IDownloaderDataSource {
var isEmpty: Bool {
return searching ? searchDataSource.isEmpty : countryIds.isEmpty
}
var title: String {
guard let parentCountryId = parentCountryId else {
return L("downloader_my_maps_title")
}
return Storage.name(forCountry: parentCountryId)
}
var isRoot: Bool {
parentCountryId == nil
}
var isSearching: Bool {
searching
}
func parentAttributes() -> MapNodeAttributes {
guard let parentId = parentCountryId else {
return Storage.attributesForRoot()
}
return Storage.attributes(forCountry: parentId)
}
func numberOfSections() -> Int {
searching ? searchDataSource.numberOfSections() : 1
}
func numberOfItems(in section: Int) -> Int {
searching ? searchDataSource.numberOfItems(in: section) : countryIds.count
}
func item(at indexPath: IndexPath) -> MapNodeAttributes {
if searching {
return searchDataSource.item(at: indexPath)
}
guard indexPath.section == 0 else { fatalError() }
let countryId = countryIds[indexPath.item]
return Storage.attributes(forCountry: countryId)
}
func matchedName(at indexPath: IndexPath) -> String? {
searching ? searchDataSource.matchedName(at: indexPath) : nil
}
func title(for section: Int) -> String {
if searching {
return searchDataSource.title(for: section)
}
if let parentCountryId = parentCountryId {
let attributes = Storage.attributes(forCountry: parentCountryId)
return Storage.name(forCountry: parentCountryId) + " (\(formattedSize(attributes.downloadedSize)))"
}
let attributes = Storage.attributesForRoot()
return L("downloader_downloaded_subtitle") + " (\(formattedSize(attributes.downloadedSize)))"
}
func indexTitles() -> [String]? {
nil
}
func dataSourceFor(_ childId: String) -> IDownloaderDataSource {
searching ? searchDataSource.dataSourceFor(childId) : DownloadedMapsDataSource(childId)
}
func reload(_ completion: () -> Void) {
if searching {
searchDataSource.reload(completion)
return
}
reloadData()
completion()
}
func search(_ query: String, locale: String, update: @escaping (Bool) -> Void) {
if query.isEmpty {
cancelSearch()
update(true)
return
}
searching = true
searchDataSource.search(query, locale: locale, update: update)
}
func cancelSearch() {
searching = false
searchDataSource.cancelSearch()
}
}

View file

@ -0,0 +1,17 @@
protocol IDownloaderDataSource {
var isEmpty: Bool { get }
var title: String { get }
var isRoot: Bool { get }
var isSearching: Bool { get }
func parentAttributes() -> MapNodeAttributes
func numberOfSections() -> Int
func numberOfItems(in section: Int) -> Int
func item(at indexPath: IndexPath) -> MapNodeAttributes
func matchedName(at indexPath: IndexPath) -> String?
func title(for section: Int) -> String
func indexTitles() -> [String]?
func dataSourceFor(_ childId: String) -> IDownloaderDataSource
func reload(_ completion: () -> Void)
func search(_ query: String, locale: String, update: @escaping (_ completed: Bool) -> Void)
func cancelSearch()
}

View file

@ -1,13 +0,0 @@
#import "MWMMapDownloaderButtonTableViewCell.h"
#import "MWMMapDownloaderMode.h"
#import "MWMMapDownloaderProtocol.h"
#import "MWMViewController.h"
@interface MWMBaseMapDownloaderViewController : MWMViewController <UITableViewDelegate, MWMMapDownloaderProtocol, MWMMapDownloaderButtonTableViewCellProtocol>
- (void)configTable;
- (void)configAllMapsView;
- (void)setParentCountryId:(NSString *)parentId mode:(MWMMapDownloaderMode)mode;
@end

View file

@ -1,776 +0,0 @@
#import "MWMBaseMapDownloaderViewController.h"
#import "MWMButton.h"
#import "MWMFrameworkListener.h"
#import "MWMMapDownloaderAdsTableViewCell.h"
#import "MWMMapDownloaderCellHeader.h"
#import "MWMMapDownloaderDefaultDataSource.h"
#import "MWMMapDownloaderExtendedDataSourceWithAds.h"
#import "MWMMapDownloaderLargeCountryTableViewCell.h"
#import "MWMMapDownloaderPlaceTableViewCell.h"
#import "MWMMapDownloaderSubplaceTableViewCell.h"
#import "MWMMyTarget.h"
#import "MWMSegue.h"
#import "MWMStorage.h"
#import "SwiftBridge.h"
#include <CoreApi/Framework.h>
namespace
{
typedef NS_OPTIONS(NSUInteger, ActionButtons) {
NoAction = 0,
ShowOnMapAction = 1 << 1,
DownloadAction = 1 << 2,
UpdateAction = 1 << 3,
CancelDownloadAction = 1 << 4,
RetryDownloadAction = 1 << 5,
DeleteAction = 1 << 6
};
NSString * const kAllMapsLabelFormat = @"%@ (%@)";
NSString * const kCancelActionTitle = L(@"cancel");
NSString * const kCancelAllTitle = L(@"downloader_cancel_all");
NSString * const kCancelDownloadActionTitle = L(@"cancel_download");
NSString * const kDeleteActionTitle = L(@"downloader_delete_map");
NSString * const kDownloadActionTitle = L(@"downloader_download_map");
NSString * const kDownloadAllActionTitle = L(@"downloader_download_all_button");
NSString * const kDownloadingTitle = L(@"downloader_downloading");
NSString * const kMapsTitle = L(@"downloader_maps");
NSString * const kRetryActionTitle = L(@"downloader_retry");
NSString * const kShowOnMapActionTitle = L(@"zoom_to_country");
NSString * const kUpdateActionTitle = L(@"downloader_status_outdated");
NSString * const kUpdateAllTitle = L(@"downloader_update_all_button");
NSString * const kBaseControllerIdentifier = @"MWMBaseMapDownloaderViewController";
NSString * const kControllerIdentifier = @"MWMMapDownloaderViewController";
} // namespace
using namespace storage;
@interface MWMBaseMapDownloaderViewController ()<UIScrollViewDelegate, MWMFrameworkStorageObserver,
MWMMyTargetDelegate>
@property (weak, nonatomic) IBOutlet UITableView * tableView;
@property (weak, nonatomic) IBOutlet UIView * allMapsView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * allMapsViewBottomOffset;
@property (weak, nonatomic) IBOutlet MWMButton * allMapsButton;
@property (weak, nonatomic) IBOutlet MWMButton * allMapsCancelButton;
@property (nonatomic) UIImage * navBarBackground;
@property (nonatomic) UIImage * navBarShadow;
@property (nonatomic) CGFloat lastScrollOffset;
@property (nonatomic) MWMMapDownloaderDataSource * dataSource;
@property (nonatomic) MWMMapDownloaderDefaultDataSource * defaultDataSource;
@property (nonatomic) BOOL skipCountryEventProcessing;
@property (nonatomic) BOOL forceFullReload;
@property (nonatomic, readonly) NSString * parentCountryId;
@property(nonatomic, readonly) MWMMapDownloaderMode mode;
@property (nonatomic) BOOL showAllMapsButtons;
@end
@implementation MWMBaseMapDownloaderViewController
{
CountryId m_actionSheetId;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configNavBar];
[self configTable];
[self configMyTarget];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[MWMFrameworkListener addObserver:self];
[self configViews];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[MWMFrameworkListener removeObserver:self];
[self notifyParentController];
}
- (void)configViews
{
[self configAllMapsView];
}
- (void)configNavBar
{
BOOL const downloaded = self.mode == MWMMapDownloaderModeDownloaded;
if (self.dataSource.isParentRoot)
{
self.title = downloaded ? L(@"downloader_my_maps_title") : L(@"download_maps");
}
else
{
NodeAttrs nodeAttrs;
GetFramework().GetStorage().GetNodeAttrs(self.parentCountryId.UTF8String, nodeAttrs);
self.title = @(nodeAttrs.m_nodeLocalName.c_str());
}
if (downloaded)
{
UIBarButtonItem * addButton = [self buttonWithImage:[UIImage imageNamed:@"ic_nav_bar_add"]
action:@selector(openAvailableMaps)];
self.navigationItem.rightBarButtonItems = [self alignedNavBarButtonItems:@[ addButton ]];
}
}
- (void)configMyTarget { [MWMMyTarget manager].delegate = self; }
- (void)notifyParentController
{
NSArray<MWMViewController *> * viewControllers = [self.navigationController viewControllers];
BOOL const goingTreeDeeper = ([viewControllers indexOfObject:self] != NSNotFound);
if (goingTreeDeeper)
return;
MWMViewController * parentVC = viewControllers.lastObject;
if ([parentVC isKindOfClass:[MWMBaseMapDownloaderViewController class]])
{
MWMBaseMapDownloaderViewController * downloaderVC = static_cast<MWMBaseMapDownloaderViewController *>(parentVC);
[downloaderVC processCountryEvent:self.parentCountryId.UTF8String];
}
}
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
{
if (self.skipCountryEventProcessing)
return;
for (UITableViewCell * cell in self.tableView.visibleCells)
{
if ([cell conformsToProtocol:@protocol(MWMFrameworkStorageObserver)])
[static_cast<id<MWMFrameworkStorageObserver>>(cell) processCountryEvent:countryId];
}
BOOL needReload = NO;
auto const & s = GetFramework().GetStorage();
s.ForEachInSubtree(self.parentCountryId.UTF8String,
[&needReload, &countryId](CountryId const & descendantId, bool groupNode) {
needReload = needReload || countryId == descendantId;
});
if (needReload)
{
[self configViews];
[self reloadData];
}
}
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress
{
for (UITableViewCell * cell in self.tableView.visibleCells)
{
if ([cell conformsToProtocol:@protocol(MWMFrameworkStorageObserver)])
[static_cast<id<MWMFrameworkStorageObserver>>(cell) processCountry:countryId progress:progress];
}
}
#pragma mark - Table
- (void)configTable
{
UITableView * tv = self.tableView;
tv.separatorColor = [UIColor blackDividers];
[tv registerWithCellClass:[MWMMapDownloaderAdsTableViewCell class]];
[tv registerWithCellClass:[MWMMapDownloaderButtonTableViewCell class]];
[tv registerWithCellClass:[MWMMapDownloaderTableViewCell class]];
[tv registerWithCellClass:[MWMMapDownloaderLargeCountryTableViewCell class]];
[tv registerWithCellClass:[MWMMapDownloaderPlaceTableViewCell class]];
[tv registerWithCellClass:[MWMMapDownloaderSubplaceTableViewCell class]];
}
#pragma mark - MWMMyTargetDelegate
- (void)onAppWallRefresh { [self reloadTable]; }
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
SEL const selector = @selector(refreshAllMapsView);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector object:nil];
[self refreshAllMapsViewForOffset:targetContentOffset->y];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
SEL const selector = @selector(refreshAllMapsView);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector object:nil];
[self performSelector:selector withObject:nil afterDelay:kDefaultAnimationDuration];
}
#pragma mark - All Maps Action
- (void)configAllMapsView
{
auto const & s = GetFramework().GetStorage();
CountryId const parentCountryId = self.parentCountryId.UTF8String;
if (self.dataSource != self.defaultDataSource)
{
self.showAllMapsButtons = NO;
}
else if (self.mode == MWMMapDownloaderModeDownloaded)
{
Storage::UpdateInfo updateInfo{};
s.GetUpdateInfo(parentCountryId, updateInfo);
self.showAllMapsButtons = YES;
if (updateInfo.m_numberOfMwmFilesToUpdate != 0)
{
self.allMapsButton.hidden = NO;
[self.allMapsButton
setTitle:[NSString stringWithFormat:kAllMapsLabelFormat, kUpdateAllTitle,
formattedSize(updateInfo.m_totalUpdateSizeInBytes)]
forState:UIControlStateNormal];
self.allMapsCancelButton.hidden = YES;
}
else
{
CountriesVec queuedChildren;
s.GetQueuedChildren(parentCountryId, queuedChildren);
if (queuedChildren.empty())
{
self.showAllMapsButtons = NO;
}
else
{
self.showAllMapsButtons = YES;
self.allMapsButton.hidden = YES;
self.allMapsCancelButton.hidden = NO;
[self.allMapsCancelButton setTitle:kCancelAllTitle forState:UIControlStateNormal];
}
}
}
else if (parentCountryId != s.GetRootId())
{
CountriesVec queuedChildren;
s.GetQueuedChildren(parentCountryId, queuedChildren);
if (queuedChildren.empty())
{
CountriesVec downloadedChildren;
CountriesVec availableChildren;
s.GetChildrenInGroups(parentCountryId, downloadedChildren, availableChildren, true /* keepAvailableChildren */);
self.showAllMapsButtons = downloadedChildren.size() != availableChildren.size();
if (self.showAllMapsButtons)
{
NodeAttrs nodeAttrs;
s.GetNodeAttrs(parentCountryId, nodeAttrs);
self.allMapsButton.hidden = NO;
[self.allMapsButton
setTitle:[NSString stringWithFormat:kAllMapsLabelFormat, kDownloadAllActionTitle,
formattedSize(nodeAttrs.m_mwmSize)]
forState:UIControlStateNormal];
self.allMapsCancelButton.hidden = YES;
}
}
else
{
MwmSize queuedSize = 0;
for (CountryId const & countryId : queuedChildren)
{
NodeAttrs nodeAttrs;
s.GetNodeAttrs(countryId, nodeAttrs);
queuedSize += nodeAttrs.m_mwmSize;
}
self.showAllMapsButtons = YES;
self.allMapsButton.hidden = YES;
self.allMapsCancelButton.hidden = NO;
[self.allMapsCancelButton
setTitle:[NSString stringWithFormat:kAllMapsLabelFormat, kCancelAllTitle,
formattedSize(queuedSize)]
forState:UIControlStateNormal];
}
}
else
{
self.showAllMapsButtons = NO;
}
}
- (void)refreshAllMapsView
{
[self refreshAllMapsViewForOffset:self.tableView.contentOffset.y];
}
- (void)refreshAllMapsViewForOffset:(CGFloat)scrollOffset
{
if (!self.showAllMapsButtons)
return;
UITableView * tv = self.tableView;
CGFloat const bottomOffset = tv.contentSize.height - tv.frame.size.height;
BOOL const hide =
scrollOffset >= self.lastScrollOffset && scrollOffset > 0 && scrollOffset < bottomOffset;
self.lastScrollOffset = scrollOffset;
if (self.allMapsView.hidden == hide)
return;
if (!hide)
self.allMapsView.hidden = hide;
[self.view layoutIfNeeded];
self.allMapsViewBottomOffset.constant = hide ? self.allMapsView.height : 0.0;
[UIView animateWithDuration:kDefaultAnimationDuration
animations:^{
self.allMapsView.alpha = hide ? 0.0 : 1.0;
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
if (hide)
self.allMapsView.hidden = hide;
}];
}
- (IBAction)allMapsAction
{
self.skipCountryEventProcessing = YES;
CountryId const parentCountryId = self.parentCountryId.UTF8String;
if (self.mode == MWMMapDownloaderModeDownloaded)
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatUpdate,
kStatIsAuto: kStatNo,
kStatFrom: kStatDownloader,
kStatScenario: kStatUpdateAll
}];
[MWMStorage updateNode:parentCountryId
onCancel:nil];
}
else
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction : kStatDownload,
kStatIsAuto : kStatNo,
kStatFrom : kStatDownloader,
kStatScenario : kStatDownloadGroup
}];
[MWMStorage downloadNode:parentCountryId
onSuccess:nil
onCancel:nil];
}
self.skipCountryEventProcessing = NO;
[self processCountryEvent:parentCountryId];
}
- (IBAction)allMapsCancelAction
{
self.skipCountryEventProcessing = YES;
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction : kStatCancel,
kStatIsAuto : kStatNo,
kStatFrom : kStatDownloader,
kStatScenario : kStatDownloadGroup
}];
CountryId const parentCountryId = self.parentCountryId.UTF8String;
[MWMStorage cancelDownloadNode:parentCountryId];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:parentCountryId];
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Class cls = [self.dataSource cellClassForIndexPath:indexPath];
if ([MWMMapDownloaderLargeCountryTableViewCell class] == cls)
{
NSAssert(self.dataSource != nil, @"Datasource is nil.");
NSString * countyId = [self.dataSource countryIdForIndexPath:indexPath];
NSAssert(countyId != nil, @"CountryId is nil.");
[self openNodeSubtree:countyId.UTF8String];
}
else if ([MWMMapDownloaderAdsTableViewCell class] == cls)
{
[[MWMMyTarget manager] handleBannerClickAtIndex:indexPath.row withController:self];
}
else
{
[self showActionSheetForRowAtIndexPath:indexPath];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Class cls = [self.dataSource cellClassForIndexPath:indexPath];
if ([MWMMapDownloaderAdsTableViewCell class] == cls)
{
MWMMapDownloaderExtendedDataSourceWithAds * adDataSource =
static_cast<MWMMapDownloaderExtendedDataSourceWithAds *>(self.dataSource);
MTRGAppwallBannerAdView * adView = [adDataSource viewForBannerAtIndex:indexPath.row];
return [adView sizeThatFits:{CGRectGetWidth(tableView.bounds), 0}].height + 1;
}
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.dataSource isButtonCell:indexPath.section])
return [MWMMapDownloaderButtonTableViewCell estimatedHeight];
Class<MWMMapDownloaderTableViewCellProtocol> cellClass =
[self.dataSource cellClassForIndexPath:indexPath];
return [cellClass estimatedHeight];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return [self.dataSource isButtonCell:section] ? 36 : 28;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return section == [tableView numberOfSections] - 1 ? 68 : 0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
CGFloat const width = CGRectGetWidth(tableView.bounds);
CGFloat const height = [self tableView:tableView heightForHeaderInSection:section];
MWMMapDownloaderCellHeader * headerView =
[[MWMMapDownloaderCellHeader alloc] initWithFrame:{{}, {width, height}}];
headerView.text = [self.dataSource tableView:tableView titleForHeaderInSection:section];
return headerView;
}
#pragma mark - UILongPressGestureRecognizer
- (IBAction)longPress:(UILongPressGestureRecognizer *)sender
{
if (sender.state != UIGestureRecognizerStateBegan)
return;
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:[sender locationInView:self.tableView]];
if (!indexPath)
return;
if ([self.dataSource isButtonCell:indexPath.section])
return;
Class cls = [self.dataSource cellClassForIndexPath:indexPath];
if ([MWMMapDownloaderAdsTableViewCell class] == cls)
return;
[self showActionSheetForRowAtIndexPath:indexPath];
}
#pragma mark - Action Sheet
- (void)showActionSheetForRowAtIndexPath:(NSIndexPath *)indexPath
{
auto const & s = GetFramework().GetStorage();
NodeAttrs nodeAttrs;
NSAssert(self.dataSource != nil, @"Datasource is nil.");
NSString * countyId = [self.dataSource countryIdForIndexPath:indexPath];
NSAssert(countyId != nil, @"CountryId is nil.");
m_actionSheetId = countyId.UTF8String;
s.GetNodeAttrs(m_actionSheetId, nodeAttrs);
ActionButtons buttons = NoAction;
switch (nodeAttrs.m_status)
{
case NodeStatus::Undefined:
break;
case NodeStatus::NotDownloaded:
buttons |= DownloadAction;
break;
case NodeStatus::Downloading:
case NodeStatus::InQueue:
case NodeStatus::Applying: buttons |= CancelDownloadAction; break;
case NodeStatus::OnDiskOutOfDate:
buttons |= ShowOnMapAction;
buttons |= UpdateAction;
buttons |= DeleteAction;
break;
case NodeStatus::OnDisk:
buttons |= ShowOnMapAction;
buttons |= DeleteAction;
break;
case NodeStatus::Partly:
buttons |= DownloadAction;
buttons |= DeleteAction;
break;
case NodeStatus::Error:
buttons |= RetryDownloadAction;
if (nodeAttrs.m_localMwmCounter != 0)
buttons |= DeleteAction;
break;
}
NSAssert(buttons != NoAction, @"No action buttons defined.");
if (buttons == NoAction)
return;
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIView * cellSuperView = cell.superview;
if (!cellSuperView)
return;
NSString * title = @(nodeAttrs.m_nodeLocalName.c_str());
BOOL const isMultiParent = (nodeAttrs.m_parentInfo.size() > 1);
NSString * message = (self.dataSource.isParentRoot || isMultiParent)
? nil
: @(nodeAttrs.m_parentInfo[0].m_localName.c_str());
UIAlertController * alertController =
[UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleActionSheet];
alertController.popoverPresentationController.sourceView = cell;
alertController.popoverPresentationController.sourceRect = cell.bounds;
[self addButtons:buttons toActionComponent:alertController];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)addButtons:(ActionButtons)buttons toActionComponent:(UIAlertController *)alertController
{
if (buttons & ShowOnMapAction)
{
UIAlertAction * action = [UIAlertAction actionWithTitle:kShowOnMapActionTitle
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{ [self showNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
auto const & s = GetFramework().GetStorage();
if (buttons & DownloadAction)
{
NodeAttrs nodeAttrs;
s.GetNodeAttrs(m_actionSheetId, nodeAttrs);
NSString * prefix = nodeAttrs.m_mwmCounter == 1 ? kDownloadActionTitle : kDownloadAllActionTitle;
NSString * title = [NSString stringWithFormat:kAllMapsLabelFormat, prefix,
formattedSize(nodeAttrs.m_mwmSize)];
UIAlertAction * action = [UIAlertAction actionWithTitle:title
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{ [self downloadNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
if (buttons & UpdateAction)
{
Storage::UpdateInfo updateInfo;
s.GetUpdateInfo(m_actionSheetId, updateInfo);
NSString * title = [NSString stringWithFormat:kAllMapsLabelFormat, kUpdateActionTitle,
formattedSize(updateInfo.m_totalUpdateSizeInBytes)];
UIAlertAction * action = [UIAlertAction actionWithTitle:title
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{ [self updateNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
if (buttons & CancelDownloadAction)
{
UIAlertAction * action = [UIAlertAction actionWithTitle:kCancelDownloadActionTitle
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action)
{ [self cancelNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
if (buttons & RetryDownloadAction)
{
UIAlertAction * action = [UIAlertAction actionWithTitle:kRetryActionTitle
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action)
{ [self retryDownloadNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
if (buttons & DeleteAction)
{
UIAlertAction * action = [UIAlertAction actionWithTitle:kDeleteActionTitle
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action)
{ [self deleteNode:self->m_actionSheetId]; }];
[alertController addAction:action];
}
UIAlertAction * action = [UIAlertAction actionWithTitle:kCancelActionTitle
style:UIAlertActionStyleCancel
handler:nil];
[alertController addAction:action];
}
#pragma mark - Countries tree(s) navigation
- (void)openAvailableMaps
{
BOOL const isParentRoot = [self.parentCountryId isEqualToString:@(GetFramework().GetStorage().GetRootId().c_str())];
NSString * identifier = isParentRoot ? kControllerIdentifier : kBaseControllerIdentifier;
MWMBaseMapDownloaderViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
[vc setParentCountryId:self.parentCountryId mode:MWMMapDownloaderModeAvailable];
[MWMSegue segueFrom:self to:vc];
}
#pragma mark - MWMMapDownloaderProtocol
- (void)openNodeSubtree:(storage::CountryId const &)countryId
{
MWMBaseMapDownloaderViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:kBaseControllerIdentifier];
[vc setParentCountryId:@(countryId.c_str()) mode:self.mode];
[MWMSegue segueFrom:self to:vc];
}
- (void)downloadNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatDownload,
kStatIsAuto: kStatNo,
kStatFrom: kStatDownloader,
kStatScenario: kStatDownload
}];
self.skipCountryEventProcessing = YES;
[MWMStorage downloadNode:countryId onSuccess:nil onCancel:nil];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:countryId];
}
- (void)retryDownloadNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatRetry,
kStatIsAuto: kStatNo,
kStatFrom: kStatDownloader,
kStatScenario: kStatDownload
}];
self.skipCountryEventProcessing = YES;
[MWMStorage retryDownloadNode:countryId];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:countryId];
}
- (void)updateNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatUpdate,
kStatIsAuto: kStatNo,
kStatFrom: kStatDownloader,
kStatScenario: kStatUpdate
}];
self.skipCountryEventProcessing = YES;
[MWMStorage updateNode:countryId onCancel:nil];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:countryId];
}
- (void)deleteNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatDelete,
kStatIsAuto: kStatNo,
kStatFrom: kStatDownloader,
kStatScenario: kStatDelete
}];
self.skipCountryEventProcessing = YES;
[MWMStorage deleteNode:countryId];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:countryId];
}
- (void)cancelNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderDownloadCancel withParameters:@{kStatFrom : kStatDownloader}];
self.skipCountryEventProcessing = YES;
[MWMStorage cancelDownloadNode:countryId];
self.skipCountryEventProcessing = NO;
[self processCountryEvent:countryId];
}
- (void)showNode:(storage::CountryId const &)countryId
{
[Statistics logEvent:kStatDownloaderMapAction
withParameters:@{
kStatAction: kStatExplore,
kStatFrom: kStatDownloader,
}];
[self.navigationController popToRootViewControllerAnimated:YES];
[MWMStorage showNode:countryId];
}
#pragma mark - Managing the Status Bar
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
#pragma mark - Configuration
- (void)setParentCountryId:(NSString *)parentId mode:(MWMMapDownloaderMode)mode
{
self.defaultDataSource = [[MWMMapDownloaderDefaultDataSource alloc] initForRootCountryId:parentId
delegate:self
mode:mode];
}
#pragma mark - Properties
- (void)setTableView:(UITableView *)tableView
{
_tableView = tableView;
tableView.tableFooterView = [[UIView alloc] initWithFrame:{}];
self.dataSource = self.defaultDataSource;
}
- (void)setShowAllMapsButtons:(BOOL)showAllMapsButtons
{
_showAllMapsButtons = showAllMapsButtons;
self.allMapsView.hidden = !showAllMapsButtons;
}
- (NSString *)parentCountryId
{
return self.dataSource.parentCountryId;
}
- (MWMMapDownloaderMode)mode { return self.dataSource.mode; }
- (void)setDataSource:(MWMMapDownloaderDataSource *)dataSource
{
self.forceFullReload = YES;
// Order matters. _dataSource must be set last since self.tableView does not retain dataSource.
// In different order outdated datasource gets reclaimed between assignments.
self.tableView.dataSource = dataSource;
_dataSource = dataSource;
}
#pragma mark - Helpers
- (void)reloadData
{
MWMMapDownloaderDefaultDataSource * defaultDataSource = self.defaultDataSource;
[defaultDataSource load];
if (self.dataSource == defaultDataSource)
[self reloadTable];
}
- (void)reloadTable
{
UITableView * tableView = self.tableView;
// If these methods are not called, tableView will not call tableView:cellForRowAtIndexPath:
[tableView setNeedsLayout];
[tableView layoutIfNeeded];
[tableView reloadData];
// If these methods are not called, tableView will not display new cells
[tableView setNeedsLayout];
[tableView layoutIfNeeded];
}
@end

View file

@ -1,13 +0,0 @@
#include "storage/storage_defines.hpp"
@protocol MWMMapDownloaderProtocol <NSObject>
- (void)openNodeSubtree:(storage::CountryId const &)countryId;
- (void)downloadNode:(storage::CountryId const &)countryId;
- (void)retryDownloadNode:(storage::CountryId const &)countryId;
- (void)updateNode:(storage::CountryId const &)countryId;
- (void)deleteNode:(storage::CountryId const &)countryId;
- (void)cancelNode:(storage::CountryId const &)countryId;
- (void)showNode:(storage::CountryId const &)countryId;
@end

View file

@ -1,5 +0,0 @@
#import "MWMBaseMapDownloaderViewController.h"
@interface MWMMapDownloaderViewController : MWMBaseMapDownloaderViewController
@end

View file

@ -1,209 +0,0 @@
#import "MWMMapDownloaderViewController.h"
#import "MWMMapDownloaderExtendedDataSourceWithAds.h"
#import "MWMMapDownloaderSearchDataSource.h"
#import "SwiftBridge.h"
#include <CoreApi/Framework.h>
namespace
{
NSString * const kMapDownloaderNoResultsEmbedViewControllerSegue =
@"MapDownloaderNoResultsEmbedViewControllerSegue";
} // namespace
using namespace storage;
@interface MWMBaseMapDownloaderViewController ()
@property(weak, nonatomic) IBOutlet UITableView * tableView;
@property(nonatomic) MWMMapDownloaderDataSource * dataSource;
@property(nonatomic) MWMMapDownloaderDataSource * defaultDataSource;
@property(nonatomic, readonly) NSString * parentCountryId;
@property(nonatomic, readonly) MWMMapDownloaderMode mode;
@property(nonatomic) BOOL showAllMapsButtons;
- (void)configViews;
- (void)openAvailableMaps;
- (void)reloadTable;
@end
@interface MWMMapDownloaderViewController ()<UISearchBarDelegate, UIScrollViewDelegate>
@property(weak, nonatomic) IBOutlet UIView * statusBarBackground;
@property(weak, nonatomic) IBOutlet UISearchBar * searchBar;
@property(weak, nonatomic) IBOutlet UIView * noMapsContainer;
@property(nonatomic) MWMDownloaderNoResultsEmbedViewController * noResultsEmbedViewController;
@property(nonatomic) MWMMapDownloaderSearchDataSource * searchDataSource;
@property(nonatomic) NSTimeInterval lastSearchTimestamp;
@end
@implementation MWMMapDownloaderViewController
{
DownloaderSearchParams m_searchParams;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar.placeholder = L(@"downloader_search_field_hint");
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIColor * searchBarColor = [UIColor primary];
self.statusBarBackground.backgroundColor = self.searchBar.barTintColor = searchBarColor;
self.searchBar.backgroundImage = [UIImage imageWithColor:searchBarColor];
}
- (void)configViews
{
[super configViews];
[self checkAndConfigNoMapsView];
}
#pragma mark - No Maps
- (void)checkAndConfigNoMapsView
{
auto const & s = GetFramework().GetStorage();
if (![self.parentCountryId isEqualToString:@(s.GetRootId().c_str())])
return;
auto const showResults = ^{
[self configAllMapsView];
self.tableView.hidden = NO;
self.noMapsContainer.hidden = YES;
};
auto const showNoResults = ^(MWMDownloaderNoResultsScreen screen) {
self.showAllMapsButtons = NO;
self.tableView.hidden = YES;
self.noMapsContainer.hidden = NO;
self.noResultsEmbedViewController.screen = screen;
};
BOOL const noResults =
self.dataSource == self.searchDataSource && self.searchDataSource.isEmpty;
BOOL const isModeAvailable = self.mode == MWMMapDownloaderModeAvailable;
BOOL const haveActiveMaps = s.HaveDownloadedCountries() || s.IsDownloadInProgress();
if (noResults)
showNoResults(MWMDownloaderNoResultsScreenNoSearchResults);
else if (isModeAvailable || haveActiveMaps)
showResults();
else
showNoResults(MWMDownloaderNoResultsScreenNoMaps);
}
#pragma mark - UISearchBarDelegate
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
[self.searchBar setShowsCancelButton:YES animated:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
self.tableView.contentInset = self.tableView.scrollIndicatorInsets = {};
return YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
[self.searchBar setShowsCancelButton:NO animated:YES];
[self.navigationController setNavigationBarHidden:NO animated:YES];
self.tableView.contentInset = self.tableView.scrollIndicatorInsets = {};
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
self.searchBar.text = @"";
[self.searchBar resignFirstResponder];
self.dataSource = self.defaultDataSource;
[self reloadTable];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSString * primaryLanguage = self.searchBar.textInputMode.primaryLanguage;
if (primaryLanguage)
m_searchParams.m_inputLocale = primaryLanguage.UTF8String;
m_searchParams.m_query = searchText.precomposedStringWithCompatibilityMapping.UTF8String;
[self updateSearchCallback];
GetFramework().SearchInDownloader(m_searchParams);
}
#pragma mark - UIBarPositioningDelegate
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; }
#pragma mark - Search
- (void)updateSearchCallback
{
__weak auto weakSelf = self;
NSTimeInterval const timestamp = [NSDate date].timeIntervalSince1970;
self.lastSearchTimestamp = timestamp;
m_searchParams.m_onResults = [weakSelf, timestamp](DownloaderSearchResults const & results) {
__strong auto self = weakSelf;
if (!self || timestamp != self.lastSearchTimestamp)
return;
if (results.m_query.empty())
{
self.dataSource = self.defaultDataSource;
}
else
{
self.searchDataSource =
[[MWMMapDownloaderSearchDataSource alloc] initWithSearchResults:results delegate:self];
self.dataSource = self.searchDataSource;
}
[self reloadTable];
};
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.searchBar resignFirstResponder];
}
#pragma mark - MWMNoMapsViewControllerProtocol
- (void)handleDownloadMapsAction { [self openAvailableMaps]; }
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[super prepareForSegue:segue sender:sender];
if ([segue.identifier isEqualToString:kMapDownloaderNoResultsEmbedViewControllerSegue])
self.noResultsEmbedViewController = segue.destinationViewController;
}
#pragma mark - Configuration
- (void)setParentCountryId:(NSString *)parentId mode:(MWMMapDownloaderMode)mode
{
self.defaultDataSource =
[[MWMMapDownloaderExtendedDataSourceWithAds alloc] initForRootCountryId:parentId
delegate:self
mode:mode];
}
#pragma mark - Helpers
- (void)reloadTable
{
[super reloadTable];
[self checkAndConfigNoMapsView];
}
@end

View file

@ -0,0 +1,75 @@
class SearchMapsDataSource {
fileprivate var searchResults: [MapSearchResult] = []
fileprivate var searchId = 0
}
extension SearchMapsDataSource: IDownloaderDataSource {
var isEmpty: Bool {
searchResults.isEmpty
}
var title: String {
""
}
var isRoot: Bool {
true
}
var isSearching: Bool {
true
}
func numberOfSections() -> Int {
1
}
func parentAttributes() -> MapNodeAttributes {
return Storage.attributesForRoot()
}
func numberOfItems(in section: Int) -> Int {
searchResults.count
}
func item(at indexPath: IndexPath) -> MapNodeAttributes {
Storage.attributes(forCountry: searchResults[indexPath.item].countryId)
}
func matchedName(at indexPath: IndexPath) -> String? {
searchResults[indexPath.item].matchedName
}
func title(for section: Int) -> String {
L("downloader_search_results")
}
func indexTitles() -> [String]? {
nil
}
func dataSourceFor(_ childId: String) -> IDownloaderDataSource {
AvailableMapsDataSource(childId)
}
func reload(_ completion: () -> Void) {
completion()
}
func search(_ query: String, locale: String, update: @escaping (Bool) -> Void) {
searchId += 1
FrameworkHelper.search(inDownloader: query, inputLocale: locale) { [weak self, searchId] (results, finished) in
self?.searchResults = results
if searchId != self?.searchId {
return
}
if results.count > 0 || finished {
update(finished)
}
}
}
func cancelSearch() {
self.searchResults = []
}
}

View file

@ -2,6 +2,7 @@
#import "CLLocation+Mercator.h"
#import "MWMActivityViewController.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMLocationHelpers.h"
#import "MWMLocationObserver.h"
#import "MWMPlacePageData.h"
@ -18,6 +19,8 @@
#include "geometry/distance_on_sphere.hpp"
using namespace storage;
namespace
{
void logSponsoredEvent(MWMPlacePageData * data, NSString * eventName)
@ -104,7 +107,7 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
[self.layout showWithData:self.data];
// Call for the first time to produce changes
[self processCountryEvent:[self.data countryId]];
[self processCountryEvent:@([self.data countryId].c_str())];
}
- (void)update {
@ -165,13 +168,13 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
switch (nodeAttrs.m_status)
{
case NodeStatus::NotDownloaded:
case NodeStatus::Partly: [MWMStorage downloadNode:countryId onSuccess:nil onCancel:nil]; break;
case NodeStatus::Partly: [MWMStorage downloadNode:@(countryId.c_str()) onSuccess:nil onCancel:nil]; break;
case NodeStatus::Undefined:
case NodeStatus::Error: [MWMStorage retryDownloadNode:countryId]; break;
case NodeStatus::OnDiskOutOfDate: [MWMStorage updateNode:countryId onCancel:nil]; break;
case NodeStatus::Error: [MWMStorage retryDownloadNode:@(countryId.c_str())]; break;
case NodeStatus::OnDiskOutOfDate: [MWMStorage updateNode:@(countryId.c_str()) onCancel:nil]; break;
case NodeStatus::Downloading:
case NodeStatus::Applying:
case NodeStatus::InQueue: [MWMStorage cancelDownloadNode:countryId]; break;
case NodeStatus::InQueue: [MWMStorage cancelDownloadNode:@(countryId.c_str())]; break;
case NodeStatus::OnDisk: break;
}
}
@ -210,10 +213,10 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(CountryId const &)countryId
- (void)processCountryEvent:(NSString *)countryId
{
auto data = self.data;
if (!data || [data countryId] != countryId)
if (!data || [data countryId] != countryId.UTF8String)
return;
if ([data countryId] == kInvalidCountryId)
@ -233,16 +236,17 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page:
[self.layout processDownloaderEventWithStatus:status progress:0];
}
- (void)processCountry:(CountryId const &)countryId
progress:(MapFilesDownloader::Progress const &)progress
- (void)processCountry:(NSString *)countryId
downloadedBytes:(uint64_t)downloadedBytes
totalBytes:(uint64_t)totalBytes
{
auto data = self.data;
if (!data || countryId == kInvalidCountryId || [data countryId] != countryId)
if (!data || countryId.UTF8String == kInvalidCountryId || [data countryId] != countryId.UTF8String)
return;
[self.layout
processDownloaderEventWithStatus:storage::NodeStatus::Downloading
progress:static_cast<CGFloat>(progress.first) / progress.second];
progress:static_cast<CGFloat>(downloadedBytes) / totalBytes];
}
#pragma mark - MWMPlacePageLayoutDelegate

View file

@ -1,5 +1,6 @@
#import "MWMSearchManager.h"
#import "MWMFrameworkListener.h"
#import "MWMFrameworkStorageObserver.h"
#import "MWMMapViewControlsManager.h"
#import "MWMNoMapsViewController.h"
#import "MWMRoutePoint+CPP.h"
@ -188,11 +189,11 @@ using Observers = NSHashTable<Observer>;
#pragma mark - MWMFrameworkStorageObserver
- (void)processCountryEvent:(storage::CountryId const &)countryId
- (void)processCountryEvent:(NSString *)countryId
{
using namespace storage;
NodeStatuses nodeStatuses{};
GetFramework().GetStorage().GetNodeStatuses(countryId, nodeStatuses);
GetFramework().GetStorage().GetNodeStatuses(countryId.UTF8String, nodeStatuses);
if (nodeStatuses.m_status != NodeStatus::OnDisk)
return;
[self updateTopController];

View file

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Wns-nH-AQU">
<device id="retina4_0" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Wns-nH-AQU">
<device id="retina4_0" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -19,7 +17,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_carplay_activated" translatesAutoresizingMaskIntoConstraints="NO" id="Tqh-46-Yrm">
<rect key="frame" x="80" y="214" width="160" height="160"/>
<rect key="frame" x="80" y="204" width="160" height="160"/>
<constraints>
<constraint firstAttribute="height" constant="160" id="dkE-Cj-sE5"/>
<constraint firstAttribute="width" constant="160" id="pz7-lu-Ocm"/>
@ -33,7 +31,7 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<subviews>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="65S-M4-TnM" customClass="NavigationInfoArea" customModule="maps_me" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
</view>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TdT-ia-GP9" customClass="MenuArea" customModule="maps_me" customModuleProvider="target">
@ -49,15 +47,15 @@
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
</view>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NI8-tV-i2B" customClass="WidgetsArea" customModule="maps_me" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
</view>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xJx-UU-IdV" customClass="SideButtonsArea" customModule="maps_me" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
</view>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QKu-4A-UgP" customClass="TrafficButtonArea" customModule="maps_me" customModuleProvider="target">
<rect key="frame" x="0.0" y="20" width="320" height="548"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
</view>
</subviews>
@ -198,7 +196,7 @@
<navigationController id="Psz-BY-Fy4" customClass="MWMNavigationController" sceneMemberID="viewController">
<value key="contentSizeForViewInPopover" type="size" width="600" height="600"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="SUN-3A-xgM">
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
@ -244,7 +242,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="none" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="X1H-IB-Nv1">
<rect key="frame" x="0.0" y="20" width="320" height="504"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="524"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
@ -255,7 +253,7 @@
</connections>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aQv-7U-zAP">
<rect key="frame" x="0.0" y="20" width="320" height="504"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="524"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="PrH-u2-IEv" userLabel="Editor View" customClass="MWMTextView">
<rect key="frame" x="0.0" y="36" width="320" height="88"/>
@ -295,7 +293,7 @@
</userDefinedRuntimeAttributes>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="5T5-Pp-hb5">
<rect key="frame" x="0.0" y="459" width="320" height="1"/>
<rect key="frame" x="0.0" y="479" width="320" height="1"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="ZXK-zv-uSz"/>
</constraints>
@ -528,7 +526,7 @@
<rect key="frame" x="0.0" y="28" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RXe-xp-xlR" id="g0x-Vt-1FI">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JcK-nR-UGw">
@ -587,7 +585,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="JbV-y9-HBo">
<rect key="frame" x="0.0" y="76" width="320" height="492"/>
<rect key="frame" x="0.0" y="56" width="320" height="512"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
@ -598,7 +596,7 @@
</connections>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rI9-RR-sKP" userLabel="Status Bar Background">
<rect key="frame" x="0.0" y="-32" width="320" height="108"/>
<rect key="frame" x="0.0" y="-52" width="320" height="108"/>
<color key="backgroundColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@ -621,7 +619,7 @@
</userDefinedRuntimeAttributes>
</view>
<searchBar contentMode="redraw" translatesAutoresizingMaskIntoConstraints="NO" id="gzF-B7-8pj">
<rect key="frame" x="0.0" y="20" width="320" height="56"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="2uI-k6-ahr"/>
@ -670,7 +668,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="ina-WD-kps">
<rect key="frame" x="0.0" y="76" width="320" height="492"/>
<rect key="frame" x="0.0" y="56" width="320" height="512"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
@ -681,7 +679,7 @@
</connections>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HEU-Bu-3wh" userLabel="Status Bar Background">
<rect key="frame" x="0.0" y="-32" width="320" height="108"/>
<rect key="frame" x="0.0" y="-52" width="320" height="108"/>
<color key="backgroundColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@ -704,7 +702,7 @@
</userDefinedRuntimeAttributes>
</view>
<searchBar contentMode="redraw" translatesAutoresizingMaskIntoConstraints="NO" id="z6s-26-dP6">
<rect key="frame" x="0.0" y="20" width="320" height="56"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="UAk-z1-2EY"/>
@ -743,24 +741,24 @@
</objects>
<point key="canvasLocation" x="1055" y="3560"/>
</scene>
<!--Map Downloader View Controller-->
<!--Download Maps View Controller-->
<scene sceneID="1ZZ-fS-lza">
<objects>
<viewController storyboardIdentifier="MWMMapDownloaderViewController" id="h4a-ne-bSJ" customClass="MWMMapDownloaderViewController" sceneMemberID="viewController">
<viewController storyboardIdentifier="DownloadMapsViewController" id="h4a-ne-bSJ" customClass="MWMDownloadMapsViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="XQZ-0V-SyR">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="CwW-x8-G3j">
<rect key="frame" x="0.0" y="76" width="320" height="492"/>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="CwW-x8-G3j">
<rect key="frame" x="0.0" y="56" width="320" height="512"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="h4a-ne-bSJ" id="nrq-1D-7lZ"/>
<outlet property="delegate" destination="h4a-ne-bSJ" id="3jT-yg-FQv"/>
<outletCollection property="gestureRecognizers" destination="huu-3c-diL" appends="YES" id="h7R-bq-lcB"/>
</connections>
</tableView>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="st5-ZJ-F0A" userLabel="UpdateAllView">
@ -787,7 +785,7 @@
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="white"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="allMapsAction" destination="h4a-ne-bSJ" eventType="touchUpInside" id="swH-BL-Egj"/>
<action selector="onAllMaps:" destination="h4a-ne-bSJ" eventType="touchUpInside" id="dBj-ob-MNu"/>
</connections>
</button>
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bQM-6x-WHa" customClass="MWMButton">
@ -801,7 +799,7 @@
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="red"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="allMapsCancelAction" destination="h4a-ne-bSJ" eventType="touchUpInside" id="UOO-Sn-8Cf"/>
<action selector="onCancelAllMaps:" destination="h4a-ne-bSJ" eventType="touchUpInside" id="Vxv-zA-R1k"/>
</connections>
</button>
</subviews>
@ -834,7 +832,7 @@
</variation>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Xxz-fq-71r" userLabel="Status Bar Background">
<rect key="frame" x="0.0" y="-32" width="320" height="108"/>
<rect key="frame" x="0.0" y="-52" width="320" height="108"/>
<color key="backgroundColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@ -857,7 +855,7 @@
</userDefinedRuntimeAttributes>
</view>
<searchBar contentMode="redraw" translatesAutoresizingMaskIntoConstraints="NO" id="DPt-gs-efn">
<rect key="frame" x="0.0" y="20" width="320" height="56"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="9M7-y1-RSU"/>
@ -869,7 +867,7 @@
</connections>
</searchBar>
<containerView hidden="YES" opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kXO-Oh-2vO" userLabel="No Maps Container View">
<rect key="frame" x="0.0" y="76" width="320" height="492"/>
<rect key="frame" x="0.0" y="56" width="320" height="512"/>
<connections>
<segue destination="b8o-rZ-x0k" kind="embed" identifier="MapDownloaderNoResultsEmbedViewControllerSegue" id="ish-dC-mkH"/>
</connections>
@ -913,143 +911,25 @@
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="M3U-Z9-ALg" userLabel="First Responder" sceneMemberID="firstResponder"/>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="huu-3c-diL">
<connections>
<action selector="longPress:" destination="h4a-ne-bSJ" id="L7J-uC-Wnf"/>
</connections>
</pongPressGestureRecognizer>
</objects>
<point key="canvasLocation" x="3780" y="951"/>
</scene>
<!--Base Map Downloader View Controller-->
<scene sceneID="Gej-SE-BmY">
<objects>
<viewController storyboardIdentifier="MWMBaseMapDownloaderViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="ccD-FK-8j5" customClass="MWMBaseMapDownloaderViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="uK4-o2-eLJ">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="bgs-Kf-cQA">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="delegate" destination="ccD-FK-8j5" id="bu7-R5-NFs"/>
<outletCollection property="gestureRecognizers" destination="u47-DA-0Sa" appends="YES" id="U3g-pC-K4D"/>
</connections>
</tableView>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9vd-CW-37q" userLabel="UpdateAllView">
<rect key="frame" x="16" y="508" width="288" height="44"/>
<subviews>
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xL5-0u-TaG" customClass="MWMButton">
<rect key="frame" x="0.0" y="0.0" width="288" height="44"/>
<color key="backgroundColor" red="0.034757062792778015" green="0.31522077322006226" blue="0.81491315364837646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="Download All">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular17"/>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="linkBlue"/>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundHighlightedColorName" value="linkBlueHighlighted"/>
<userDefinedRuntimeAttribute type="string" keyPath="coloringName" value="MWMWhite"/>
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="white"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="allMapsAction" destination="ccD-FK-8j5" eventType="touchUpInside" id="EtQ-2G-MEd"/>
</connections>
</button>
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MmB-HW-cD5" customClass="MWMButton">
<rect key="frame" x="0.0" y="0.0" width="288" height="44"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular17"/>
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="red"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="allMapsCancelAction" destination="ccD-FK-8j5" eventType="touchUpInside" id="Wob-NQ-ZJX"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="xL5-0u-TaG" firstAttribute="top" secondItem="9vd-CW-37q" secondAttribute="top" id="6ui-Df-HR9"/>
<constraint firstItem="xL5-0u-TaG" firstAttribute="centerY" secondItem="9vd-CW-37q" secondAttribute="centerY" id="8ea-Gk-AzX"/>
<constraint firstItem="MmB-HW-cD5" firstAttribute="leading" secondItem="9vd-CW-37q" secondAttribute="leading" id="Dh1-Fr-eWw"/>
<constraint firstAttribute="height" priority="750" constant="44" id="Dow-HV-Frg"/>
<constraint firstItem="xL5-0u-TaG" firstAttribute="leading" secondItem="9vd-CW-37q" secondAttribute="leading" id="EdJ-xv-Ddl"/>
<constraint firstAttribute="bottom" secondItem="MmB-HW-cD5" secondAttribute="bottom" id="M2K-ym-QIN"/>
<constraint firstAttribute="trailing" secondItem="MmB-HW-cD5" secondAttribute="trailing" id="Qpf-le-AUb"/>
<constraint firstAttribute="trailing" secondItem="xL5-0u-TaG" secondAttribute="trailing" id="gm9-AZ-44g"/>
<constraint firstAttribute="bottom" secondItem="xL5-0u-TaG" secondAttribute="bottom" id="rd1-SA-czc"/>
<constraint firstItem="MmB-HW-cD5" firstAttribute="top" secondItem="9vd-CW-37q" secondAttribute="top" id="xAU-rg-nW4"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<variation key="default">
<mask key="constraints">
<exclude reference="8ea-Gk-AzX"/>
</mask>
</variation>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="rna-hw-m68" firstAttribute="trailing" secondItem="9vd-CW-37q" secondAttribute="trailing" constant="16" id="3T4-vx-sKV"/>
<constraint firstItem="9vd-CW-37q" firstAttribute="bottom" secondItem="rna-hw-m68" secondAttribute="bottom" priority="100" id="7qP-Cg-0PM"/>
<constraint firstItem="bgs-Kf-cQA" firstAttribute="leading" secondItem="uK4-o2-eLJ" secondAttribute="leading" id="8gX-1F-KTf"/>
<constraint firstItem="9vd-CW-37q" firstAttribute="leading" secondItem="rna-hw-m68" secondAttribute="leading" constant="16" id="Wrn-2m-Umk"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="9vd-CW-37q" secondAttribute="bottom" constant="16" id="arv-yq-Pjb"/>
<constraint firstItem="rna-hw-m68" firstAttribute="bottom" secondItem="bgs-Kf-cQA" secondAttribute="bottom" id="jBv-Bl-uzd"/>
<constraint firstAttribute="trailing" secondItem="bgs-Kf-cQA" secondAttribute="trailing" id="oXb-9d-uHx"/>
<constraint firstItem="bgs-Kf-cQA" firstAttribute="top" secondItem="uK4-o2-eLJ" secondAttribute="top" id="tLn-Tw-dPb"/>
</constraints>
<viewLayoutGuide key="safeArea" id="rna-hw-m68"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
</userDefinedRuntimeAttributes>
</view>
<connections>
<outlet property="allMapsButton" destination="xL5-0u-TaG" id="09K-th-orY"/>
<outlet property="allMapsCancelButton" destination="MmB-HW-cD5" id="wsr-lk-f32"/>
<outlet property="allMapsView" destination="9vd-CW-37q" id="XZs-Bj-AmZ"/>
<outlet property="tableView" destination="bgs-Kf-cQA" id="Nri-qd-wNS"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="MJl-0C-Sj1" userLabel="First Responder" sceneMemberID="firstResponder"/>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="u47-DA-0Sa">
<connections>
<action selector="longPress:" destination="ccD-FK-8j5" id="bEm-32-TBl"/>
</connections>
</pongPressGestureRecognizer>
</objects>
<point key="canvasLocation" x="4680" y="951"/>
</scene>
<!--No Maps View Controller-->
<scene sceneID="bz6-ac-EbZ">
<objects>
<viewController storyboardIdentifier="MWMNoMapsViewController" id="3el-Zi-2E4" customClass="MWMNoMapsViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="4WP-vj-Alg">
<rect key="frame" x="0.0" y="0.0" width="320" height="492"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="512"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gmw-e3-n53" userLabel="Container" customClass="MWMNoMapsView">
<rect key="frame" x="6" y="20" width="308" height="452"/>
<rect key="frame" x="6" y="0.0" width="308" height="512"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dCZ-PN-2Ob" userLabel="BoundsView">
<rect key="frame" x="16" y="0.0" width="276" height="348"/>
<rect key="frame" x="16" y="0.0" width="276" height="408"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="87G-jh-N8H" userLabel="CenteredView">
<rect key="frame" x="0.0" y="41.5" width="276" height="265"/>
<rect key="frame" x="0.0" y="71.5" width="276" height="265"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalCompressionResistancePriority="749" image="img_no_maps" translatesAutoresizingMaskIntoConstraints="NO" id="vI9-fc-FO2">
<rect key="frame" x="58" y="0.0" width="160" height="160"/>
@ -1112,7 +992,7 @@
</constraints>
</view>
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Moj-UK-oyl" userLabel="DownloadMaps" customClass="MWMButton">
<rect key="frame" x="34" y="368" width="240" height="44"/>
<rect key="frame" x="34" y="428" width="240" height="44"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="240" id="49x-bx-JJj"/>