diff --git a/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj b/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj index 01b3b78b08..530419f159 100644 --- a/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj +++ b/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj @@ -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 = ""; }; 4718C4302355FC3C00640DF1 /* MWMNetworkPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMNetworkPolicy.h; sourceTree = ""; }; 4718C4312355FC3C00640DF1 /* MWMNetworkPolicy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMNetworkPolicy.mm; sourceTree = ""; }; + 471AB98B23AB925D00F56D49 /* MWMMapSearchResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapSearchResult.h; sourceTree = ""; }; + 471AB98C23AB925D00F56D49 /* MWMMapSearchResult.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapSearchResult.mm; sourceTree = ""; }; + 471AB98F23AB931000F56D49 /* MWMMapSearchResult+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapSearchResult+Core.h"; sourceTree = ""; }; 475784C02344B421008291A4 /* Framework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Framework.h; sourceTree = ""; }; 475784C12344B422008291A4 /* Framework.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Framework.cpp; sourceTree = ""; }; 479834E62342697100724D1E /* MWMTag+Convenience.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "MWMTag+Convenience.mm"; sourceTree = ""; }; @@ -104,9 +116,15 @@ 47C637DA2354B79A00E12DE0 /* MWMSearchFrameworkHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSearchFrameworkHelper.mm; sourceTree = ""; }; 47C637DB2354B79B00E12DE0 /* MWMSearchFrameworkHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchFrameworkHelper.h; sourceTree = ""; }; 47D609DB234FE625008ECC47 /* MWMBookmarksObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMBookmarksObserver.h; sourceTree = ""; }; + 47D9019323AC22E500D9364C /* MWMMapUpdateInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapUpdateInfo.h; sourceTree = ""; }; + 47D9019423AC22E500D9364C /* MWMMapUpdateInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapUpdateInfo.mm; sourceTree = ""; }; + 47D9019723AC236100D9364C /* MWMMapUpdateInfo+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapUpdateInfo+Core.h"; sourceTree = ""; }; 47EEAFF22350CEDA005CF316 /* AppInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = AppInfo.mm; sourceTree = ""; }; 47EEAFF32350CEDB005CF316 /* AppInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppInfo.h; sourceTree = ""; }; 47EEAFF52350CEF6005CF316 /* MWMCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMCommon.h; sourceTree = ""; }; + 47F4F1F723A3336B0022FD56 /* MWMMapNodeAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMMapNodeAttributes.h; sourceTree = ""; }; + 47F4F1F823A3336C0022FD56 /* MWMMapNodeAttributes.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapNodeAttributes.mm; sourceTree = ""; }; + 47F4F1FB23A3D1AC0022FD56 /* MWMMapNodeAttributes+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMMapNodeAttributes+Core.h"; sourceTree = ""; }; 99103841237EDFA200893C9F /* DeepLinkData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeepLinkData.h; sourceTree = ""; }; 99103842237EDFA200893C9F /* DeepLinkData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeepLinkData.m; sourceTree = ""; }; 991CE2E82375AF19009EB02A /* PromoAfterBookingCampaignAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PromoAfterBookingCampaignAdapter.mm; sourceTree = ""; }; @@ -163,6 +181,7 @@ 470015F12342509C00EBF03D /* CoreApi */ = { isa = PBXGroup; children = ( + 47F4F1F623A333280022FD56 /* Storage */, 993F54ED237C5D1000545511 /* Promo */, 9957FAE5237AE59C00855F48 /* Logger */, 9957FAC1237AABD800855F48 /* DeepLink */, @@ -296,6 +315,22 @@ path = Search; sourceTree = ""; }; + 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 = ""; + }; 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 */, diff --git a/iphone/CoreApi/CoreApi/Common/MWMCommon.h b/iphone/CoreApi/CoreApi/Common/MWMCommon.h index 9fd02cd213..f2d541d0e5 100644 --- a/iphone/CoreApi/CoreApi/Common/MWMCommon.h +++ b/iphone/CoreApi/CoreApi/Common/MWMCommon.h @@ -1,5 +1,7 @@ #import +NS_ASSUME_NONNULL_BEGIN + static inline BOOL firstVersionIsLessThanSecond(NSString * first, NSString * second) { NSArray * 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 diff --git a/iphone/CoreApi/CoreApi/CoreApi-swift.h b/iphone/CoreApi/CoreApi/CoreApi-swift.h index 6a03c5b73e..00771da115 100644 --- a/iphone/CoreApi/CoreApi/CoreApi-swift.h +++ b/iphone/CoreApi/CoreApi/CoreApi-swift.h @@ -25,3 +25,6 @@ FOUNDATION_EXPORT const unsigned char CoreApiVersionString[]; #import #import #import +#import +#import +#import diff --git a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h index 353cf1d0f4..863bdea1c9 100644 --- a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h +++ b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h @@ -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 *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 diff --git a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm index 08ecc1dd60..b9dee5d2e9 100644 --- a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm +++ b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm @@ -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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes+Core.h b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes+Core.h new file mode 100644 index 0000000000..ca25bdb062 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes+Core.h @@ -0,0 +1,16 @@ +#import "MWMMapNodeAttributes.h" + +#include + +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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.h b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.h new file mode 100644 index 0000000000..71edb0bf80 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.h @@ -0,0 +1,47 @@ +#import + +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 *parentInfo; +@property(nonatomic, readonly, nullable) NSArray *topmostParentInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.mm b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.mm new file mode 100644 index 0000000000..3fd83c7fd0 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapNodeAttributes.mm @@ -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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult+Core.h b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult+Core.h new file mode 100644 index 0000000000..42815cc982 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult+Core.h @@ -0,0 +1,13 @@ +#import "MWMMapSearchResult.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface MWMMapSearchResult (Core) + +- (instancetype)initWithSearchResult:(storage::DownloaderSearchResult const &)searchResult; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.h b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.h new file mode 100644 index 0000000000..8572c7e523 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.h @@ -0,0 +1,13 @@ +#import + +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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.mm b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.mm new file mode 100644 index 0000000000..140b2168e4 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapSearchResult.mm @@ -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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo+Core.h b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo+Core.h new file mode 100644 index 0000000000..bc00253394 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo+Core.h @@ -0,0 +1,13 @@ +#import "MWMMapUpdateInfo.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface MWMMapUpdateInfo (Core) + +- (instancetype)initWithUpdateInfo:(storage::Storage::UpdateInfo const &)updateInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.h b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.h new file mode 100644 index 0000000000..059b37e473 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.h @@ -0,0 +1,14 @@ +#import + +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 diff --git a/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.mm b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.mm new file mode 100644 index 0000000000..62c3b5a059 --- /dev/null +++ b/iphone/CoreApi/CoreApi/Storage/MWMMapUpdateInfo.mm @@ -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 diff --git a/iphone/Maps/Bridging-Header.h b/iphone/Maps/Bridging-Header.h index a253e018af..41afe4a241 100644 --- a/iphone/Maps/Bridging-Header.h +++ b/iphone/Maps/Bridging-Header.h @@ -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" diff --git a/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm b/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm index 2ab9a80fd1..f9bcdd9d1e 100644 --- a/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm +++ b/iphone/Maps/Classes/CustomAlert/DownloadTransitMapsAlert/MWMDownloadTransitMapAlert.mm @@ -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 * 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(overallProgress.first) / overallProgress.second; diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index 7aa8fdcbfb..696fa1dd01 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -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(mode.integerValue)]; + dvc.mode = (MWMMapDownloaderMode)mode.integerValue; } else if ([segue.identifier isEqualToString:kMap2FBLoginSegue]) { diff --git a/iphone/Maps/Classes/MapsAppDelegate.mm b/iphone/Maps/Classes/MapsAppDelegate.mm index ee401d41c8..23b149bcaf 100644 --- a/iphone/Maps/Classes/MapsAppDelegate.mm +++ b/iphone/Maps/Classes/MapsAppDelegate.mm @@ -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. diff --git a/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm b/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm index 4febea13ee..ab975f3c91 100644 --- a/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm +++ b/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm @@ -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]; } diff --git a/iphone/Maps/Core/Framework/MWMFrameworkListener.h b/iphone/Maps/Core/Framework/MWMFrameworkListener.h index 55d814ee7e..6440bbee0b 100644 --- a/iphone/Maps/Core/Framework/MWMFrameworkListener.h +++ b/iphone/Maps/Core/Framework/MWMFrameworkListener.h @@ -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 diff --git a/iphone/Maps/Core/Framework/MWMFrameworkListener.mm b/iphone/Maps/Core/Framework/MWMFrameworkListener.mm index 3139cf26a8..f20f14ffd9 100644 --- a/iphone/Maps/Core/Framework/MWMFrameworkListener.mm +++ b/iphone/Maps/Core/Framework/MWMFrameworkListener.mm @@ -1,4 +1,5 @@ #import "MWMFrameworkListener.h" +#import "MWMFrameworkObservers.h" #include @@ -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]; } }); } diff --git a/iphone/Maps/Core/Framework/MWMFrameworkObserver.h b/iphone/Maps/Core/Framework/MWMFrameworkObserver.h new file mode 100644 index 0000000000..2794c72f0d --- /dev/null +++ b/iphone/Maps/Core/Framework/MWMFrameworkObserver.h @@ -0,0 +1,3 @@ +@protocol MWMFrameworkObserver + +@end diff --git a/iphone/Maps/Core/Framework/MWMFrameworkObservers.h b/iphone/Maps/Core/Framework/MWMFrameworkObservers.h index 987b94c8d5..3ee780d81e 100644 --- a/iphone/Maps/Core/Framework/MWMFrameworkObservers.h +++ b/iphone/Maps/Core/Framework/MWMFrameworkObservers.h @@ -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 - -@end - @protocol MWMFrameworkRouteBuilderObserver - (void)processRouteBuilderEvent:(routing::RouterResultCode)code @@ -25,17 +23,6 @@ using namespace storage; @end -@protocol MWMFrameworkStorageObserver - -- (void)processCountryEvent:(CountryId const &)countryId; - -@optional - -- (void)processCountry:(CountryId const &)countryId - progress:(MapFilesDownloader::Progress const &)progress; - -@end - @protocol MWMFrameworkDrapeObserver @optional diff --git a/iphone/Maps/Core/Framework/MWMFrameworkStorageObserver.h b/iphone/Maps/Core/Framework/MWMFrameworkStorageObserver.h new file mode 100644 index 0000000000..6ead532cd8 --- /dev/null +++ b/iphone/Maps/Core/Framework/MWMFrameworkStorageObserver.h @@ -0,0 +1,17 @@ +#import "MWMFrameworkObserver.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MWMFrameworkStorageObserver + +- (void)processCountryEvent:(NSString *)countryId; + +@optional + +- (void)processCountry:(NSString *)countryId + downloadedBytes:(uint64_t)downloadedBytes + totalBytes:(uint64_t)totalBytes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Core/Framework/ProxyObjects/Routing/MWMRoutingManager.mm b/iphone/Maps/Core/Framework/ProxyObjects/Routing/MWMRoutingManager.mm index fa280c4afa..0e2c4c3722 100644 --- a/iphone/Maps/Core/Framework/ProxyObjects/Routing/MWMRoutingManager.mm +++ b/iphone/Maps/Core/Framework/ProxyObjects/Routing/MWMRoutingManager.mm @@ -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" diff --git a/iphone/Maps/Core/Routing/MWMRouter.mm b/iphone/Maps/Core/Routing/MWMRouter.mm index 9571d0b6e4..bf8b9a32cd 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.mm +++ b/iphone/Maps/Core/Routing/MWMRouter.mm @@ -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]; } diff --git a/iphone/Maps/Core/Search/MWMSearch.mm b/iphone/Maps/Core/Search/MWMSearch.mm index 0893d5e0ff..1a08fccd21 100644 --- a/iphone/Maps/Core/Search/MWMSearch.mm +++ b/iphone/Maps/Core/Search/MWMSearch.mm @@ -1,6 +1,7 @@ #import "MWMSearch.h" #import "MWMBannerHelpers.h" #import "MWMFrameworkListener.h" +#import "MWMFrameworkObservers.h" #import "SwiftBridge.h" #include diff --git a/iphone/Maps/Core/Storage/MWMStorage.h b/iphone/Maps/Core/Storage/MWMStorage.h index fffc2f908d..05490a1578 100644 --- a/iphone/Maps/Core/Storage/MWMStorage.h +++ b/iphone/Maps/Core/Storage/MWMStorage.h @@ -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 *)countryIds + onSuccess:(nullable MWMVoidBlock)onSuccess + onCancel:(nullable MWMVoidBlock)onCancel; + ++ (BOOL)haveDownloadedCountries; ++ (BOOL)downloadInProgress; + +#pragma mark - Attributes + ++ (NSArray *)allCountries; ++ (NSArray *)allCountriesWithParent:(NSString *)countryId; ++ (NSArray *)availableCountriesWithParent:(NSString *)countryId; ++ (NSArray *)downloadedCountries; ++ (NSArray *)downloadedCountriesWithParent:(NSString *)countryId; ++ (MWMMapNodeAttributes *)attributesForCountry:(NSString *)countryId; ++ (MWMMapNodeAttributes *)attributesForRoot; ++ (NSString *)nameForCountry:(NSString *)countryId; ++ (nullable NSArray *)nearbyAvailableCountries:(CLLocationCoordinate2D)location; ++ (MWMMapUpdateInfo *)updateInfoWithParent:(nullable NSString *)countryId; @end + +NS_ASSUME_NONNULL_END diff --git a/iphone/Maps/Core/Storage/MWMStorage.mm b/iphone/Maps/Core/Storage/MWMStorage.mm index 1db0d35fba..3e0e8b2695 100644 --- a/iphone/Maps/Core/Storage/MWMStorage.mm +++ b/iphone/Maps/Core/Storage/MWMStorage.mm @@ -1,8 +1,9 @@ #import "MWMStorage.h" #import "MWMAlertViewController.h" -#import "MWMRouter.h" #include +#import +#import #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 *)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 *)allCountries { + NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str()); + return [self allCountriesWithParent:rootId]; +} + ++ (NSArray *)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 *)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 *)downloadedCountries { + NSString *rootId = @(GetFramework().GetStorage().GetRootId().c_str()); + return [self downloadedCountriesWithParent:rootId]; +} + ++ (NSArray *)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 *)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 diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 6ba2edb978..b1162a344a 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -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 = ""; }; 4719A646219CBD7F009F9AA7 /* IBillingPendingTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBillingPendingTransaction.swift; sourceTree = ""; }; 4719A64D21A30C3B009F9AA7 /* PaidRouteStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaidRouteStatistics.swift; sourceTree = ""; }; + 471AB98823AA8A3500F56D49 /* IDownloaderDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IDownloaderDataSource.swift; sourceTree = ""; }; + 471AB99323ABA3BD00F56D49 /* SearchMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchMapsDataSource.swift; sourceTree = ""; }; 471BBD932130390F00EB17C9 /* TutorialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TutorialViewController.swift; sourceTree = ""; }; 471C448A2322A7C800C307EC /* SubscriptionGoToCatalogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionGoToCatalogViewController.swift; sourceTree = ""; }; 471C448B2322A7C800C307EC /* SubscriptionGoToCatalogViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SubscriptionGoToCatalogViewController.xib; sourceTree = ""; }; @@ -1464,6 +1462,9 @@ 472E3F4B2147D5700020E412 /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = ""; }; 473464A5218B0BC000D6AF5B /* MWMPurchaseValidation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMPurchaseValidation.h; sourceTree = ""; }; 473464A6218B0BC000D6AF5B /* MWMPurchaseValidation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPurchaseValidation.mm; sourceTree = ""; }; + 4735008923A83CF700661A95 /* DownloadedMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedMapsDataSource.swift; sourceTree = ""; }; + 473500C023A8F81800661A95 /* MWMFrameworkObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkObserver.h; sourceTree = ""; }; + 473500C123A8F85A00661A95 /* MWMFrameworkStorageObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkStorageObserver.h; sourceTree = ""; }; 473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSelectableProgressCell.swift; sourceTree = ""; }; 474902D8224A54EC008D71E0 /* MWMRoutingOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMRoutingOptions.h; sourceTree = ""; }; 474902D9224A54EC008D71E0 /* MWMRoutingOptions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMRoutingOptions.mm; sourceTree = ""; }; @@ -1545,6 +1546,8 @@ 47E6CB092178BA3600EA102B /* SearchBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBannerCell.swift; sourceTree = ""; }; 47E6CB0A2178BA3600EA102B /* SearchBannerCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchBannerCell.xib; sourceTree = ""; }; 47EF05B221504D8F00EAC269 /* RemoveAdsPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsPresentationController.swift; sourceTree = ""; }; + 47F4F21223A6EC420022FD56 /* DownloadMapsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadMapsViewController.swift; sourceTree = ""; }; + 47F4F21423A6F06F0022FD56 /* AvailableMapsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableMapsDataSource.swift; sourceTree = ""; }; 47F67D0F21CA8F800069754E /* IMWMWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMWMWebImage.h; sourceTree = ""; }; 47F67D1321CAB21B0069754E /* MWMImageCoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMImageCoder.h; sourceTree = ""; }; 47F67D1421CAB21B0069754E /* MWMImageCoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMImageCoder.m; sourceTree = ""; }; @@ -1894,43 +1897,24 @@ F6D67CE8206929590032FD38 /* PPPSearchSimilarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPPSearchSimilarButton.swift; sourceTree = ""; }; F6D67CEA2069318B0032FD38 /* PPPSearchSimilarButton.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PPPSearchSimilarButton.xib; sourceTree = ""; }; F6DF5F321CD1136800A87154 /* LocaleTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocaleTranslator.h; sourceTree = ""; }; - F6E2FBFE1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderAdsTableViewCell.h; sourceTree = ""; }; - F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderAdsTableViewCell.m; sourceTree = ""; }; - F6E2FC001E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderAdsTableViewCell.xib; sourceTree = ""; }; F6E2FC011E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderButtonTableViewCell.h; sourceTree = ""; }; F6E2FC021E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderButtonTableViewCell.m; sourceTree = ""; }; F6E2FC031E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderButtonTableViewCell.xib; sourceTree = ""; }; F6E2FC041E097B9F0083EBEC /* MWMMapDownloaderCellHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderCellHeader.h; sourceTree = ""; }; F6E2FC051E097B9F0083EBEC /* MWMMapDownloaderCellHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderCellHeader.m; sourceTree = ""; }; F6E2FC061E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderLargeCountryTableViewCell.h; sourceTree = ""; }; - F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderLargeCountryTableViewCell.mm; sourceTree = ""; }; + F6E2FC071E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderLargeCountryTableViewCell.m; sourceTree = ""; }; F6E2FC081E097B9F0083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderLargeCountryTableViewCell.xib; sourceTree = ""; }; F6E2FC091E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderPlaceTableViewCell.h; sourceTree = ""; }; F6E2FC0A1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderPlaceTableViewCell.mm; sourceTree = ""; }; F6E2FC0B1E097B9F0083EBEC /* MWMMapDownloaderPlaceTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderPlaceTableViewCell.xib; sourceTree = ""; }; F6E2FC0C1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderSubplaceTableViewCell.h; sourceTree = ""; }; - F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderSubplaceTableViewCell.mm; sourceTree = ""; }; + F6E2FC0D1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMMapDownloaderSubplaceTableViewCell.m; sourceTree = ""; }; F6E2FC0E1E097B9F0083EBEC /* MWMMapDownloaderSubplaceTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderSubplaceTableViewCell.xib; sourceTree = ""; }; F6E2FC0F1E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderTableViewCell.h; sourceTree = ""; }; F6E2FC101E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderTableViewCell.mm; sourceTree = ""; }; F6E2FC111E097B9F0083EBEC /* MWMMapDownloaderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloaderTableViewCell.xib; sourceTree = ""; }; - F6E2FC121E097B9F0083EBEC /* MWMMapDownloaderTableViewCellProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderTableViewCellProtocol.h; sourceTree = ""; }; - F6E2FC141E097B9F0083EBEC /* MWMMapDownloaderDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderDataSource.h; sourceTree = ""; }; - F6E2FC151E097B9F0083EBEC /* MWMMapDownloaderDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMMapDownloaderDataSource.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - F6E2FC161E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderDefaultDataSource.h; sourceTree = ""; }; - F6E2FC171E097B9F0083EBEC /* MWMMapDownloaderDefaultDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMMapDownloaderDefaultDataSource.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - F6E2FC181E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderExtendedDataSource.h; sourceTree = ""; }; - F6E2FC191E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderExtendedDataSource.mm; sourceTree = ""; }; - F6E2FC1A1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderExtendedDataSourceWithAds.h; sourceTree = ""; }; - F6E2FC1B1E097B9F0083EBEC /* MWMMapDownloaderExtendedDataSourceWithAds.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderExtendedDataSourceWithAds.mm; sourceTree = ""; }; - F6E2FC1C1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderSearchDataSource.h; sourceTree = ""; }; - F6E2FC1D1E097B9F0083EBEC /* MWMMapDownloaderSearchDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderSearchDataSource.mm; sourceTree = ""; }; - F6E2FC1E1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMBaseMapDownloaderViewController.h; sourceTree = ""; }; - F6E2FC1F1E097B9F0083EBEC /* MWMBaseMapDownloaderViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMBaseMapDownloaderViewController.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - F6E2FC201E097B9F0083EBEC /* MWMMapDownloaderProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderProtocol.h; sourceTree = ""; }; F6E2FC211E097B9F0083EBEC /* MWMMapDownloaderMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderMode.h; sourceTree = ""; }; - F6E2FC221E097B9F0083EBEC /* MWMMapDownloaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderViewController.h; sourceTree = ""; }; - F6E2FC231E097B9F0083EBEC /* MWMMapDownloaderViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderViewController.mm; sourceTree = ""; }; F6E2FC251E097B9F0083EBEC /* MWMNoMapsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMNoMapsView.h; sourceTree = ""; }; F6E2FC261E097B9F0083EBEC /* MWMNoMapsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMNoMapsView.m; sourceTree = ""; }; F6E2FC271E097B9F0083EBEC /* MWMNoMapsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMNoMapsViewController.h; sourceTree = ""; }; @@ -3055,6 +3039,8 @@ 3486B5121E27AD3B0069C126 /* MWMFrameworkListener.h */, 3486B5131E27AD3B0069C126 /* MWMFrameworkListener.mm */, 3486B5141E27AD3B0069C126 /* MWMFrameworkObservers.h */, + 473500C023A8F81800661A95 /* MWMFrameworkObserver.h */, + 473500C123A8F85A00661A95 /* MWMFrameworkStorageObserver.h */, ); path = Framework; sourceTree = ""; @@ -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 = ""; @@ -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 = ""; }; - 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 = ""; - }; 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 */, diff --git a/iphone/Maps/UI/Autoupdate/MWMAutoupdateController.mm b/iphone/Maps/UI/Autoupdate/MWMAutoupdateController.mm index 32f5772cf0..e7dd50f3b9 100644 --- a/iphone/Maps/UI/Autoupdate/MWMAutoupdateController.mm +++ b/iphone/Maps/UI/Autoupdate/MWMAutoupdateController.mm @@ -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(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 diff --git a/iphone/Maps/UI/Downloader/AvailableMapsDataSource.swift b/iphone/Maps/UI/Downloader/AvailableMapsDataSource.swift new file mode 100644 index 0000000000..6121803219 --- /dev/null +++ b/iphone/Maps/UI/Downloader/AvailableMapsDataSource.swift @@ -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() + } +} diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.h b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.h deleted file mode 100644 index 55e391cf58..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.h +++ /dev/null @@ -1,10 +0,0 @@ -#import -#import "MWMMapDownloaderTableViewCellProtocol.h" -#import "MWMTableViewCell.h" - -@interface MWMMapDownloaderAdsTableViewCell - : MWMTableViewCell - -@property(nonatomic) MTRGAppwallBannerAdView * adView; - -@end diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.m b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.m deleted file mode 100644 index c3c0654f59..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.m +++ /dev/null @@ -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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.xib b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.xib deleted file mode 100644 index 0011165459..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderAdsTableViewCell.xib +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.h b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.h index 94c3873a98..930b239558 100644 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.h +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.h @@ -1,4 +1,3 @@ -#import "MWMMapDownloaderTableViewCellProtocol.h" #import "MWMTableViewCell.h" @protocol MWMMapDownloaderButtonTableViewCellProtocol @@ -7,7 +6,7 @@ @end -@interface MWMMapDownloaderButtonTableViewCell : MWMTableViewCell +@interface MWMMapDownloaderButtonTableViewCell : MWMTableViewCell @property (weak, nonatomic) id delegate; diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.m b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.m index 417714e8d9..dc8f4ea124 100644 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.m +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderButtonTableViewCell.m @@ -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]; diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.m b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.m new file mode 100644 index 0000000000..6b38871398 --- /dev/null +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.m @@ -0,0 +1,22 @@ +#import "MWMMapDownloaderLargeCountryTableViewCell.h" + +#import + +@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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm deleted file mode 100644 index 6cc567e328..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm +++ /dev/null @@ -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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm index 6b90aa0902..abc86ee234 100644 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm @@ -1,6 +1,7 @@ #import "MWMMapDownloaderPlaceTableViewCell.h" #include +#import @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 = diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.m b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.m new file mode 100644 index 0000000000..17b46dfa93 --- /dev/null +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.m @@ -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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm deleted file mode 100644 index ebeacaed2d..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm +++ /dev/null @@ -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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.h b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.h index 76d52ab5a0..e8f3b5e834 100644 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.h +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.h @@ -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 +NS_ASSUME_NONNULL_BEGIN -@property(nonatomic) BOOL isHeightCell; -@property(weak, nonatomic) id delegate; -@property(nonatomic) MWMMapDownloaderMode mode; +@protocol MWMMapDownloaderTableViewCellDelegate -- (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 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 diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.mm b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.mm index 6fd1db651a..161a18e036 100644 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.mm +++ b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCell.mm @@ -5,43 +5,49 @@ #include #import +#import +#import -@interface MWMMapDownloaderTableViewCell () +@interface MWMMapDownloaderTableViewCell () -@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(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(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 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; } diff --git a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCellProtocol.h b/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCellProtocol.h deleted file mode 100644 index 0917bd8e15..0000000000 --- a/iphone/Maps/UI/Downloader/Cells/MWMMapDownloaderTableViewCellProtocol.h +++ /dev/null @@ -1,5 +0,0 @@ -@protocol MWMMapDownloaderTableViewCellProtocol - -+ (CGFloat)estimatedHeight; - -@end diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.h b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.h deleted file mode 100644 index 7661fea427..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.h +++ /dev/null @@ -1,25 +0,0 @@ -#import "MWMMapDownloaderButtonTableViewCell.h" -#import "MWMMapDownloaderMode.h" -#import "MWMMapDownloaderProtocol.h" -#import "MWMMapDownloaderTableViewCell.h" - -@interface MWMMapDownloaderDataSource : NSObject - -@property(nonatomic, readonly) BOOL isParentRoot; -@property(nonatomic, readonly) MWMMapDownloaderMode mode; -@property(weak, nonatomic, readonly) - id - delegate; - -- (instancetype) -initWithDelegate:(id)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 diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.mm b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.mm deleted file mode 100644 index 67212f61f1..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDataSource.mm +++ /dev/null @@ -1,111 +0,0 @@ -#import "MWMMapDownloaderDataSource.h" -#import "MWMMapDownloaderPlaceTableViewCell.h" -#import "MWMMapDownloaderSubplaceTableViewCell.h" -#import "SwiftBridge.h" - -using namespace storage; - -@implementation MWMMapDownloaderDataSource - -- (instancetype) -initWithDelegate:(id)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(cell); - placeCell.needDisplayArea = self.isParentRoot; - } - - if ([cell isKindOfClass:[MWMMapDownloaderSubplaceTableViewCell class]]) - { - MWMMapDownloaderSubplaceTableViewCell * subplaceCell = static_cast(cell); - [subplaceCell setSubplaceText:[self searchMatchedResultForCountryId:countryId]]; - } - - MWMMapDownloaderTableViewCell * tCell = static_cast(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( - [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 diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.h b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.h deleted file mode 100644 index ad761b34ad..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "MWMMapDownloaderDataSource.h" - -@interface MWMMapDownloaderDefaultDataSource : MWMMapDownloaderDataSource - -- (instancetype) -initForRootCountryId:(NSString *)countryId - delegate: - (id)delegate - mode:(MWMMapDownloaderMode)mode; -- (void)load; - -@end diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.mm b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.mm deleted file mode 100644 index aee2fd26e6..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderDefaultDataSource.mm +++ /dev/null @@ -1,229 +0,0 @@ -#import "MWMMapDownloaderDefaultDataSource.h" -#import "MWMMapDownloaderLargeCountryTableViewCell.h" -#import "MWMMapDownloaderPlaceTableViewCell.h" -#import "SwiftBridge.h" - -#include - -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 * indexes; -@property (copy, nonatomic) NSDictionary *> * availableCountries; -@property (copy, nonatomic) NSArray * downloadedCountries; - -@end - -@implementation MWMMapDownloaderDefaultDataSource -{ - CountryId m_parentId; -} - -@synthesize isParentRoot = _isParentRoot; - -- (instancetype) -initForRootCountryId:(NSString *)countryId - delegate: - (id)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 * indexSet = [NSMutableSet setWithCapacity:availableChildren.size()]; - NSMutableDictionary *> * 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 * letterIds = availableCountries[index]; - letterIds = letterIds ?: [@[] mutableCopy]; - [letterIds addObject:nsCountryId]; - availableCountries[index] = letterIds; - } - self.indexes = [[indexSet allObjects] sortedArrayUsingComparator:compareStrings]; - [availableCountries enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSMutableArray * obj, BOOL * stop) - { - [obj sortUsingComparator:compareLocalNames]; - }]; - self.availableCountries = availableCountries; -} - -- (void)configDownloadedSection:(CountriesVec const &)downloadedChildren -{ - NSMutableArray * 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( - [tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]); - cell.delegate = self.delegate; - return cell; - } - else - { - return [super tableView:tableView cellForRowAtIndexPath:indexPath]; - } -} - -- (NSArray *)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 * 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 diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.h b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.h deleted file mode 100644 index 7c02da1b82..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "MWMMapDownloaderDefaultDataSource.h" - -enum class MWMMapDownloaderDataSourceExtraSection -{ - NearMe, - Ads -}; - -@interface MWMMapDownloaderExtendedDataSource : MWMMapDownloaderDefaultDataSource - -@end diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.mm b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.mm deleted file mode 100644 index e6e16e3cab..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSource.mm +++ /dev/null @@ -1,129 +0,0 @@ -#import "MWMMapDownloaderExtendedDataSource.h" -#import "CLLocation+Mercator.h" -#import "MWMLocationManager.h" - -#include - -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 * nearmeCountries; - -@end - -@implementation MWMMapDownloaderExtendedDataSource -{ - std::vector 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 * 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 diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.h b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.h deleted file mode 100644 index efe0e544ca..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.h +++ /dev/null @@ -1,8 +0,0 @@ -#import -#import "MWMMapDownloaderExtendedDataSource.h" - -@interface MWMMapDownloaderExtendedDataSourceWithAds : MWMMapDownloaderExtendedDataSource - -- (MTRGAppwallBannerAdView *)viewForBannerAtIndex:(NSUInteger)index; - -@end diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.mm b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.mm deleted file mode 100644 index b75070b81a..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderExtendedDataSourceWithAds.mm +++ /dev/null @@ -1,114 +0,0 @@ -#import "MWMMapDownloaderExtendedDataSourceWithAds.h" -#import "MWMMapDownloaderAdsTableViewCell.h" -#import "MWMMyTarget.h" - -#include - -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(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 diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.h b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.h deleted file mode 100644 index 5f52bbe37a..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.h +++ /dev/null @@ -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)delegate; - -@end diff --git a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.mm b/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.mm deleted file mode 100644 index 2fbaba09c6..0000000000 --- a/iphone/Maps/UI/Downloader/DataSources/MWMMapDownloaderSearchDataSource.mm +++ /dev/null @@ -1,95 +0,0 @@ -#import "MWMMapDownloaderSearchDataSource.h" -#import "MWMMapDownloaderLargeCountryTableViewCell.h" -#import "MWMMapDownloaderPlaceTableViewCell.h" -#import "MWMMapDownloaderSubplaceTableViewCell.h" - -#include - -using namespace storage; - -@interface MWMMapDownloaderSearchDataSource () - -@property (copy, nonatomic) NSArray * searchCountryIds; -@property (copy, nonatomic) NSDictionary * searchMatchedResults; -@property (copy, nonatomic) NSString * searchQuery; - -@end - -@implementation MWMMapDownloaderSearchDataSource - -- (instancetype)initWithSearchResults:(DownloaderSearchResults const &)results delegate:(id)delegate -{ - self = [super initWithDelegate:delegate mode:MWMMapDownloaderModeAvailable]; - if (self) - { - NSMutableOrderedSet * nsSearchCountryIds = - [NSMutableOrderedSet orderedSetWithCapacity:results.m_results.size()]; - NSMutableDictionary * 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 diff --git a/iphone/Maps/UI/Downloader/DownloadMapsViewController.swift b/iphone/Maps/UI/Downloader/DownloadMapsViewController.swift new file mode 100644 index 0000000000..6027367781 --- /dev/null +++ b/iphone/Maps/UI/Downloader/DownloadMapsViewController.swift @@ -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 + } +} diff --git a/iphone/Maps/UI/Downloader/DownloadedMapsDataSource.swift b/iphone/Maps/UI/Downloader/DownloadedMapsDataSource.swift new file mode 100644 index 0000000000..1ea2f57e5c --- /dev/null +++ b/iphone/Maps/UI/Downloader/DownloadedMapsDataSource.swift @@ -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() + } +} diff --git a/iphone/Maps/UI/Downloader/IDownloaderDataSource.swift b/iphone/Maps/UI/Downloader/IDownloaderDataSource.swift new file mode 100644 index 0000000000..16627e2349 --- /dev/null +++ b/iphone/Maps/UI/Downloader/IDownloaderDataSource.swift @@ -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() +} diff --git a/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.h b/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.h deleted file mode 100644 index a42f930213..0000000000 --- a/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "MWMMapDownloaderButtonTableViewCell.h" -#import "MWMMapDownloaderMode.h" -#import "MWMMapDownloaderProtocol.h" -#import "MWMViewController.h" - -@interface MWMBaseMapDownloaderViewController : MWMViewController - -- (void)configTable; -- (void)configAllMapsView; - -- (void)setParentCountryId:(NSString *)parentId mode:(MWMMapDownloaderMode)mode; - -@end diff --git a/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.mm b/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.mm deleted file mode 100644 index 92203c0584..0000000000 --- a/iphone/Maps/UI/Downloader/MWMBaseMapDownloaderViewController.mm +++ /dev/null @@ -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 - -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 () - -@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 * 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(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>(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>(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(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 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 diff --git a/iphone/Maps/UI/Downloader/MWMMapDownloaderProtocol.h b/iphone/Maps/UI/Downloader/MWMMapDownloaderProtocol.h deleted file mode 100644 index a8857ef907..0000000000 --- a/iphone/Maps/UI/Downloader/MWMMapDownloaderProtocol.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "storage/storage_defines.hpp" - -@protocol MWMMapDownloaderProtocol - -- (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 diff --git a/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.h b/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.h deleted file mode 100644 index 5aa8ec53e8..0000000000 --- a/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "MWMBaseMapDownloaderViewController.h" - -@interface MWMMapDownloaderViewController : MWMBaseMapDownloaderViewController - -@end diff --git a/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.mm b/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.mm deleted file mode 100644 index b23d2b8965..0000000000 --- a/iphone/Maps/UI/Downloader/MWMMapDownloaderViewController.mm +++ /dev/null @@ -1,209 +0,0 @@ -#import "MWMMapDownloaderViewController.h" -#import "MWMMapDownloaderExtendedDataSourceWithAds.h" -#import "MWMMapDownloaderSearchDataSource.h" -#import "SwiftBridge.h" - -#include - -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 () - -@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)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 diff --git a/iphone/Maps/UI/Downloader/SearchMapsDataSource.swift b/iphone/Maps/UI/Downloader/SearchMapsDataSource.swift new file mode 100644 index 0000000000..961277ecc8 --- /dev/null +++ b/iphone/Maps/UI/Downloader/SearchMapsDataSource.swift @@ -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 = [] + } +} diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm b/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm index ddd3a76cc9..6e67e1094a 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm @@ -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(progress.first) / progress.second]; + progress:static_cast(downloadedBytes) / totalBytes]; } #pragma mark - MWMPlacePageLayoutDelegate diff --git a/iphone/Maps/UI/Search/MWMSearchManager.mm b/iphone/Maps/UI/Search/MWMSearchManager.mm index e84243152b..41787117e3 100644 --- a/iphone/Maps/UI/Search/MWMSearchManager.mm +++ b/iphone/Maps/UI/Search/MWMSearchManager.mm @@ -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; #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]; diff --git a/iphone/Maps/UI/Storyboard/Main.storyboard b/iphone/Maps/UI/Storyboard/Main.storyboard index c280f3cd45..85800be205 100644 --- a/iphone/Maps/UI/Storyboard/Main.storyboard +++ b/iphone/Maps/UI/Storyboard/Main.storyboard @@ -1,11 +1,9 @@ - - - - + + - + @@ -19,7 +17,7 @@ - + @@ -528,7 +526,7 @@ - +