forked from organicmaps/organicmaps
[iOS][Cross-Traffic] Guides on the discovery screen
This commit is contained in:
parent
48e472dd71
commit
7889a2a982
43 changed files with 1419 additions and 952 deletions
|
@ -213,6 +213,7 @@ static NSString * const kStatMapSearch = @"Map search";
|
|||
static NSString * const kStatMapViewStyle = @"Map view style";
|
||||
static NSString * const kStatMapViewStyleSettings = @"Map view style settings";
|
||||
static NSString * const kStatMapsme = @"maps.me";
|
||||
static NSString * const kStatMapsmeGuides = @"MapsMeGuides";
|
||||
static NSString * const kStatMaxim = @"Maxim";
|
||||
static NSString * const kStatMenu = @"menu";
|
||||
static NSString * const kStatMigrationBig2SmallMWM = @"Big mwms to small mwms migration counter";
|
||||
|
|
12
iphone/Maps/Images.xcassets/Discovery/img_guide_placeholder.imageset/Contents.json
vendored
Normal file
12
iphone/Maps/Images.xcassets/Discovery/img_guide_placeholder.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Illustration.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
iphone/Maps/Images.xcassets/Discovery/img_guide_placeholder.imageset/Illustration.pdf
vendored
Normal file
BIN
iphone/Maps/Images.xcassets/Discovery/img_guide_placeholder.imageset/Illustration.pdf
vendored
Normal file
Binary file not shown.
|
@ -568,10 +568,18 @@
|
|||
BB8123CF212C264700ADE512 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB8123CD212C264700ADE512 /* Metal.framework */; };
|
||||
BB8123D0212C264700ADE512 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB8123CE212C264700ADE512 /* MetalKit.framework */; };
|
||||
BB8123D62130427E00ADE512 /* MetalContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = BB8123D52130427E00ADE512 /* MetalContextFactory.mm */; };
|
||||
CD96C70C22A681C400DB7CFE /* DiscoveryGuideCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD96C70A22A681C400DB7CFE /* DiscoveryGuideCell.swift */; };
|
||||
CD96C70D22A681C400DB7CFE /* DiscoveryGuideCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD96C70B22A681C400DB7CFE /* DiscoveryGuideCell.xib */; };
|
||||
CD96C71122A6820800DB7CFE /* DiscoveryGuideCollectionHolderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD96C70F22A6820800DB7CFE /* DiscoveryGuideCollectionHolderCell.xib */; };
|
||||
CD96C71422A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = CD96C71322A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.m */; };
|
||||
CD96C71722A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD96C71622A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.mm */; };
|
||||
CD96C71C22A8113100DB7CFE /* MWMDiscoveryControllerViewModel.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDB92CEA229E9ADF00EC757C /* MWMDiscoveryControllerViewModel.mm */; };
|
||||
CDB92CEE229E9CF900EC757C /* MWMDiscoveryMapObjects.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDB92CED229E9CF900EC757C /* MWMDiscoveryMapObjects.mm */; };
|
||||
CDB92CF1229EB8A800EC757C /* MWMDiscoverySearchViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB92CF0229EB8A800EC757C /* MWMDiscoverySearchViewModel.m */; };
|
||||
CDB92CF822A5350500EC757C /* MWMDiscoveryHotelViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = CDB92CF722A5350500EC757C /* MWMDiscoveryHotelViewModel.m */; };
|
||||
F5BD255A0838E70EC012748E /* DiscoverySearchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5BD2ED6E94925472A9901B4 /* DiscoverySearchCell.swift */; };
|
||||
F5BD29FF26AD58255766C51A /* DiscoverySpinnerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5BD246A7E6BE8CD8600EDD9 /* DiscoverySpinnerCell.swift */; };
|
||||
F5BD2CA4DBEFACBC48195F39 /* DiscoveryCollectionHolderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5BD2A86D9DA2F9769D30B54 /* DiscoveryCollectionHolderCell.swift */; };
|
||||
F603E05A1FDE9410006B84D6 /* DiscoveryLocalExpertCollectionHolderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F603E0581FDE9410006B84D6 /* DiscoveryLocalExpertCollectionHolderCell.xib */; };
|
||||
F603E05E1FDE9703006B84D6 /* DiscoverySearchCollectionHolderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F603E05C1FDE9703006B84D6 /* DiscoverySearchCollectionHolderCell.xib */; };
|
||||
F607C1881C032A8800B53A87 /* resources-hdpi_clear in Resources */ = {isa = PBXBuildFile; fileRef = F607C1831C032A8800B53A87 /* resources-hdpi_clear */; };
|
||||
F607C18A1C032A8800B53A87 /* resources-hdpi_dark in Resources */ = {isa = PBXBuildFile; fileRef = F607C1841C032A8800B53A87 /* resources-hdpi_dark */; };
|
||||
|
@ -614,8 +622,6 @@
|
|||
F69018BD1E9F7CB600B3C10B /* MWMAutoupdateController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F69018BB1E9F7CB600B3C10B /* MWMAutoupdateController.xib */; };
|
||||
F692F3831EA0FAF5001E82EB /* MWMAutoupdateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F69018B71E9E601400B3C10B /* MWMAutoupdateController.mm */; };
|
||||
F69739B21FD197DB00FDA07D /* MWMDiscoveryTableManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = F69739B01FD197DB00FDA07D /* MWMDiscoveryTableManager.mm */; };
|
||||
F69739DC1FD6ECCE00FDA07D /* DiscoveryLocalExpertCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F69739DA1FD6ECCE00FDA07D /* DiscoveryLocalExpertCell.swift */; };
|
||||
F69739E01FD6EE1D00FDA07D /* DiscoveryLocalExpertCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F69739DE1FD6EE1D00FDA07D /* DiscoveryLocalExpertCell.xib */; };
|
||||
F69CE8D61E5C49B4002B5881 /* PPHotelCarouselCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F69CE8D41E5C49B4002B5881 /* PPHotelCarouselCell.swift */; };
|
||||
F69CE8DA1E5C5088002B5881 /* PPHotelCarouselCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F69CE8D81E5C5088002B5881 /* PPHotelCarouselCell.xib */; };
|
||||
F69CE8DE1E5C51AB002B5881 /* CarouselElement.xib in Resources */ = {isa = PBXBuildFile; fileRef = F69CE8DC1E5C51AB002B5881 /* CarouselElement.xib */; };
|
||||
|
@ -1598,6 +1604,21 @@
|
|||
BB8123CE212C264700ADE512 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
|
||||
BB8123D42130427E00ADE512 /* MetalContextFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalContextFactory.h; sourceTree = "<group>"; };
|
||||
BB8123D52130427E00ADE512 /* MetalContextFactory.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MetalContextFactory.mm; sourceTree = "<group>"; };
|
||||
CD96C70A22A681C400DB7CFE /* DiscoveryGuideCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryGuideCell.swift; sourceTree = "<group>"; };
|
||||
CD96C70B22A681C400DB7CFE /* DiscoveryGuideCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoveryGuideCell.xib; sourceTree = "<group>"; };
|
||||
CD96C70F22A6820800DB7CFE /* DiscoveryGuideCollectionHolderCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoveryGuideCollectionHolderCell.xib; sourceTree = "<group>"; };
|
||||
CD96C71222A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryGuideViewModel.h; sourceTree = "<group>"; };
|
||||
CD96C71322A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMDiscoveryGuideViewModel.m; sourceTree = "<group>"; };
|
||||
CD96C71522A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryCityGalleryObjects.h; sourceTree = "<group>"; };
|
||||
CD96C71622A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMDiscoveryCityGalleryObjects.mm; sourceTree = "<group>"; };
|
||||
CDB92CE9229E9ADF00EC757C /* MWMDiscoveryControllerViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryControllerViewModel.h; sourceTree = "<group>"; };
|
||||
CDB92CEA229E9ADF00EC757C /* MWMDiscoveryControllerViewModel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMDiscoveryControllerViewModel.mm; sourceTree = "<group>"; };
|
||||
CDB92CEC229E9CF900EC757C /* MWMDiscoveryMapObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryMapObjects.h; sourceTree = "<group>"; };
|
||||
CDB92CED229E9CF900EC757C /* MWMDiscoveryMapObjects.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMDiscoveryMapObjects.mm; sourceTree = "<group>"; };
|
||||
CDB92CEF229EB8A700EC757C /* MWMDiscoverySearchViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoverySearchViewModel.h; sourceTree = "<group>"; };
|
||||
CDB92CF0229EB8A800EC757C /* MWMDiscoverySearchViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMDiscoverySearchViewModel.m; sourceTree = "<group>"; };
|
||||
CDB92CF622A5350500EC757C /* MWMDiscoveryHotelViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryHotelViewModel.h; sourceTree = "<group>"; };
|
||||
CDB92CF722A5350500EC757C /* MWMDiscoveryHotelViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MWMDiscoveryHotelViewModel.m; sourceTree = "<group>"; };
|
||||
ED48BBB317C267F5003E7E92 /* ColorPickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorPickerView.h; sourceTree = "<group>"; };
|
||||
ED48BBB417C267F5003E7E92 /* ColorPickerView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ColorPickerView.mm; sourceTree = "<group>"; };
|
||||
ED48BBB817C2B1E2003E7E92 /* CircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleView.h; sourceTree = "<group>"; };
|
||||
|
@ -1615,7 +1636,6 @@
|
|||
F5BD246A7E6BE8CD8600EDD9 /* DiscoverySpinnerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverySpinnerCell.swift; sourceTree = "<group>"; };
|
||||
F5BD2A86D9DA2F9769D30B54 /* DiscoveryCollectionHolderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoveryCollectionHolderCell.swift; sourceTree = "<group>"; };
|
||||
F5BD2ED6E94925472A9901B4 /* DiscoverySearchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverySearchCell.swift; sourceTree = "<group>"; };
|
||||
F603E0581FDE9410006B84D6 /* DiscoveryLocalExpertCollectionHolderCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoveryLocalExpertCollectionHolderCell.xib; sourceTree = "<group>"; };
|
||||
F603E05C1FDE9703006B84D6 /* DiscoverySearchCollectionHolderCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoverySearchCollectionHolderCell.xib; sourceTree = "<group>"; };
|
||||
F607C1831C032A8800B53A87 /* resources-hdpi_clear */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-hdpi_clear"; path = "../../data/resources-hdpi_clear"; sourceTree = "<group>"; };
|
||||
F607C1841C032A8800B53A87 /* resources-hdpi_dark */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-hdpi_dark"; path = "../../data/resources-hdpi_dark"; sourceTree = "<group>"; };
|
||||
|
@ -1695,10 +1715,7 @@
|
|||
F69018BB1E9F7CB600B3C10B /* MWMAutoupdateController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMAutoupdateController.xib; sourceTree = "<group>"; };
|
||||
F69739AF1FD197DB00FDA07D /* MWMDiscoveryTableManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryTableManager.h; sourceTree = "<group>"; };
|
||||
F69739B01FD197DB00FDA07D /* MWMDiscoveryTableManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMDiscoveryTableManager.mm; sourceTree = "<group>"; };
|
||||
F69739B41FD198E300FDA07D /* DiscoveryControllerViewModel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DiscoveryControllerViewModel.hpp; sourceTree = "<group>"; };
|
||||
F69739B51FD19D9900FDA07D /* MWMDiscoveryTapDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMDiscoveryTapDelegate.h; sourceTree = "<group>"; };
|
||||
F69739DA1FD6ECCE00FDA07D /* DiscoveryLocalExpertCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryLocalExpertCell.swift; sourceTree = "<group>"; };
|
||||
F69739DE1FD6EE1D00FDA07D /* DiscoveryLocalExpertCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoveryLocalExpertCell.xib; sourceTree = "<group>"; };
|
||||
F69CE8D41E5C49B4002B5881 /* PPHotelCarouselCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PPHotelCarouselCell.swift; sourceTree = "<group>"; };
|
||||
F69CE8D81E5C5088002B5881 /* PPHotelCarouselCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PPHotelCarouselCell.xib; sourceTree = "<group>"; };
|
||||
F69CE8DC1E5C51AB002B5881 /* CarouselElement.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CarouselElement.xib; sourceTree = "<group>"; };
|
||||
|
@ -3512,6 +3529,61 @@
|
|||
path = Catalog;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD96C71822A80C8400DB7CFE /* Collection Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD96C70A22A681C400DB7CFE /* DiscoveryGuideCell.swift */,
|
||||
CD96C70B22A681C400DB7CFE /* DiscoveryGuideCell.xib */,
|
||||
34B6FD5D2015E6BE00C18E97 /* DiscoveryBookingCell.swift */,
|
||||
34B6FD5E2015E6BF00C18E97 /* DiscoveryBookingCell.xib */,
|
||||
F5BD2ED6E94925472A9901B4 /* DiscoverySearchCell.swift */,
|
||||
F60C8BED1FCED15900DCF5FB /* DiscoverySearchCell.xib */,
|
||||
F655C026207278300048A241 /* DiscoveryMoreCell.swift */,
|
||||
F655C02820727A630048A241 /* DiscoveryMoreCell.xib */,
|
||||
);
|
||||
path = "Collection Cells";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD96C71922A80CCF00DB7CFE /* Table Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD96C71A22A80D1600DB7CFE /* Holders */,
|
||||
F6EBB26D1FD7E33300B69B6A /* DiscoveryNoResultsCell.swift */,
|
||||
F6EBB2711FD7E4FD00B69B6A /* DiscoveryNoResultsCell.xib */,
|
||||
F61757EB1FC73027000AD0D0 /* DiscoveryOnlineTemplateCell.swift */,
|
||||
F61757EF1FC731F5000AD0D0 /* DiscoveryOnlineTemplateCell.xib */,
|
||||
F5BD246A7E6BE8CD8600EDD9 /* DiscoverySpinnerCell.swift */,
|
||||
F61757E71FC72CDE000AD0D0 /* DiscoverySpinnerCell.xib */,
|
||||
);
|
||||
path = "Table Cells";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD96C71A22A80D1600DB7CFE /* Holders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD96C70F22A6820800DB7CFE /* DiscoveryGuideCollectionHolderCell.xib */,
|
||||
34B6FD612015F71900C18E97 /* DiscoveryBookingCollectionHolderCell.xib */,
|
||||
F603E05C1FDE9703006B84D6 /* DiscoverySearchCollectionHolderCell.xib */,
|
||||
F5BD2A86D9DA2F9769D30B54 /* DiscoveryCollectionHolderCell.swift */,
|
||||
);
|
||||
path = Holders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD96C71B22A80D3E00DB7CFE /* View Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CDB92CE9229E9ADF00EC757C /* MWMDiscoveryControllerViewModel.h */,
|
||||
CDB92CEA229E9ADF00EC757C /* MWMDiscoveryControllerViewModel.mm */,
|
||||
CDB92CEF229EB8A700EC757C /* MWMDiscoverySearchViewModel.h */,
|
||||
CDB92CF0229EB8A800EC757C /* MWMDiscoverySearchViewModel.m */,
|
||||
CDB92CF622A5350500EC757C /* MWMDiscoveryHotelViewModel.h */,
|
||||
CDB92CF722A5350500EC757C /* MWMDiscoveryHotelViewModel.m */,
|
||||
CD96C71222A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.h */,
|
||||
CD96C71322A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.m */,
|
||||
);
|
||||
path = "View Models";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F607C18B1C047FCA00B53A87 /* Segue */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -4310,31 +4382,19 @@
|
|||
F6E407CC1FC45ED4001F7821 /* Discovery */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34B6FD5D2015E6BE00C18E97 /* DiscoveryBookingCell.swift */,
|
||||
34B6FD5E2015E6BF00C18E97 /* DiscoveryBookingCell.xib */,
|
||||
34B6FD612015F71900C18E97 /* DiscoveryBookingCollectionHolderCell.xib */,
|
||||
F5BD2A86D9DA2F9769D30B54 /* DiscoveryCollectionHolderCell.swift */,
|
||||
F69739B41FD198E300FDA07D /* DiscoveryControllerViewModel.hpp */,
|
||||
F69739DA1FD6ECCE00FDA07D /* DiscoveryLocalExpertCell.swift */,
|
||||
F69739DE1FD6EE1D00FDA07D /* DiscoveryLocalExpertCell.xib */,
|
||||
F603E0581FDE9410006B84D6 /* DiscoveryLocalExpertCollectionHolderCell.xib */,
|
||||
F6EBB26D1FD7E33300B69B6A /* DiscoveryNoResultsCell.swift */,
|
||||
F6EBB2711FD7E4FD00B69B6A /* DiscoveryNoResultsCell.xib */,
|
||||
F61757EB1FC73027000AD0D0 /* DiscoveryOnlineTemplateCell.swift */,
|
||||
F61757EF1FC731F5000AD0D0 /* DiscoveryOnlineTemplateCell.xib */,
|
||||
F5BD2ED6E94925472A9901B4 /* DiscoverySearchCell.swift */,
|
||||
F60C8BED1FCED15900DCF5FB /* DiscoverySearchCell.xib */,
|
||||
F603E05C1FDE9703006B84D6 /* DiscoverySearchCollectionHolderCell.xib */,
|
||||
F5BD246A7E6BE8CD8600EDD9 /* DiscoverySpinnerCell.swift */,
|
||||
F61757E71FC72CDE000AD0D0 /* DiscoverySpinnerCell.xib */,
|
||||
CD96C71B22A80D3E00DB7CFE /* View Models */,
|
||||
CD96C71922A80CCF00DB7CFE /* Table Cells */,
|
||||
CD96C71822A80C8400DB7CFE /* Collection Cells */,
|
||||
F6E407CD1FC45EF5001F7821 /* MWMDiscoveryController.h */,
|
||||
F6E407CE1FC45EF5001F7821 /* MWMDiscoveryController.mm */,
|
||||
F6E407D21FC4722F001F7821 /* MWMDiscoveryController.xib */,
|
||||
F69739AF1FD197DB00FDA07D /* MWMDiscoveryTableManager.h */,
|
||||
F69739B01FD197DB00FDA07D /* MWMDiscoveryTableManager.mm */,
|
||||
F69739B51FD19D9900FDA07D /* MWMDiscoveryTapDelegate.h */,
|
||||
F655C026207278300048A241 /* DiscoveryMoreCell.swift */,
|
||||
F655C02820727A630048A241 /* DiscoveryMoreCell.xib */,
|
||||
CDB92CEC229E9CF900EC757C /* MWMDiscoveryMapObjects.h */,
|
||||
CDB92CED229E9CF900EC757C /* MWMDiscoveryMapObjects.mm */,
|
||||
CD96C71522A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.h */,
|
||||
CD96C71622A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.mm */,
|
||||
);
|
||||
path = Discovery;
|
||||
sourceTree = "<group>";
|
||||
|
@ -4623,6 +4683,7 @@
|
|||
349D1AE11E2E325C004A2006 /* MWMBottomMenuViewController.xib in Resources */,
|
||||
34D3B01E1E389D05004100F9 /* MWMButtonCell.xib in Resources */,
|
||||
6741A98B1BF340DE002C974C /* MWMCircularProgress.xib in Resources */,
|
||||
CD96C71122A6820800DB7CFE /* DiscoveryGuideCollectionHolderCell.xib in Resources */,
|
||||
6741A94F1BF340DE002C974C /* MWMDefaultAlert.xib in Resources */,
|
||||
F6E2FE461E097BA00083EBEC /* MWMDirectionView.xib in Resources */,
|
||||
6741A9951BF340DE002C974C /* MWMDownloaderDialogCell.xib in Resources */,
|
||||
|
@ -4669,7 +4730,7 @@
|
|||
34B6FD602015E6BF00C18E97 /* DiscoveryBookingCell.xib in Resources */,
|
||||
4788739020EE30B300F6826B /* LayersViewController.xib in Resources */,
|
||||
F6E2FDF51E097BA00083EBEC /* MWMOpeningHoursAddScheduleTableViewCell.xib in Resources */,
|
||||
F603E05A1FDE9410006B84D6 /* DiscoveryLocalExpertCollectionHolderCell.xib in Resources */,
|
||||
CD96C70D22A681C400DB7CFE /* DiscoveryGuideCell.xib in Resources */,
|
||||
F6E2FDFB1E097BA00083EBEC /* MWMOpeningHoursAllDayTableViewCell.xib in Resources */,
|
||||
342639361EA0E60A0025EB89 /* local_ads_symbols.txt in Resources */,
|
||||
4554B6EC1E55F0EF0084017F /* drules_proto_vehicle_clear.bin in Resources */,
|
||||
|
@ -4748,7 +4809,6 @@
|
|||
F69CE8DA1E5C5088002B5881 /* PPHotelCarouselCell.xib in Resources */,
|
||||
F69CE8DE1E5C51AB002B5881 /* CarouselElement.xib in Resources */,
|
||||
6741A97F1BF340DE002C974C /* resources-mdpi_clear in Resources */,
|
||||
F69739E01FD6EE1D00FDA07D /* DiscoveryLocalExpertCell.xib in Resources */,
|
||||
6741A9901BF340DE002C974C /* resources-mdpi_dark in Resources */,
|
||||
6741A9981BF340DE002C974C /* resources-xhdpi_clear in Resources */,
|
||||
6741A9611BF340DE002C974C /* resources-xhdpi_dark in Resources */,
|
||||
|
@ -4894,6 +4954,7 @@
|
|||
34AB665F1FC5AA330078E451 /* TransportTransitIntermediatePoint.swift in Sources */,
|
||||
34B846A82029E8110081ECCD /* BMCDefaultViewModel.swift in Sources */,
|
||||
470F5A7F2189C30800754295 /* InAppPurchase.swift in Sources */,
|
||||
CD96C71422A6CBFD00DB7CFE /* MWMDiscoveryGuideViewModel.m in Sources */,
|
||||
348A8DF51F66775A00D83026 /* RatingView.swift in Sources */,
|
||||
F63AF50F1EA6215100A1DB98 /* FilterPriceCategoryCell.swift in Sources */,
|
||||
34D3AFF61E37A36A004100F9 /* UICollectionView+Cells.swift in Sources */,
|
||||
|
@ -4930,6 +4991,7 @@
|
|||
34F4073E1E9E1AFF00E57AC0 /* MPNativeAd+MWM.mm in Sources */,
|
||||
F6E2FED01E097BA00083EBEC /* MWMSearchFilterViewController.mm in Sources */,
|
||||
34D4FA671E265749003F53EF /* WhatsNewController.swift in Sources */,
|
||||
CDB92CEE229E9CF900EC757C /* MWMDiscoveryMapObjects.mm in Sources */,
|
||||
34B6FD5F2015E6BF00C18E97 /* DiscoveryBookingCell.swift in Sources */,
|
||||
34D3B01B1E389D05004100F9 /* MWMButtonCell.mm in Sources */,
|
||||
3486B5161E27AD3B0069C126 /* Framework.cpp in Sources */,
|
||||
|
@ -4960,7 +5022,6 @@
|
|||
34E50DF81F6FCC96008EED49 /* UGCReviewCell.swift in Sources */,
|
||||
F6E2FF3F1E097BA00083EBEC /* MWMSearchTableViewController.mm in Sources */,
|
||||
F6E2FDE01E097BA00083EBEC /* MWMEditorViewController.mm in Sources */,
|
||||
F69739DC1FD6ECCE00FDA07D /* DiscoveryLocalExpertCell.swift in Sources */,
|
||||
6741A9C01BF340DE002C974C /* MWMTextView.m in Sources */,
|
||||
B32FE74320D2B09600EF7446 /* CatalogWebViewController.swift in Sources */,
|
||||
F6E2FDB61E097BA00083EBEC /* MWMEditorAdditionalNamesHeader.mm in Sources */,
|
||||
|
@ -5031,6 +5092,7 @@
|
|||
349D1ACF1E2E325B004A2006 /* MWMBottomMenuCollectionViewCell.mm in Sources */,
|
||||
F6E2FF451E097BA00083EBEC /* SettingsTableViewLinkCell.swift in Sources */,
|
||||
34C9BD0A1C6DBCDA000DC38D /* MWMNavigationController.m in Sources */,
|
||||
CDB92CF822A5350500EC757C /* MWMDiscoveryHotelViewModel.m in Sources */,
|
||||
F6550C1F1FD81B3800352D88 /* RatingSummaryView+DefaultConfig.swift in Sources */,
|
||||
F6E2FE311E097BA00083EBEC /* MWMStreetEditorViewController.mm in Sources */,
|
||||
F6E2FE281E097BA00083EBEC /* MWMOpeningHoursSection.mm in Sources */,
|
||||
|
@ -5115,6 +5177,7 @@
|
|||
B33D21B820E130D000BAD749 /* BookmarksTabViewController.swift in Sources */,
|
||||
3404754A1E081A4600C92850 /* AppInfo.mm in Sources */,
|
||||
3358607E217632A2006D11F2 /* BookmarksSharingViewController.swift in Sources */,
|
||||
CDB92CF1229EB8A800EC757C /* MWMDiscoverySearchViewModel.m in Sources */,
|
||||
34AB662F1FC5AA330078E451 /* RouteManageriPhonePresentationController.swift in Sources */,
|
||||
4797A4DC226F4B2900D3A984 /* DeepLinkHandler.swift in Sources */,
|
||||
34AB66201FC5AA330078E451 /* RouteStartButton.swift in Sources */,
|
||||
|
@ -5146,6 +5209,7 @@
|
|||
34E7761F1F14DB48003040B3 /* PlacePageArea.swift in Sources */,
|
||||
346DB82E1E5C4F6700E3123E /* GalleryItemViewController.swift in Sources */,
|
||||
340475561E081A4600C92850 /* Statistics.mm in Sources */,
|
||||
CD96C71722A7B5DE00DB7CFE /* MWMDiscoveryCityGalleryObjects.mm in Sources */,
|
||||
F6381BF61CD12045004CA943 /* LocaleTranslator.mm in Sources */,
|
||||
3444DFCD1F1760B900E73099 /* WidgetsArea.swift in Sources */,
|
||||
F6E2FE9A1E097BA00083EBEC /* MWMiPadPlacePageLayoutImpl.mm in Sources */,
|
||||
|
@ -5237,6 +5301,7 @@
|
|||
349D1ADB1E2E325C004A2006 /* MWMBottomMenuView.mm in Sources */,
|
||||
344BEAF61F66BDC30045DC45 /* RatingSummaryViewSettings.swift in Sources */,
|
||||
F6E2FD921E097BA00083EBEC /* MWMBookmarkColorViewController.mm in Sources */,
|
||||
CD96C71C22A8113100DB7CFE /* MWMDiscoveryControllerViewModel.mm in Sources */,
|
||||
F63AF5061EA6162400A1DB98 /* FilterTypeCell.swift in Sources */,
|
||||
347752881F725002000D46A3 /* UGCAddReviewRatingCell.swift in Sources */,
|
||||
47E3C7332111F4D8008B3B27 /* CoverVerticalDismissalAnimator.swift in Sources */,
|
||||
|
@ -5287,6 +5352,7 @@
|
|||
34EF94291C05A6F30050B714 /* MWMSegue.m in Sources */,
|
||||
3430291D1F87BF4400D0A07C /* ReviewsViewController.swift in Sources */,
|
||||
F6E2FE731E097BA00083EBEC /* MWMOpeningHours.mm in Sources */,
|
||||
CD96C70C22A681C400DB7CFE /* DiscoveryGuideCell.swift in Sources */,
|
||||
47E3C7312111F4C2008B3B27 /* CoverVerticalPresentationAnimator.swift in Sources */,
|
||||
F6D67CDC2062B9C00032FD38 /* BCCreateCategoryAlert.swift in Sources */,
|
||||
F6E2FF601E097BA00083EBEC /* MWMSettingsViewController.mm in Sources */,
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
@objc(MWMDiscoveryGuideCell)
|
||||
final class DiscoveryGuideCell: UICollectionViewCell {
|
||||
@IBOutlet var avatar: UIImageView!
|
||||
@IBOutlet var titleLabel: UILabel! {
|
||||
didSet {
|
||||
titleLabel.font = UIFont.medium14()
|
||||
titleLabel.textColor = UIColor.blackPrimaryText()
|
||||
titleLabel.numberOfLines = 2
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var subtitleLabel: UILabel! {
|
||||
didSet {
|
||||
subtitleLabel.font = UIFont.regular12()
|
||||
subtitleLabel.textColor = UIColor.blackSecondaryText()
|
||||
subtitleLabel.numberOfLines = 1
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var proLabel: UILabel! {
|
||||
didSet {
|
||||
proLabel.font = UIFont.bold12()
|
||||
proLabel.textColor = UIColor.white()
|
||||
proLabel.backgroundColor = .clear
|
||||
proLabel.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var proContainer: UIView! {
|
||||
didSet {
|
||||
proLabel.backgroundColor = UIColor.ratingRed()
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var detailsButton: UIButton! {
|
||||
didSet {
|
||||
detailsButton.setTitleColor(UIColor.linkBlue(), for: .normal)
|
||||
detailsButton.setTitle(L("details"), for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
typealias OnDetails = () -> Void
|
||||
private var onDetails: OnDetails?
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
didSet {
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: [.allowUserInteraction, .beginFromCurrentState],
|
||||
animations: { self.alpha = self.isHighlighted ? 0.3 : 1 },
|
||||
completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
layer.borderColor = UIColor.blackDividers().cgColor
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
avatar.image = UIImage(named: "img_guide_placeholder")
|
||||
titleLabel.text = ""
|
||||
subtitleLabel.text = ""
|
||||
proLabel.text = ""
|
||||
proContainer.isHidden = true
|
||||
onDetails = nil
|
||||
}
|
||||
|
||||
private func setAvatar(_ avatarURL: String?) {
|
||||
guard let avatarURL = avatarURL else { return }
|
||||
if !avatarURL.isEmpty, let url = URL(string: avatarURL) {
|
||||
avatar.image = UIImage(named: "img_guide_placeholder")
|
||||
avatar.wi_setImage(with: url, transitionDuration: kDefaultAnimationDuration)
|
||||
} else {
|
||||
avatar.image = UIImage(named: "img_guide_placeholder")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func config(avatarURL: String?,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
label: String?,
|
||||
onDetails: @escaping OnDetails) {
|
||||
setAvatar(avatarURL)
|
||||
titleLabel.text = title
|
||||
subtitleLabel.text = subtitle
|
||||
self.onDetails = onDetails
|
||||
guard let label = label, !label.isEmpty else {
|
||||
proContainer.isHidden = true
|
||||
return
|
||||
}
|
||||
proLabel.text = label
|
||||
proContainer.isHidden = false
|
||||
}
|
||||
|
||||
@IBAction private func detailsAction() {
|
||||
onDetails?()
|
||||
}
|
||||
}
|
111
iphone/Maps/UI/Discovery/Collection Cells/DiscoveryGuideCell.xib
Normal file
111
iphone/Maps/UI/Discovery/Collection Cells/DiscoveryGuideCell.xib
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="DiscoveryGuideCell" id="gTV-IL-0wX" customClass="MWMDiscoveryGuideCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="194"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="194"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="PVI-wd-HVI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="80"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="80" id="kmH-tC-wJm"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yJV-Vb-Cna">
|
||||
<rect key="frame" x="0.0" y="154" width="160" height="40"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.040000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="160" id="k85-sb-f1d"/>
|
||||
<constraint firstAttribute="height" constant="40" id="mzG-ku-CVD"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Button"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7eA-bJ-coY">
|
||||
<rect key="frame" x="12" y="94" width="136" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fEh-1z-Iwj">
|
||||
<rect key="frame" x="12" y="119" width="136" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C9b-m0-Yo8">
|
||||
<rect key="frame" x="0.0" y="46" width="54" height="24"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PRO" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vHm-DF-mQY">
|
||||
<rect key="frame" x="12" y="2" width="34" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="vHm-DF-mQY" secondAttribute="trailing" constant="8" id="PrH-Je-n6I"/>
|
||||
<constraint firstItem="vHm-DF-mQY" firstAttribute="centerY" secondItem="C9b-m0-Yo8" secondAttribute="centerY" id="Xs2-If-e7l"/>
|
||||
<constraint firstItem="vHm-DF-mQY" firstAttribute="leading" secondItem="C9b-m0-Yo8" secondAttribute="leading" constant="12" id="Y5o-2R-3Oc"/>
|
||||
<constraint firstAttribute="height" constant="24" id="wua-lE-6XL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="fEh-1z-Iwj" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="12" id="0by-Hl-DH6"/>
|
||||
<constraint firstItem="C9b-m0-Yo8" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="46" id="4kb-GH-H1e"/>
|
||||
<constraint firstAttribute="trailing" secondItem="PVI-wd-HVI" secondAttribute="trailing" id="8Cm-hB-mok"/>
|
||||
<constraint firstItem="PVI-wd-HVI" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="B20-vK-ARj"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="C9b-m0-Yo8" secondAttribute="trailing" constant="12" id="C8r-A9-Der"/>
|
||||
<constraint firstItem="fEh-1z-Iwj" firstAttribute="top" secondItem="7eA-bJ-coY" secondAttribute="bottom" constant="4" id="LiX-Yq-174"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fEh-1z-Iwj" secondAttribute="trailing" constant="12" id="Umy-G4-a7D"/>
|
||||
<constraint firstAttribute="bottom" secondItem="yJV-Vb-Cna" secondAttribute="bottom" id="XF5-Eb-seh"/>
|
||||
<constraint firstAttribute="trailing" secondItem="yJV-Vb-Cna" secondAttribute="trailing" id="aDP-NV-THf"/>
|
||||
<constraint firstItem="C9b-m0-Yo8" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="bfT-M4-gwc"/>
|
||||
<constraint firstItem="7eA-bJ-coY" firstAttribute="top" secondItem="PVI-wd-HVI" secondAttribute="bottom" constant="14" id="gky-f9-L3c"/>
|
||||
<constraint firstAttribute="trailing" secondItem="7eA-bJ-coY" secondAttribute="trailing" constant="12" id="h1O-eP-2R5"/>
|
||||
<constraint firstItem="PVI-wd-HVI" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="jfP-VD-ppb"/>
|
||||
<constraint firstItem="7eA-bJ-coY" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="12" id="un2-TG-Jhd"/>
|
||||
<constraint firstItem="yJV-Vb-Cna" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="xQS-S1-sFI"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<size key="customSize" width="160" height="194"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
|
||||
<integer key="value" value="1"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="avatar" destination="PVI-wd-HVI" id="zzN-X5-o2N"/>
|
||||
<outlet property="detailsButton" destination="yJV-Vb-Cna" id="UE3-4n-7dC"/>
|
||||
<outlet property="proContainer" destination="C9b-m0-Yo8" id="gUI-wn-gtQ"/>
|
||||
<outlet property="proLabel" destination="vHm-DF-mQY" id="31b-6G-yvb"/>
|
||||
<outlet property="subtitleLabel" destination="fEh-1z-Iwj" id="anX-gC-URG"/>
|
||||
<outlet property="titleLabel" destination="7eA-bJ-coY" id="hpL-Ce-BRw"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="220.28985507246378" y="184.82142857142856"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
</document>
|
|
@ -1,126 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "map/discovery/discovery_client_params.hpp"
|
||||
#include "map/search_product_info.hpp"
|
||||
|
||||
#include "partners_api/locals_api.hpp"
|
||||
|
||||
#include "search/result.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace discovery
|
||||
{
|
||||
class DiscoveryControllerViewModel
|
||||
{
|
||||
public:
|
||||
void SetSearchResults(search::Results const & res,
|
||||
std::vector<search::ProductInfo> const & productInfo,
|
||||
m2::PointD const & viewportCenter, ItemType const type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::Attractions:
|
||||
m_attractions.SetResults(res, productInfo, viewportCenter);
|
||||
break;
|
||||
case ItemType::Cafes:
|
||||
m_cafes.SetResults(res, productInfo, viewportCenter);
|
||||
break;
|
||||
case ItemType::Hotels:
|
||||
m_hotels.SetResults(res, productInfo, viewportCenter);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetExperts(std::vector<locals::LocalExpert> const & experts) { m_experts = experts; }
|
||||
|
||||
size_t GetItemsCount(ItemType const type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::Attractions: return m_attractions.m_results.GetCount();
|
||||
case ItemType::Cafes: return m_cafes.m_results.GetCount();
|
||||
case ItemType::Hotels: return m_hotels.m_results.GetCount();
|
||||
case ItemType::LocalExperts: return m_experts.size();
|
||||
// TODO: Add correct value here.
|
||||
case ItemType::Promo: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
search::Result const & GetAttractionAt(size_t const index) const
|
||||
{
|
||||
return m_attractions.GetSearchResultAt(index);
|
||||
}
|
||||
|
||||
m2::PointD const & GetAttractionReferencePoint() const { return m_attractions.m_viewportCenter; }
|
||||
|
||||
search::ProductInfo const & GetAttractionProductInfoAt(size_t const index) const
|
||||
{
|
||||
return m_attractions.GetProductInfoAt(index);
|
||||
}
|
||||
|
||||
search::Result const & GetCafeAt(size_t const index) const
|
||||
{
|
||||
return m_cafes.GetSearchResultAt(index);
|
||||
}
|
||||
|
||||
m2::PointD const & GetCafeReferencePoint() const { return m_cafes.m_viewportCenter; }
|
||||
|
||||
search::ProductInfo const & GetCafeProductInfoAt(size_t const index) const
|
||||
{
|
||||
return m_cafes.GetProductInfoAt(index);
|
||||
}
|
||||
|
||||
locals::LocalExpert const & GetExpertAt(size_t const index) const
|
||||
{
|
||||
CHECK_LESS(index, m_experts.size(), ("Incorrect experts index:", index));
|
||||
return m_experts[index];
|
||||
}
|
||||
|
||||
search::Result const & GetHotelAt(size_t const index) const
|
||||
{
|
||||
return m_hotels.GetSearchResultAt(index);
|
||||
}
|
||||
|
||||
m2::PointD const & GetHotelReferencePoint() const { return m_hotels.m_viewportCenter; }
|
||||
|
||||
private:
|
||||
struct UISearchResults
|
||||
{
|
||||
m2::PointD m_viewportCenter;
|
||||
search::Results m_results;
|
||||
std::vector<search::ProductInfo> m_productInfos;
|
||||
|
||||
void SetResults(search::Results const & res,
|
||||
std::vector<search::ProductInfo> const & productInfo,
|
||||
m2::PointD const & viewportCenter)
|
||||
{
|
||||
m_viewportCenter = viewportCenter;
|
||||
m_results = res;
|
||||
m_productInfos = productInfo;
|
||||
}
|
||||
|
||||
search::Result const & GetSearchResultAt(size_t const index) const
|
||||
{
|
||||
CHECK_LESS(index, m_results.GetCount(), ("Incorrect index:", index));
|
||||
return m_results[index];
|
||||
}
|
||||
|
||||
search::ProductInfo const & GetProductInfoAt(size_t const index) const
|
||||
{
|
||||
CHECK_LESS(index, m_productInfos.size(), ("Incorrect index:", index));
|
||||
return m_productInfos[index];
|
||||
}
|
||||
};
|
||||
|
||||
UISearchResults m_attractions;
|
||||
UISearchResults m_cafes;
|
||||
UISearchResults m_hotels;
|
||||
std::vector<locals::LocalExpert> m_experts;
|
||||
};
|
||||
} // namespace discovery
|
|
@ -1,74 +0,0 @@
|
|||
@objc(MWMDiscoveryLocalExpertCell)
|
||||
final class DiscoveryLocalExpertCell: UICollectionViewCell {
|
||||
@IBOutlet private weak var avatar: UIImageView!
|
||||
@IBOutlet private weak var name: UILabel!
|
||||
@IBOutlet private weak var rating: RatingSummaryView! {
|
||||
didSet {
|
||||
rating.defaultConfig()
|
||||
rating.textFont = UIFont.bold12()
|
||||
rating.textSize = 12
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var price: UIButton!
|
||||
|
||||
private lazy var formatter: NumberFormatter = {
|
||||
let f = NumberFormatter()
|
||||
f.numberStyle = .currency
|
||||
return f
|
||||
}()
|
||||
|
||||
typealias Tap = () -> ()
|
||||
private var tap: Tap!
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
didSet {
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: [.allowUserInteraction, .beginFromCurrentState],
|
||||
animations: { self.alpha = self.isHighlighted ? 0.3 : 1 },
|
||||
completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func config(avatarURL: String,
|
||||
name: String,
|
||||
ratingValue: String,
|
||||
ratingType: MWMRatingSummaryViewValueType,
|
||||
price: Double,
|
||||
currency: String,
|
||||
tap: @escaping Tap) {
|
||||
if avatarURL.count > 0, let url = URL(string: avatarURL) {
|
||||
avatar.image = #imageLiteral(resourceName: "img_localsdefault")
|
||||
avatar.wi_setImage(with: url, transitionDuration: kDefaultAnimationDuration)
|
||||
} else {
|
||||
avatar.image = #imageLiteral(resourceName: "img_localsdefault")
|
||||
}
|
||||
|
||||
self.name.text = name
|
||||
rating.value = ratingValue
|
||||
rating.type = ratingType
|
||||
let str: String
|
||||
if currency.count > 0, let cur = stringFor(price: price, currencyCode: currency) {
|
||||
str = String(coreFormat: L("price_per_hour"), arguments:[cur])
|
||||
} else {
|
||||
str = L("free")
|
||||
}
|
||||
|
||||
self.price.setTitle(str, for: .normal)
|
||||
self.tap = tap
|
||||
}
|
||||
|
||||
@IBAction private func tapOnPrice() {
|
||||
tap?()
|
||||
}
|
||||
|
||||
private func stringFor(price: Double, currencyCode: String) -> String? {
|
||||
formatter.currencyCode = currencyCode
|
||||
return formatter.string(for: price)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
layer.borderColor = UIColor.blackDividers().cgColor
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="DiscoveryLocalExpertCell" id="bjC-eX-cME" customClass="MWMDiscoveryLocalExpertCell" propertyAccessControl="all">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="196"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="196"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="WIp-9D-zCf">
|
||||
<rect key="frame" x="40" y="12" width="80" height="80"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="80" id="SzI-04-VFX"/>
|
||||
<constraint firstAttribute="width" constant="80" id="aTd-ud-dX2"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="40"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WvH-Ak-fYM">
|
||||
<rect key="frame" x="12" y="104" width="136" height="20"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="136" id="0qb-xy-rRb"/>
|
||||
<constraint firstAttribute="height" constant="20" id="D3X-Qh-8pr"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium14"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KmA-vt-YxO" customClass="RatingSummaryView" customModule="maps_me" customModuleProvider="target">
|
||||
<rect key="frame" x="56" y="128" width="48" height="20"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="48" id="6WJ-qD-apL"/>
|
||||
<constraint firstAttribute="height" constant="20" id="jcd-OG-vjG"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="excellentImage" value="ic_24px_rating_excellent"/>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="goodImage" value="ic_24px_rating_excellent"/>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="normalImage" value="ic_24px_rating_normal"/>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="badImage" value="ic_24px_rating_bad"/>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="horribleImage" value="ic_24px_rating_horrible"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="topOffset">
|
||||
<real key="value" value="2"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="bottomOffset">
|
||||
<real key="value" value="2"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="leadingImageOffset">
|
||||
<real key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="margin">
|
||||
<real key="value" value="4"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="trailingTextOffset">
|
||||
<real key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="noValueImage" value="ic_12px_rating_normal"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5vR-oH-2gt">
|
||||
<rect key="frame" x="0.0" y="156" width="160" height="40"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.040000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="160" id="NFU-3P-bPD"/>
|
||||
<constraint firstAttribute="height" constant="40" id="Yyw-mG-8Io"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Button"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="tapOnPrice" destination="bjC-eX-cME" eventType="touchUpInside" id="Stz-gF-ZeN"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="5vR-oH-2gt" firstAttribute="centerX" secondItem="bjC-eX-cME" secondAttribute="centerX" id="A7d-cI-icR"/>
|
||||
<constraint firstItem="WIp-9D-zCf" firstAttribute="top" secondItem="bjC-eX-cME" secondAttribute="top" constant="12" id="Hdr-qF-Wyu"/>
|
||||
<constraint firstItem="WvH-Ak-fYM" firstAttribute="centerX" secondItem="WIp-9D-zCf" secondAttribute="centerX" id="JT7-a1-XfK"/>
|
||||
<constraint firstItem="KmA-vt-YxO" firstAttribute="centerX" secondItem="WvH-Ak-fYM" secondAttribute="centerX" id="ai8-rn-tev"/>
|
||||
<constraint firstItem="WIp-9D-zCf" firstAttribute="centerX" secondItem="bjC-eX-cME" secondAttribute="centerX" id="fbj-br-6kW"/>
|
||||
<constraint firstItem="KmA-vt-YxO" firstAttribute="top" secondItem="WvH-Ak-fYM" secondAttribute="bottom" constant="4" id="iw3-ld-rqj"/>
|
||||
<constraint firstAttribute="bottom" secondItem="5vR-oH-2gt" secondAttribute="bottom" priority="750" id="lUj-bi-oC1"/>
|
||||
<constraint firstItem="5vR-oH-2gt" firstAttribute="top" secondItem="KmA-vt-YxO" secondAttribute="bottom" constant="8" id="pDT-4d-d9L"/>
|
||||
<constraint firstItem="WvH-Ak-fYM" firstAttribute="top" secondItem="WIp-9D-zCf" secondAttribute="bottom" constant="12" id="uvh-8Y-Ed6"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
|
||||
<integer key="value" value="1"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="avatar" destination="WIp-9D-zCf" id="NO6-oZ-fBH"/>
|
||||
<outlet property="name" destination="WvH-Ak-fYM" id="SDk-7F-Ff1"/>
|
||||
<outlet property="price" destination="5vR-oH-2gt" id="IFd-Z9-x8k"/>
|
||||
<outlet property="rating" destination="KmA-vt-YxO" id="fp1-El-5cn"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-165" y="-28"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="ic_12px_rating_normal" width="12" height="12"/>
|
||||
<image name="ic_24px_rating_bad" width="24" height="24"/>
|
||||
<image name="ic_24px_rating_excellent" width="24" height="24"/>
|
||||
<image name="ic_24px_rating_horrible" width="24" height="24"/>
|
||||
<image name="ic_24px_rating_normal" width="24" height="24"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -1,39 +0,0 @@
|
|||
@objc(MWMDiscoveryOnlineTemplateType)
|
||||
enum DiscoveryOnlineTemplateType: Int {
|
||||
case locals
|
||||
}
|
||||
|
||||
@objc(MWMDiscoveryOnlineTemplateCell)
|
||||
final class DiscoveryOnlineTemplateCell: MWMTableViewCell {
|
||||
@IBOutlet private weak var spinner: UIImageView! {
|
||||
didSet {
|
||||
let postfix = UIColor.isNightMode() ? "_dark" : "_light"
|
||||
spinner.image = UIImage(named: "Spinner" + postfix)
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet private weak var title: UILabel!
|
||||
@IBOutlet private weak var subtitle: UILabel!
|
||||
|
||||
typealias Tap = () -> ()
|
||||
private var tap: Tap?
|
||||
|
||||
@objc func config(type: DiscoveryOnlineTemplateType, needSpinner: Bool, tap: @escaping Tap) {
|
||||
switch type {
|
||||
case .locals:
|
||||
title.text = needSpinner ? L("discovery_button_other_loading_message") :
|
||||
L("discovery_button_other_error_message")
|
||||
subtitle.text = ""
|
||||
}
|
||||
|
||||
spinner.isHidden = !needSpinner
|
||||
if (needSpinner) {
|
||||
spinner.startRotation()
|
||||
}
|
||||
self.tap = tap
|
||||
}
|
||||
|
||||
@IBAction private func onTap() {
|
||||
tap?()
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="DiscoveryOnlineTemplateCell" rowHeight="218" id="9IM-3s-P1U" customClass="MWMDiscoveryOnlineTemplateCell" propertyAccessControl="all">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="218"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9IM-3s-P1U" id="RFj-It-lNu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="217.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UMh-FO-rZJ">
|
||||
<rect key="frame" x="20" y="79" width="335" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="XSe-2e-PrA"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium14"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Jk-er-UUa">
|
||||
<rect key="frame" x="20" y="99" width="335" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="e1q-4W-JhV"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dCP-Yu-fFz">
|
||||
<rect key="frame" x="175" y="47" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="JmM-dN-DAf"/>
|
||||
<constraint firstAttribute="height" constant="24" id="RP9-kK-iAl"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WoO-mw-61q">
|
||||
<rect key="frame" x="0.0" y="177" width="375" height="40"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.040000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="JKj-h8-ljn"/>
|
||||
</constraints>
|
||||
<state key="normal" title="DETAILS"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="details"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="onTap" destination="9IM-3s-P1U" eventType="touchUpInside" id="wGN-bL-0IS"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="UMh-FO-rZJ" firstAttribute="top" secondItem="dCP-Yu-fFz" secondAttribute="bottom" constant="8" id="BY1-6k-WBn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UMh-FO-rZJ" secondAttribute="trailing" constant="20" id="Rsw-ey-7z8"/>
|
||||
<constraint firstItem="WoO-mw-61q" firstAttribute="top" secondItem="4Jk-er-UUa" secondAttribute="bottom" constant="62" id="afG-Ho-xVJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WoO-mw-61q" secondAttribute="trailing" id="c97-re-08v"/>
|
||||
<constraint firstItem="4Jk-er-UUa" firstAttribute="leading" secondItem="RFj-It-lNu" secondAttribute="leading" constant="20" id="iEA-Ea-7qS"/>
|
||||
<constraint firstItem="WoO-mw-61q" firstAttribute="leading" secondItem="RFj-It-lNu" secondAttribute="leading" id="leN-MX-iDP"/>
|
||||
<constraint firstAttribute="bottom" secondItem="WoO-mw-61q" secondAttribute="bottom" priority="750" id="njG-qV-vDU"/>
|
||||
<constraint firstItem="dCP-Yu-fFz" firstAttribute="centerX" secondItem="RFj-It-lNu" secondAttribute="centerX" id="p1k-Ug-WjO"/>
|
||||
<constraint firstItem="UMh-FO-rZJ" firstAttribute="leading" secondItem="RFj-It-lNu" secondAttribute="leading" constant="20" id="pOY-Nu-Av9"/>
|
||||
<constraint firstItem="4Jk-er-UUa" firstAttribute="top" secondItem="UMh-FO-rZJ" secondAttribute="bottom" constant="4" id="uED-OK-PG4"/>
|
||||
<constraint firstItem="dCP-Yu-fFz" firstAttribute="top" secondItem="RFj-It-lNu" secondAttribute="top" constant="47" id="wjy-Fv-MDg"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4Jk-er-UUa" secondAttribute="trailing" constant="20" id="xiC-I1-7yp"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="spinner" destination="dCP-Yu-fFz" id="0nk-0c-1AG"/>
|
||||
<outlet property="subtitle" destination="4Jk-er-UUa" id="oHh-a4-HLJ"/>
|
||||
<outlet property="title" destination="UMh-FO-rZJ" id="Bqr-Qj-R0g"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-187.5" y="105"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
14
iphone/Maps/UI/Discovery/MWMDiscoveryCityGalleryObjects.h
Normal file
14
iphone/Maps/UI/Discovery/MWMDiscoveryCityGalleryObjects.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "partners_api/promo_api.hpp"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MWMDiscoveryCityGalleryObjects : NSObject
|
||||
|
||||
- (instancetype)initWithGalleryResults:(promo::CityGallery const &)results;
|
||||
- (promo::CityGallery::Item const &)galleryItemAtIndex:(NSUInteger)index;
|
||||
- (NSUInteger)count;
|
||||
- (nullable NSURL *)moreURL;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
35
iphone/Maps/UI/Discovery/MWMDiscoveryCityGalleryObjects.mm
Normal file
35
iphone/Maps/UI/Discovery/MWMDiscoveryCityGalleryObjects.mm
Normal file
|
@ -0,0 +1,35 @@
|
|||
#import "MWMDiscoveryCityGalleryObjects.h"
|
||||
|
||||
@interface MWMDiscoveryCityGalleryObjects() {
|
||||
promo::CityGallery m_results;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryCityGalleryObjects
|
||||
|
||||
- (instancetype)initWithGalleryResults:(promo::CityGallery const &)results {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
m_results = results;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (promo::CityGallery::Item const &)galleryItemAtIndex:(NSUInteger)index {
|
||||
CHECK_LESS(index, m_results.m_items.size(), ("Incorrect index:", index));
|
||||
return m_results.m_items[index];
|
||||
}
|
||||
|
||||
- (NSUInteger)count {
|
||||
return m_results.m_items.size();
|
||||
}
|
||||
|
||||
- (NSURL *)moreURL {
|
||||
NSString *path = @(m_results.m_moreUrl.c_str());
|
||||
if (path != nil && path.length > 0) {
|
||||
return [NSURL URLWithString:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,6 +1,9 @@
|
|||
#import "MWMDiscoveryController.h"
|
||||
|
||||
#import "Framework.h"
|
||||
#import "MWMDiscoveryControllerViewModel.h"
|
||||
#import "MWMDiscoveryCityGalleryObjects.h"
|
||||
#import "MWMDiscoveryMapObjects.h"
|
||||
#import "MWMDiscoveryTableManager.h"
|
||||
#import "MWMDiscoveryTapDelegate.h"
|
||||
#import "MWMEye.h"
|
||||
|
@ -10,8 +13,7 @@
|
|||
#import "MWMSearchManager+Filter.h"
|
||||
#import "Statistics.h"
|
||||
#import "UIKitCategories.h"
|
||||
|
||||
#include "DiscoveryControllerViewModel.hpp"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
#include "map/discovery/discovery_client_params.hpp"
|
||||
#include "map/search_product_info.hpp"
|
||||
|
@ -49,28 +51,28 @@ struct Callback
|
|||
m_setSearchResults(results, productInfo, viewportCenter, type);
|
||||
m_refreshSection(type);
|
||||
}
|
||||
|
||||
|
||||
void operator()(uint32_t const requestId, vector<locals::LocalExpert> const & experts) const
|
||||
{
|
||||
CHECK(m_setLocalExperts, ());
|
||||
CHECK(m_refreshSection, ());
|
||||
m_setLocalExperts(experts);
|
||||
m_refreshSection(ItemType::LocalExperts);
|
||||
// TODO: Please add correct implementation here.
|
||||
}
|
||||
|
||||
void operator()(uint32_t const requestId, promo::CityGallery const & experts) const
|
||||
{
|
||||
// TODO: Please add correct implementation here.
|
||||
CHECK(m_setPromoCityGallery, ());
|
||||
CHECK(m_refreshSection, ());
|
||||
m_setPromoCityGallery(experts);
|
||||
m_refreshSection(ItemType::Promo);
|
||||
}
|
||||
|
||||
using SetSearchResults =
|
||||
function<void(search::Results const & res, vector<search::ProductInfo> const & productInfo,
|
||||
m2::PointD const & viewportCenter, ItemType const type)>;
|
||||
using SetLocalExperts = function<void(vector<locals::LocalExpert> const & experts)>;
|
||||
using SetPromoCityGallery = function<void(promo::CityGallery const & experts)>;
|
||||
using RefreshSection = function<void(ItemType const type)>;
|
||||
|
||||
SetSearchResults m_setSearchResults;
|
||||
SetLocalExperts m_setLocalExperts;
|
||||
SetPromoCityGallery m_setPromoCityGallery;
|
||||
RefreshSection m_refreshSection;
|
||||
};
|
||||
} // namespace
|
||||
|
@ -78,54 +80,67 @@ struct Callback
|
|||
@interface MWMDiscoveryController ()<MWMDiscoveryTapDelegate>
|
||||
{
|
||||
Callback m_callback;
|
||||
DiscoveryControllerViewModel m_model;
|
||||
}
|
||||
|
||||
@property(weak, nonatomic) IBOutlet UITableView * tableView;
|
||||
@property(nonatomic) MWMDiscoveryTableManager * tableManager;
|
||||
@property(nonatomic) MWMDiscoveryControllerViewModel *viewModel;
|
||||
@property(nonatomic) BOOL canUseNetwork;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryController
|
||||
|
||||
+ (instancetype)instanceWithConnection:(BOOL)canUseNetwork
|
||||
{
|
||||
+ (instancetype)instanceWithConnection:(BOOL)canUseNetwork {
|
||||
auto instance = [[MWMDiscoveryController alloc] initWithNibName:self.className bundle:nil];
|
||||
instance.title = L(@"discovery_button_title");
|
||||
instance.canUseNetwork = canUseNetwork;
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)name bundle:(NSBundle *)bundle
|
||||
{
|
||||
- (instancetype)initWithNibName:(NSString *)name bundle:(NSBundle *)bundle {
|
||||
self = [super initWithNibName:name bundle:bundle];
|
||||
if (self)
|
||||
{
|
||||
if (self) {
|
||||
_viewModel = [[MWMDiscoveryControllerViewModel alloc] init];
|
||||
auto & cb = m_callback;
|
||||
cb.m_setLocalExperts = bind(&DiscoveryControllerViewModel::SetExperts, &m_model, _1);
|
||||
cb.m_setSearchResults =
|
||||
bind(&DiscoveryControllerViewModel::SetSearchResults, &m_model, _1, _2, _3, _4);
|
||||
cb.m_refreshSection = [self](ItemType const type) { [self.tableManager reloadItem:type]; };
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
cb.m_setSearchResults = [weakSelf](search::Results const & res, vector<search::ProductInfo> const & productInfo, m2::PointD const & viewportCenter, ItemType const type) {
|
||||
__strong __typeof__(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) { return; }
|
||||
MWMDiscoveryMapObjects *objects = [[MWMDiscoveryMapObjects alloc] initWithSearchResults:res
|
||||
productInfos:productInfo
|
||||
viewPortCenter:viewportCenter];
|
||||
[strongSelf.viewModel updateMapObjects:objects forType:type];
|
||||
};
|
||||
cb.m_setPromoCityGallery = [weakSelf](promo::CityGallery const & experts) {
|
||||
__strong __typeof__(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) { return; }
|
||||
MWMDiscoveryCityGalleryObjects *objects = [[MWMDiscoveryCityGalleryObjects alloc] initWithGalleryResults:experts];
|
||||
[strongSelf.viewModel updateCityGalleryObjects:objects];
|
||||
};
|
||||
cb.m_refreshSection = [weakSelf](ItemType const type) {
|
||||
__strong __typeof__(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf) { return; }
|
||||
[strongSelf.tableManager reloadItem:type];
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
auto callback = [self]() -> DiscoveryControllerViewModel const & { return self->m_model; };
|
||||
self.tableManager = [[MWMDiscoveryTableManager alloc] initWithTableView:self.tableView
|
||||
delegate:self
|
||||
model:move(callback)];
|
||||
|
||||
auto getTypes = [](BOOL canUseNetwork) -> vector<ItemType> {
|
||||
if (canUseNetwork)
|
||||
return {ItemType::Hotels, ItemType::Attractions, ItemType::Cafes, ItemType::LocalExperts};
|
||||
return {ItemType::Hotels, ItemType::Attractions, ItemType::Cafes};
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
MWMGetModelCallback callback = ^{
|
||||
return weakSelf.viewModel;
|
||||
};
|
||||
|
||||
vector<ItemType> types = getTypes(self.canUseNetwork);
|
||||
self.tableManager = [[MWMDiscoveryTableManager alloc] initWithTableView:self.tableView
|
||||
canUseNetwork:self.canUseNetwork
|
||||
delegate:self
|
||||
model:callback];
|
||||
vector<ItemType> types = {ItemType::Hotels, ItemType::Attractions, ItemType::Cafes, ItemType:: Promo};
|
||||
[self.tableManager loadItems:types];
|
||||
ClientParams p;
|
||||
p.m_itemTypes = move(types);
|
||||
|
@ -138,91 +153,90 @@ struct Callback
|
|||
|
||||
#pragma mark - MWMDiscoveryTapDelegate
|
||||
|
||||
- (void)showSearchResult:(const search::Result &)item
|
||||
{
|
||||
- (void)showSearchResult:(const search::Result &)item {
|
||||
GetFramework().ShowSearchResult(item);
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)tapOnItem:(ItemType const)type atIndex:(size_t const)index
|
||||
{
|
||||
- (void)tapOnItem:(ItemType const)type atIndex:(NSInteger)index {
|
||||
NSString * dest = @"";
|
||||
NSString * event = kStatPlacepageSponsoredItemSelected;
|
||||
MWMEyeDiscoveryEvent eyeEvent;
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::LocalExperts:
|
||||
if (index == m_model.GetItemsCount(type))
|
||||
{
|
||||
[self openURLForItem:type];
|
||||
event = kStatPlacepageSponsoredMoreSelected;
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreLocals;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self openUrl:[NSURL URLWithString:@(m_model.GetExpertAt(index).m_pageUrl.c_str())]];
|
||||
eyeEvent = MWMEyeDiscoveryEventLocals;
|
||||
}
|
||||
dest = kStatExternal;
|
||||
break;
|
||||
case ItemType::Attractions:
|
||||
if (index == m_model.GetItemsCount(type))
|
||||
{
|
||||
[self searchTourism];
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreAttractions;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self showSearchResult:m_model.GetAttractionAt(index)];
|
||||
eyeEvent = MWMEyeDiscoveryEventAttractions;
|
||||
}
|
||||
|
||||
dest = kStatPlacePage;
|
||||
break;
|
||||
case ItemType::Cafes:
|
||||
if (index == m_model.GetItemsCount(type))
|
||||
{
|
||||
[self searchFood];
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreCafes;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self showSearchResult:m_model.GetCafeAt(index)];
|
||||
eyeEvent = MWMEyeDiscoveryEventCafes;
|
||||
}
|
||||
|
||||
dest = kStatPlacePage;
|
||||
break;
|
||||
case ItemType::Hotels:
|
||||
if (index == m_model.GetItemsCount(type))
|
||||
{
|
||||
[self openFilters];
|
||||
event = kStatPlacepageSponsoredMoreSelected;
|
||||
dest = kStatSearchFilterOpen;
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreHotels;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self showSearchResult:m_model.GetHotelAt(index)];
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
if (index == [self.viewModel itemsCountForType:type]) {
|
||||
[self searchTourism];
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreAttractions;
|
||||
} else {
|
||||
[self showSearchResult:[self.viewModel.attractions searchResultAtIndex:index]];
|
||||
eyeEvent = MWMEyeDiscoveryEventAttractions;
|
||||
}
|
||||
|
||||
dest = kStatPlacePage;
|
||||
eyeEvent = MWMEyeDiscoveryEventHotels;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case ItemType::Cafes:
|
||||
if (index == [self.viewModel itemsCountForType:type]) {
|
||||
[self searchFood];
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreCafes;
|
||||
} else {
|
||||
[self showSearchResult:[self.viewModel.cafes searchResultAtIndex:index]];
|
||||
eyeEvent = MWMEyeDiscoveryEventCafes;
|
||||
}
|
||||
|
||||
dest = kStatPlacePage;
|
||||
break;
|
||||
case ItemType::Hotels:
|
||||
if (index == [self.viewModel itemsCountForType:type]) {
|
||||
[self openFilters];
|
||||
event = kStatPlacepageSponsoredMoreSelected;
|
||||
dest = kStatSearchFilterOpen;
|
||||
eyeEvent = MWMEyeDiscoveryEventMoreHotels;
|
||||
} else {
|
||||
[self showSearchResult:[self.viewModel.hotels searchResultAtIndex:index]];
|
||||
dest = kStatPlacePage;
|
||||
eyeEvent = MWMEyeDiscoveryEventHotels;
|
||||
}
|
||||
break;
|
||||
case ItemType::Promo:
|
||||
if (index == [self.viewModel itemsCountForType:type]) {
|
||||
[self logEvent:kStatPlacepageSponsoredMoreSelected
|
||||
type:type
|
||||
index:index
|
||||
destination:kStatExternal];
|
||||
} else {
|
||||
[self openURLForItem:type];
|
||||
[self logEvent:event
|
||||
type:type
|
||||
index:index
|
||||
destination:kStatExternal];
|
||||
}
|
||||
return;
|
||||
case ItemType::LocalExperts:
|
||||
return;
|
||||
}
|
||||
|
||||
NSAssert(dest.length > 0, @"");
|
||||
[Statistics logEvent:kStatPlacepageSponsoredItemSelected
|
||||
withParameters:@{
|
||||
kStatProvider: StatProvider(type),
|
||||
kStatPlacement: kStatDiscovery,
|
||||
kStatItem: @(index + 1),
|
||||
kStatDestination: dest
|
||||
}];
|
||||
|
||||
[self logEvent:event
|
||||
type:type
|
||||
index:index
|
||||
destination:dest];
|
||||
[MWMEye discoveryItemClickedWithEvent:eyeEvent];
|
||||
}
|
||||
|
||||
- (void)openFilters
|
||||
{
|
||||
- (void)logEvent:(NSString *)eventName
|
||||
type:(ItemType const)type
|
||||
index:(NSInteger)index
|
||||
destination:(NSString *)destination {
|
||||
NSAssert(destination.length > 0, @"");
|
||||
[Statistics logEvent:eventName
|
||||
withParameters:@{
|
||||
kStatProvider: StatProvider(type),
|
||||
kStatPlacement: kStatDiscovery,
|
||||
kStatItem: @(index + 1),
|
||||
kStatDestination: destination
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)openFilters {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
[[MWMSearchManager manager] showHotelFilterWithParams:nil
|
||||
onFinishCallback:^{
|
||||
|
@ -232,22 +246,19 @@ struct Callback
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)searchFood
|
||||
{
|
||||
- (void)searchFood {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
[MWMMapViewControlsManager.manager searchTextOnMap:[L(@"eat") stringByAppendingString:@" "]
|
||||
forInputLocale:[NSLocale currentLocale].localeIdentifier];
|
||||
}
|
||||
|
||||
- (void)searchTourism
|
||||
{
|
||||
- (void)searchTourism {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
[MWMMapViewControlsManager.manager searchTextOnMap:[L(@"tourism") stringByAppendingString:@" "]
|
||||
forInputLocale:[NSLocale currentLocale].localeIdentifier];
|
||||
}
|
||||
|
||||
- (void)routeToItem:(ItemType const)type atIndex:(size_t const)index
|
||||
{
|
||||
- (void)routeToItem:(ItemType const)type atIndex:(NSInteger)index {
|
||||
__block m2::PointD point;
|
||||
__block NSString * title;
|
||||
__block NSString * subtitle;
|
||||
|
@ -262,16 +273,19 @@ struct Callback
|
|||
title = item.GetString().empty() ? subtitle : @(item.GetString().c_str());
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::Attractions: getRoutePointInfo(m_model.GetAttractionAt(index)); break;
|
||||
case ItemType::Cafes: getRoutePointInfo(m_model.GetCafeAt(index)); break;
|
||||
case ItemType::Hotels: getRoutePointInfo(m_model.GetHotelAt(index)); break;
|
||||
case ItemType::LocalExperts:
|
||||
CHECK(false, ("Attempt to route to item with type:", static_cast<int>(type)));
|
||||
break;
|
||||
// TODO: Add correct code here.
|
||||
case ItemType::Promo: break;
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
getRoutePointInfo([self.viewModel.attractions searchResultAtIndex:index]);
|
||||
break;
|
||||
case ItemType::Cafes:
|
||||
getRoutePointInfo([self.viewModel.cafes searchResultAtIndex:index]);
|
||||
break;
|
||||
case ItemType::Hotels:
|
||||
getRoutePointInfo([self.viewModel.hotels searchResultAtIndex:index]);
|
||||
break;
|
||||
case ItemType::Promo:
|
||||
case ItemType::LocalExperts:
|
||||
return;
|
||||
}
|
||||
|
||||
MWMRoutePoint * pt = [[MWMRoutePoint alloc] initWithPoint:point
|
||||
|
@ -283,22 +297,56 @@ struct Callback
|
|||
[MWMRouter buildToPoint:pt bestRouter:NO];
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
|
||||
[Statistics logEvent:kStatPlacepageSponsoredItemSelected
|
||||
withParameters:@{
|
||||
kStatProvider: StatProvider(type),
|
||||
kStatPlacement: kStatDiscovery,
|
||||
kStatItem: @(index + 1),
|
||||
kStatDestination: kStatRouting
|
||||
}];
|
||||
[self logEvent:kStatPlacepageSponsoredItemSelected
|
||||
type:type
|
||||
index:index
|
||||
destination:kStatRouting];
|
||||
}
|
||||
|
||||
- (void)openURLForItem:(discovery::ItemType const)type
|
||||
{
|
||||
CHECK(type == ItemType::LocalExperts,
|
||||
("Attempt to open url for item with type:", static_cast<int>(type)));
|
||||
auto & f = GetFramework();
|
||||
auto const url = f.GetDiscoveryLocalExpertsUrl();
|
||||
[self openUrl:[NSURL URLWithString:@(url.c_str())]];
|
||||
- (void)openURLForItem:(ItemType const)type atIndex:(NSInteger)index {
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
case ItemType::Hotels:
|
||||
case ItemType::LocalExperts:
|
||||
break;
|
||||
case ItemType::Promo:
|
||||
auto bookmarks = [[MWMBookmarksTabViewController alloc] init];
|
||||
bookmarks.activeTab = ActiveTabCatalog;
|
||||
promo::CityGallery::Item const &item = [self.viewModel.guides galleryItemAtIndex:index];
|
||||
NSString *itemPath = @(item.m_url.c_str());
|
||||
if (!itemPath || itemPath.length == 0) {
|
||||
return;
|
||||
}
|
||||
MWMCatalogWebViewController *catalog = [[MWMCatalogWebViewController alloc] init:[NSURL URLWithString:itemPath]];
|
||||
NSMutableArray<UIViewController *> * controllers = [self.navigationController.viewControllers mutableCopy];
|
||||
[controllers addObjectsFromArray:@[bookmarks, catalog]];
|
||||
[self.navigationController setViewControllers:controllers animated:YES];
|
||||
[self logEvent:kStatPlacepageSponsoredItemSelected
|
||||
type:type
|
||||
index:index
|
||||
destination:kStatExternal];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openURLForItem:(ItemType const)type {
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
case ItemType::Hotels:
|
||||
case ItemType::LocalExperts:
|
||||
break;
|
||||
case ItemType::Promo:
|
||||
auto bookmarks = [[MWMBookmarksTabViewController alloc] init];
|
||||
bookmarks.activeTab = ActiveTabCatalog;
|
||||
NSURL *url = [self.viewModel.guides moreURL];
|
||||
MWMCatalogWebViewController *catalog = [[MWMCatalogWebViewController alloc] init:url];
|
||||
NSMutableArray<UIViewController *> * controllers = [self.navigationController.viewControllers mutableCopy];
|
||||
[controllers addObjectsFromArray:@[bookmarks, catalog]];
|
||||
[self.navigationController setViewControllers:controllers animated:YES];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
23
iphone/Maps/UI/Discovery/MWMDiscoveryMapObjects.h
Normal file
23
iphone/Maps/UI/Discovery/MWMDiscoveryMapObjects.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "map/search_product_info.hpp"
|
||||
|
||||
#include "search/result.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MWMDiscoveryMapObjects : NSObject
|
||||
|
||||
- (instancetype)initWithSearchResults:(search::Results const &)results
|
||||
productInfos:(std::vector<search::ProductInfo> const &)productInfos
|
||||
viewPortCenter:(m2::PointD const &)viewportCenter;
|
||||
- (search::Result const &)searchResultAtIndex:(NSUInteger)index;
|
||||
- (search::ProductInfo const &)productInfoAtIndex:(NSUInteger)index;
|
||||
- (m2::PointD const &)viewPortCenter;
|
||||
- (NSUInteger)count;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
43
iphone/Maps/UI/Discovery/MWMDiscoveryMapObjects.mm
Normal file
43
iphone/Maps/UI/Discovery/MWMDiscoveryMapObjects.mm
Normal file
|
@ -0,0 +1,43 @@
|
|||
#import "MWMDiscoveryMapObjects.h"
|
||||
|
||||
@interface MWMDiscoveryMapObjects() {
|
||||
search::Results m_results;
|
||||
std::vector<search::ProductInfo> m_productInfos;
|
||||
m2::PointD m_viewportCenter;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryMapObjects
|
||||
|
||||
- (instancetype)initWithSearchResults:(search::Results const &)results
|
||||
productInfos:(std::vector<search::ProductInfo> const &)productInfos
|
||||
viewPortCenter:(m2::PointD const &)viewportCenter {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
m_results = results;
|
||||
m_productInfos = productInfos;
|
||||
m_viewportCenter = viewportCenter;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (search::Result const &)searchResultAtIndex:(NSUInteger)index {
|
||||
CHECK_LESS(index, m_results.GetCount(), ("Incorrect index:", index));
|
||||
return m_results[index];
|
||||
}
|
||||
|
||||
- (search::ProductInfo const &)productInfoAtIndex:(NSUInteger)index {
|
||||
CHECK_LESS(index, m_productInfos.size(), ("Incorrect index:", index));
|
||||
return m_productInfos[index];
|
||||
}
|
||||
|
||||
- (m2::PointD const &)viewPortCenter {
|
||||
return m_viewportCenter;
|
||||
}
|
||||
|
||||
- (NSUInteger)count {
|
||||
return m_results.GetCount();
|
||||
}
|
||||
|
||||
@end
|
|
@ -5,20 +5,21 @@
|
|||
|
||||
namespace discovery
|
||||
{
|
||||
class DiscoveryControllerViewModel;
|
||||
|
||||
NSString * StatProvider(ItemType const type);
|
||||
} // namespace discovery
|
||||
|
||||
using GetModelCallback = std::function<discovery::DiscoveryControllerViewModel const &()>;
|
||||
@class MWMDiscoveryControllerViewModel;
|
||||
|
||||
typedef MWMDiscoveryControllerViewModel *(^MWMGetModelCallback)(void);
|
||||
|
||||
@protocol MWMDiscoveryTapDelegate;
|
||||
|
||||
@interface MWMDiscoveryTableManager : NSObject
|
||||
|
||||
- (instancetype)initWithTableView:(UITableView *)tableView
|
||||
canUseNetwork:(BOOL)canUseNetwork
|
||||
delegate:(id<MWMDiscoveryTapDelegate>)delegate
|
||||
model:(GetModelCallback &&)modelCallback;
|
||||
model:(MWMGetModelCallback)modelCallback;
|
||||
|
||||
- (void)loadItems:(std::vector<discovery::ItemType> const &)types;
|
||||
- (void)reloadItem:(discovery::ItemType const)type;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#import "MWMDiscoveryTableManager.h"
|
||||
#import "MWMDiscoveryTapDelegate.h"
|
||||
#import "MWMDiscoveryControllerViewModel.h"
|
||||
#import "MWMDiscoveryHotelViewModel.h"
|
||||
#import "MWMDiscoverySearchViewModel.h"
|
||||
#import "MWMDiscoveryGuideViewModel.h"
|
||||
#import "Statistics.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
#include "DiscoveryControllerViewModel.hpp"
|
||||
|
||||
#include "map/place_page_info.hpp"
|
||||
|
||||
#include "partners_api/locals_api.hpp"
|
||||
|
@ -32,41 +34,18 @@ namespace discovery
|
|||
{
|
||||
NSString * StatProvider(ItemType const type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::LocalExperts: return kStatLocalsProvider;
|
||||
case ItemType::Attractions: return kStatSearchAttractions;
|
||||
case ItemType::Cafes: return kStatSearchRestaurants;
|
||||
case ItemType::Hotels: return kStatBooking;
|
||||
// TODO: Add correct stat key here.
|
||||
case ItemType::Promo: return @"";
|
||||
switch (type) {
|
||||
case ItemType::Attractions: return kStatSearchAttractions;
|
||||
case ItemType::Cafes: return kStatSearchRestaurants;
|
||||
case ItemType::Hotels: return kStatBooking;
|
||||
case ItemType::Promo: return kStatMapsmeGuides;
|
||||
case ItemType::LocalExperts: return @"";
|
||||
}
|
||||
}
|
||||
|
||||
pair<NSString *, MWMRatingSummaryViewValueType> FormattedRating(float const rawValue)
|
||||
{
|
||||
auto const str = place_page::rating::GetRatingFormatted(rawValue);
|
||||
auto const impress = static_cast<MWMRatingSummaryViewValueType>(place_page::rating::GetImpress(rawValue));
|
||||
return {@(str.c_str()), impress};
|
||||
};
|
||||
} // namespace discovery
|
||||
|
||||
using namespace discovery;
|
||||
|
||||
namespace
|
||||
{
|
||||
auto const kDefaultRowAnimation = UITableViewRowAnimationFade;
|
||||
|
||||
string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
||||
{
|
||||
string distance;
|
||||
auto const f = MercatorBounds::ToLatLon(from);
|
||||
auto const t = MercatorBounds::ToLatLon(to);
|
||||
measurement_utils::FormatDistance(ms::DistanceOnEarth(f.m_lat, f.m_lon, t.m_lat, t.m_lon), distance);
|
||||
return distance;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@interface MWMDiscoveryCollectionView : UICollectionView
|
||||
@property(nonatomic) ItemType itemType;
|
||||
@end
|
||||
|
@ -83,8 +62,9 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
}
|
||||
|
||||
@property(weak, nonatomic) UITableView * tableView;
|
||||
@property(nonatomic) GetModelCallback model;
|
||||
@property(nonatomic) MWMGetModelCallback model;
|
||||
@property(weak, nonatomic) id<MWMDiscoveryTapDelegate> delegate;
|
||||
@property(nonatomic) BOOL canUseNetwork;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -93,15 +73,15 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
#pragma mark - Public
|
||||
|
||||
- (instancetype)initWithTableView:(UITableView *)tableView
|
||||
canUseNetwork:(BOOL)canUseNetwork
|
||||
delegate:(id<MWMDiscoveryTapDelegate>)delegate
|
||||
model:(GetModelCallback &&)modelCallback
|
||||
{
|
||||
model:(MWMGetModelCallback)modelCallback {
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
if (self) {
|
||||
_tableView = tableView;
|
||||
_delegate = delegate;
|
||||
_model = move(modelCallback);
|
||||
_model = modelCallback;
|
||||
_canUseNetwork = canUseNetwork;
|
||||
tableView.dataSource = self;
|
||||
tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
tableView.estimatedRowHeight = 218;
|
||||
|
@ -112,28 +92,29 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)loadItems:(vector<ItemType> const &)types
|
||||
{
|
||||
- (MWMDiscoveryControllerViewModel *)viewModel {
|
||||
return self.model();
|
||||
}
|
||||
|
||||
- (void)loadItems:(vector<ItemType> const &)types {
|
||||
m_types = types;
|
||||
m_loadingTypes = types;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)reloadItem:(ItemType const)type
|
||||
{
|
||||
if (self.model().GetItemsCount(type) == 0)
|
||||
{
|
||||
- (void)reloadItem:(ItemType const)type {
|
||||
if ([self.viewModel itemsCountForType:type] == 0) {
|
||||
[self removeItem:type];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type),
|
||||
m_loadingTypes.end());
|
||||
m_failedTypes.erase(remove(m_failedTypes.begin(), m_failedTypes.end(), type),
|
||||
m_failedTypes.end());
|
||||
auto const position = [self position:type];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:position]]
|
||||
withRowAnimation:kDefaultRowAnimation];
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type), m_loadingTypes.end());
|
||||
m_failedTypes.erase(remove(m_failedTypes.begin(), m_failedTypes.end(), type), m_failedTypes.end());
|
||||
|
||||
NSInteger position = [self position:type];
|
||||
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:position]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
||||
[Statistics logEvent:kStatPlacepageSponsoredShow
|
||||
withParameters:@{
|
||||
|
@ -143,77 +124,68 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)errorAtItem:(ItemType const)type
|
||||
{
|
||||
CHECK(type == ItemType::LocalExperts,
|
||||
- (void)errorAtItem:(ItemType const)type {
|
||||
CHECK(type == ItemType::Promo,
|
||||
("Error on item with type:", static_cast<int>(type)));
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type),
|
||||
m_loadingTypes.end());
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type), m_loadingTypes.end());
|
||||
m_failedTypes.push_back(type);
|
||||
auto const position = [self position:type];
|
||||
NSInteger position = [self position:type];
|
||||
|
||||
[Statistics logEvent:kStatPlacepageSponsoredError
|
||||
withParameters:@{kStatProvider: StatProvider(type), kStatPlacement: kStatDiscovery}];
|
||||
withParameters:@{kStatProvider: StatProvider(type),
|
||||
kStatPlacement: kStatDiscovery}];
|
||||
|
||||
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:position]
|
||||
withRowAnimation:kDefaultRowAnimation];
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (BOOL)hasOnlineSections
|
||||
{
|
||||
return find(m_types.begin(), m_types.end(), ItemType::LocalExperts) != m_types.end();
|
||||
- (BOOL)hasOnlineSections {
|
||||
return find(m_types.begin(), m_types.end(), ItemType::Promo) != m_types.end();
|
||||
}
|
||||
|
||||
- (void)removeItem:(ItemType const)type
|
||||
{
|
||||
auto const position = [self position:type];
|
||||
- (void)removeItem:(ItemType const)type {
|
||||
NSInteger position = [self position:type];
|
||||
m_types.erase(remove(m_types.begin(), m_types.end(), type), m_types.end());
|
||||
m_failedTypes.erase(remove(m_failedTypes.begin(), m_failedTypes.end(), type),
|
||||
m_failedTypes.end());
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type),
|
||||
m_loadingTypes.end());
|
||||
m_failedTypes.erase(remove(m_failedTypes.begin(), m_failedTypes.end(), type), m_failedTypes.end());
|
||||
m_loadingTypes.erase(remove(m_loadingTypes.begin(), m_loadingTypes.end(), type), m_loadingTypes.end());
|
||||
|
||||
auto indexSet = [NSIndexSet indexSetWithIndex:position];
|
||||
auto tv = self.tableView;
|
||||
if (m_types.empty())
|
||||
[tv reloadSections:indexSet withRowAnimation:kDefaultRowAnimation];
|
||||
[tv reloadData];
|
||||
else
|
||||
[tv deleteSections:indexSet withRowAnimation:kDefaultRowAnimation];
|
||||
[tv deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
|
||||
- (void)registerCells
|
||||
{
|
||||
- (void)registerCells {
|
||||
auto tv = self.tableView;
|
||||
[tv registerWithCellClass:[MWMDiscoverySpinnerCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoveryOnlineTemplateCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoverySearchCollectionHolderCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoveryLocalExpertCollectionHolderCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoveryGuideCollectionHolderCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoveryBookingCollectionHolderCell class]];
|
||||
[tv registerWithCellClass:[MWMDiscoveryNoResultsCell class]];
|
||||
}
|
||||
|
||||
- (NSInteger)position:(ItemType const)type
|
||||
{
|
||||
- (NSInteger)position:(ItemType const)type {
|
||||
auto const it = find(m_types.begin(), m_types.end(), type);
|
||||
if (it == m_types.end())
|
||||
CHECK(false, ("Incorrect item type:", static_cast<int>(type)));
|
||||
|
||||
|
||||
return distance(m_types.begin(), it);
|
||||
}
|
||||
|
||||
- (MWMDiscoverySearchCollectionHolderCell *)searchCollectionHolderCell:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (MWMDiscoverySearchCollectionHolderCell *)searchCollectionHolderCell:(NSIndexPath *)indexPath {
|
||||
Class cls = [MWMDiscoverySearchCollectionHolderCell class];
|
||||
auto const type = m_types[indexPath.section];
|
||||
auto cell = static_cast<MWMDiscoverySearchCollectionHolderCell *>(
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto collection = static_cast<MWMDiscoveryCollectionView *>(cell.collectionView);
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::Attractions: [cell configAttractionsCell]; break;
|
||||
case ItemType::Cafes: [cell configCafesCell]; break;
|
||||
ItemType const type = m_types[indexPath.section];
|
||||
MWMDiscoverySearchCollectionHolderCell *cell = (MWMDiscoverySearchCollectionHolderCell *)
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoveryCollectionView *collection = (MWMDiscoveryCollectionView *)cell.collectionView;
|
||||
switch (type) {
|
||||
case ItemType::Attractions: [cell configAttractionsCell]; break;
|
||||
case ItemType::Cafes: [cell configCafesCell]; break;
|
||||
default: NSAssert(false, @""); return nil;
|
||||
}
|
||||
collection.delegate = self;
|
||||
|
@ -222,26 +194,11 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
return cell;
|
||||
}
|
||||
|
||||
- (MWMDiscoveryLocalExpertCollectionHolderCell *)localExpertsCollectionHolderCell:
|
||||
(NSIndexPath *)indexPath
|
||||
{
|
||||
Class cls = [MWMDiscoveryLocalExpertCollectionHolderCell class];
|
||||
auto cell = static_cast<MWMDiscoveryLocalExpertCollectionHolderCell *>(
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto collection = static_cast<MWMDiscoveryCollectionView *>(cell.collectionView);
|
||||
[cell config];
|
||||
collection.delegate = self;
|
||||
collection.dataSource = self;
|
||||
collection.itemType = ItemType::LocalExperts;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (MWMDiscoveryBookingCollectionHolderCell *)bookingCollectionHolderCell:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (MWMDiscoveryBookingCollectionHolderCell *)bookingCollectionHolderCell:(NSIndexPath *)indexPath {
|
||||
Class cls = [MWMDiscoveryBookingCollectionHolderCell class];
|
||||
auto cell = static_cast<MWMDiscoveryBookingCollectionHolderCell *>(
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto collection = static_cast<MWMDiscoveryCollectionView *>(cell.collectionView);
|
||||
MWMDiscoveryBookingCollectionHolderCell *cell = (MWMDiscoveryBookingCollectionHolderCell *)
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoveryCollectionView *collection = (MWMDiscoveryCollectionView *)cell.collectionView;
|
||||
[cell config];
|
||||
collection.delegate = self;
|
||||
collection.dataSource = self;
|
||||
|
@ -249,69 +206,87 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
return cell;
|
||||
}
|
||||
|
||||
- (MWMDiscoveryGuideCollectionHolderCell *)guideCollectionHolderCell:(NSIndexPath *)indexPath {
|
||||
Class cls = [MWMDiscoveryGuideCollectionHolderCell class];
|
||||
MWMDiscoveryGuideCollectionHolderCell *cell = (MWMDiscoveryGuideCollectionHolderCell *)
|
||||
[self.tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoveryCollectionView *collection = (MWMDiscoveryCollectionView *)cell.collectionView;
|
||||
[cell config];
|
||||
collection.delegate = self;
|
||||
collection.dataSource = self;
|
||||
collection.itemType = ItemType::Promo;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (MWMDiscoverySpinnerCell *)spinnerCell:(NSIndexPath *)indexPath {
|
||||
Class cls = [MWMDiscoverySpinnerCell class];
|
||||
return (MWMDiscoverySpinnerCell *)[self.tableView dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath];
|
||||
}
|
||||
|
||||
- (MWMDiscoveryOnlineTemplateCell *)onlineTemplateCell:(NSIndexPath *)indexPath {
|
||||
Class cls = [MWMDiscoveryOnlineTemplateCell class];
|
||||
return (MWMDiscoveryOnlineTemplateCell *)[self.tableView dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
auto constexpr kNumberOfRows = 1;
|
||||
return kNumberOfRows;
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return static_cast<NSInteger>(MAX(m_types.size(), 1));
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (m_types.empty()) {
|
||||
return 1;
|
||||
}
|
||||
ItemType const type = m_types[section];
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
case ItemType::Hotels:
|
||||
case ItemType::Promo:
|
||||
return 1;
|
||||
case ItemType::LocalExperts:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView
|
||||
cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (m_types.empty())
|
||||
{
|
||||
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (m_types.empty()) {
|
||||
Class cls = [MWMDiscoveryNoResultsCell class];
|
||||
return static_cast<MWMDiscoveryNoResultsCell *>(
|
||||
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
return (MWMDiscoveryNoResultsCell *)[tableView dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath];
|
||||
}
|
||||
|
||||
ItemType const type = m_types[indexPath.section];
|
||||
BOOL isFailed = find(m_failedTypes.begin(), m_failedTypes.end(), type) != m_failedTypes.end();
|
||||
BOOL isLoading = find(m_loadingTypes.begin(), m_loadingTypes.end(), type) != m_loadingTypes.end();
|
||||
|
||||
auto const type = m_types[indexPath.section];
|
||||
bool const isFailed =
|
||||
find(m_failedTypes.begin(), m_failedTypes.end(), type) != m_failedTypes.end();
|
||||
bool const isLoading =
|
||||
find(m_loadingTypes.begin(), m_loadingTypes.end(), type) != m_loadingTypes.end();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::LocalExperts:
|
||||
{
|
||||
if (isLoading || isFailed)
|
||||
{
|
||||
Class cls = [MWMDiscoveryOnlineTemplateCell class];
|
||||
auto cell = static_cast<MWMDiscoveryOnlineTemplateCell *>(
|
||||
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
[cell configWithType:MWMDiscoveryOnlineTemplateTypeLocals
|
||||
needSpinner:isLoading
|
||||
tap:^{
|
||||
[self.delegate openURLForItem:type];
|
||||
}];
|
||||
return cell;
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
return isLoading ? [self spinnerCell:indexPath] : [self searchCollectionHolderCell:indexPath];
|
||||
case ItemType::Hotels:
|
||||
return isLoading ? [self spinnerCell:indexPath] : [self bookingCollectionHolderCell:indexPath];
|
||||
case ItemType::Promo: {
|
||||
if (isLoading || isFailed) {
|
||||
MWMDiscoveryOnlineTemplateCell *cell = [self onlineTemplateCell:indexPath];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[cell configWithType:MWMDiscoveryOnlineTemplateTypePromo
|
||||
needSpinner:isLoading
|
||||
canUseNetwork: self.canUseNetwork
|
||||
tap:^{
|
||||
[weakSelf.delegate openURLForItem:type];
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
return [self guideCollectionHolderCell: indexPath];
|
||||
}
|
||||
return [self localExpertsCollectionHolderCell:indexPath];
|
||||
case ItemType::LocalExperts:
|
||||
return [[UITableViewCell alloc] init];
|
||||
}
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
{
|
||||
if (isLoading)
|
||||
{
|
||||
Class cls = [MWMDiscoverySpinnerCell class];
|
||||
auto cell = static_cast<MWMDiscoverySpinnerCell *>(
|
||||
[tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
return cell;
|
||||
}
|
||||
return [self searchCollectionHolderCell:indexPath];
|
||||
}
|
||||
case ItemType::Hotels: return [self bookingCollectionHolderCell:indexPath];
|
||||
// TODO: Add correct value here.
|
||||
case ItemType::Promo: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return static_cast<NSInteger>(MAX(m_types.size(), 1));
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegate
|
||||
|
@ -327,137 +302,76 @@ string GetDistance(m2::PointD const & from, m2::PointD const & to)
|
|||
- (NSInteger)collectionView:(MWMDiscoveryCollectionView *)collectionView
|
||||
numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
auto const count = self.model().GetItemsCount(collectionView.itemType);
|
||||
NSInteger count = [self.viewModel itemsCountForType:collectionView.itemType];
|
||||
return count > 0 ? count + 1 : 0;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(MWMDiscoveryCollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
auto const type = collectionView.itemType;
|
||||
auto const & model = self.model();
|
||||
NSString * ratingValue;
|
||||
MWMRatingSummaryViewValueType ratingType;
|
||||
switch (type)
|
||||
{
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes:
|
||||
{
|
||||
if (indexPath.row == model.GetItemsCount(type))
|
||||
{
|
||||
Class cls = [MWMDiscoveryMoreCell class];
|
||||
auto cell = static_cast<MWMDiscoveryMoreCell *>([collectionView
|
||||
dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath]);
|
||||
return cell;
|
||||
}
|
||||
Class cls = [MWMDiscoverySearchCell class];
|
||||
auto cell = static_cast<MWMDiscoverySearchCell *>(
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto const & sr = type == ItemType::Attractions ? model.GetAttractionAt(indexPath.row)
|
||||
: model.GetCafeAt(indexPath.row);
|
||||
auto const & pt = type == ItemType::Attractions ? model.GetAttractionReferencePoint()
|
||||
: model.GetCafeReferencePoint();
|
||||
auto const & pi = type == ItemType::Attractions ? model.GetAttractionProductInfoAt(indexPath.row)
|
||||
: model.GetCafeProductInfoAt(indexPath.row);
|
||||
tie(ratingValue, ratingType) = FormattedRating(pi.m_ugcRating);
|
||||
|
||||
auto const readableType = classif().GetReadableObjectName(sr.GetFeatureType());
|
||||
auto const subtitle = platform::GetLocalizedTypeName(readableType);
|
||||
|
||||
[cell configWithTitle:sr.GetString().empty() ? @(subtitle.c_str()) : @(sr.GetString().c_str())
|
||||
subtitle:@(subtitle.c_str())
|
||||
distance:@(GetDistance(pt, sr.GetFeatureCenter()).c_str())
|
||||
popular:sr.GetRankingInfo().m_popularity > 0
|
||||
ratingValue:ratingValue
|
||||
ratingType:ratingType
|
||||
tap:^{
|
||||
[self.delegate routeToItem:type atIndex:indexPath.row];
|
||||
}];
|
||||
ItemType const type = collectionView.itemType;
|
||||
|
||||
if (indexPath.row == [self.viewModel itemsCountForType:type]) {
|
||||
Class cls = [MWMDiscoveryMoreCell class];
|
||||
MWMDiscoveryMoreCell *cell = (MWMDiscoveryMoreCell *)[collectionView
|
||||
dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath];
|
||||
return cell;
|
||||
}
|
||||
case ItemType::LocalExperts:
|
||||
{
|
||||
if (indexPath.row == model.GetItemsCount(type))
|
||||
{
|
||||
Class cls = [MWMDiscoveryMoreCell class];
|
||||
auto cell = static_cast<MWMDiscoveryMoreCell *>([collectionView
|
||||
dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath]);
|
||||
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
case ItemType::Cafes: {
|
||||
Class cls = [MWMDiscoverySearchCell class];
|
||||
MWMDiscoverySearchCell *cell = (MWMDiscoverySearchCell *)
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoverySearchViewModel *objectVM = type == ItemType::Attractions ? [self.viewModel attractionAtIndex:indexPath.item] : [self.viewModel cafeAtIndex:indexPath.item];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[cell configWithTitle:objectVM.title
|
||||
subtitle:objectVM.subtitle
|
||||
distance:objectVM.distance
|
||||
popular:objectVM.isPopular
|
||||
ratingValue:objectVM.ratingValue
|
||||
ratingType:objectVM.ratingType
|
||||
tap:^{
|
||||
[weakSelf.delegate routeToItem:type atIndex:indexPath.row];
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
|
||||
Class cls = [MWMDiscoveryLocalExpertCell class];
|
||||
auto cell = static_cast<MWMDiscoveryLocalExpertCell *>(
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto const & expert = model.GetExpertAt(indexPath.row);
|
||||
tie(ratingValue, ratingType) = FormattedRating(expert.m_rating);
|
||||
|
||||
[cell configWithAvatarURL:@(expert.m_photoUrl.c_str())
|
||||
name:@(expert.m_name.c_str())
|
||||
ratingValue:ratingValue
|
||||
ratingType:ratingType
|
||||
price:expert.m_pricePerHour
|
||||
currency:@(expert.m_currency.c_str())
|
||||
tap:^{
|
||||
[self.delegate tapOnItem:type atIndex:indexPath.row];
|
||||
case ItemType::Hotels: {
|
||||
Class cls = [MWMDiscoveryBookingCell class];
|
||||
MWMDiscoveryBookingCell *cell = (MWMDiscoveryBookingCell *)
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoveryHotelViewModel *objectVM = [self.viewModel hotelAtIndex:indexPath.item];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[cell configWithAvatarURL:nil
|
||||
title:objectVM.title
|
||||
subtitle:objectVM.subtitle
|
||||
price:objectVM.price
|
||||
ratingValue:objectVM.ratingValue
|
||||
ratingType:objectVM.ratingType
|
||||
distance:objectVM.distance
|
||||
onBuildRoute:^{
|
||||
[weakSelf.delegate routeToItem:type atIndex:indexPath.row];
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
case ItemType::Promo: {
|
||||
Class cls = [MWMDiscoveryGuideCell class];
|
||||
MWMDiscoveryGuideCell *cell = (MWMDiscoveryGuideCell *)
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
|
||||
MWMDiscoveryGuideViewModel *objectVM = [self.viewModel guideAtIndex:indexPath.item];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[cell configWithAvatarURL:objectVM.imagePath
|
||||
title:objectVM.title
|
||||
subtitle:objectVM.subtitle
|
||||
label:objectVM.label onDetails:^{
|
||||
[weakSelf.delegate openURLForItem:ItemType::Promo atIndex:indexPath.row];
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
case ItemType::Hotels:
|
||||
{
|
||||
if (indexPath.row == model.GetItemsCount(type))
|
||||
{
|
||||
Class cls = [MWMDiscoveryMoreCell class];
|
||||
auto cell = static_cast<MWMDiscoveryMoreCell *>([collectionView
|
||||
dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath]);
|
||||
return cell;
|
||||
}
|
||||
|
||||
Class cls = [MWMDiscoveryBookingCell class];
|
||||
auto cell = static_cast<MWMDiscoveryBookingCell *>(
|
||||
[collectionView dequeueReusableCellWithCellClass:cls indexPath:indexPath]);
|
||||
auto const & sr = model.GetHotelAt(indexPath.row);
|
||||
auto const & pt = model.GetHotelReferencePoint();
|
||||
|
||||
NSMutableString * subtitle = nil;
|
||||
auto starsCount = sr.GetStarsCount();
|
||||
if (starsCount == 0)
|
||||
{
|
||||
auto const readableType = classif().GetReadableObjectName(sr.GetFeatureType());
|
||||
subtitle = [@(platform::GetLocalizedTypeName(readableType).c_str()) mutableCopy];
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitle = [@"" mutableCopy];
|
||||
for (int i = 0; i < starsCount; ++i)
|
||||
[subtitle appendString:@"★"];
|
||||
}
|
||||
|
||||
tie(ratingValue, ratingType) = FormattedRating(sr.GetHotelRating());
|
||||
|
||||
[cell configWithAvatarURL:nil
|
||||
title:sr.GetString().empty() ? [subtitle copy] : @(sr.GetString().c_str())
|
||||
subtitle:[subtitle copy]
|
||||
price:@(sr.GetHotelApproximatePricing().c_str())
|
||||
ratingValue:ratingValue
|
||||
ratingType:ratingType
|
||||
distance:@(GetDistance(pt, sr.GetFeatureCenter()).c_str())
|
||||
onBuildRoute:^{
|
||||
[self.delegate routeToItem:type atIndex:indexPath.row];
|
||||
}];
|
||||
return cell;
|
||||
}
|
||||
case ItemType::Promo:
|
||||
{
|
||||
// TODO: Add correct implementation here.
|
||||
auto cls = [MWMDiscoveryMoreCell class];
|
||||
auto cell = static_cast<MWMDiscoveryMoreCell *>([collectionView
|
||||
dequeueReusableCellWithCellClass:cls
|
||||
indexPath:indexPath]);
|
||||
return cell;
|
||||
}
|
||||
case ItemType::LocalExperts:
|
||||
return [[UICollectionViewCell alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
@protocol MWMDiscoveryTapDelegate<NSObject>
|
||||
|
||||
- (void)tapOnItem:(discovery::ItemType const)type atIndex:(size_t const)index;
|
||||
- (void)routeToItem:(discovery::ItemType const)type atIndex:(size_t const)index;
|
||||
- (void)tapOnItem:(discovery::ItemType const)type atIndex:(NSInteger)index;
|
||||
- (void)routeToItem:(discovery::ItemType const)type atIndex:(NSInteger)index;
|
||||
- (void)openURLForItem:(discovery::ItemType const)type atIndex:(NSInteger)index;
|
||||
- (void)openURLForItem:(discovery::ItemType const)type;
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
@objc(MWMDiscoveryOnlineTemplateType)
|
||||
enum DiscoveryOnlineTemplateType: Int {
|
||||
case promo
|
||||
}
|
||||
|
||||
@objc(MWMDiscoveryOnlineTemplateCell)
|
||||
final class DiscoveryOnlineTemplateCell: MWMTableViewCell {
|
||||
@IBOutlet var spinner: UIImageView! {
|
||||
didSet {
|
||||
let postfix = UIColor.isNightMode() ? "_dark" : "_light"
|
||||
spinner.image = UIImage(named: "Spinner" + postfix)
|
||||
spinner.startRotation()
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var containerView: UIView! {
|
||||
didSet {
|
||||
containerView.layer.cornerRadius = 6.0
|
||||
containerView.layer.borderWidth = 1.0
|
||||
containerView.layer.borderColor = UIColor.blackDividers()?.cgColor
|
||||
}
|
||||
}
|
||||
@IBOutlet var header: UILabel!
|
||||
@IBOutlet var title: UILabel!
|
||||
@IBOutlet var subtitle: UILabel!
|
||||
@IBOutlet var actionButton: UIButton!
|
||||
|
||||
typealias Tap = () -> ()
|
||||
private var tap: Tap?
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
spinner.isHidden = true
|
||||
spinner.stopRotation()
|
||||
}
|
||||
|
||||
@objc func config(type: DiscoveryOnlineTemplateType, needSpinner: Bool, canUseNetwork: Bool, tap: @escaping Tap) {
|
||||
switch type {
|
||||
case .promo:
|
||||
header.text = L("gallery_pp_download_guides_title").uppercased()
|
||||
title.text = L("gallery_pp_download_guides_offline_title")
|
||||
subtitle.text = L("gallery_pp_download_guides_offline_subtitle")
|
||||
if canUseNetwork {
|
||||
actionButton.setTitle(L("details"),
|
||||
for: .normal)
|
||||
} else {
|
||||
actionButton.setTitle(L("gallery_pp_download_guides_offline_cta"),
|
||||
for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
if (needSpinner) {
|
||||
spinner.isHidden = false
|
||||
spinner.startRotation()
|
||||
}
|
||||
self.tap = tap
|
||||
}
|
||||
|
||||
@IBAction private func onTap() {
|
||||
tap?()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="DiscoveryOnlineTemplateCell" rowHeight="266" id="9IM-3s-P1U" customClass="MWMDiscoveryOnlineTemplateCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="266"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="9IM-3s-P1U" id="RFj-It-lNu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="265.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QHe-qU-OhV">
|
||||
<rect key="frame" x="8" y="44" width="359" height="221.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UMh-FO-rZJ">
|
||||
<rect key="frame" x="20" y="79" width="319" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="XSe-2e-PrA"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium14"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Jk-er-UUa">
|
||||
<rect key="frame" x="20" y="99" width="319" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dCP-Yu-fFz">
|
||||
<rect key="frame" x="167.5" y="47" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="JmM-dN-DAf"/>
|
||||
<constraint firstAttribute="height" constant="24" id="RP9-kK-iAl"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WoO-mw-61q">
|
||||
<rect key="frame" x="0.0" y="181.5" width="359" height="40"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.040000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="JKj-h8-ljn"/>
|
||||
</constraints>
|
||||
<state key="normal" title="DETAILS"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="details"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="onTap" destination="9IM-3s-P1U" eventType="touchUpInside" id="wGN-bL-0IS"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="UMh-FO-rZJ" secondAttribute="trailing" constant="20" id="EhK-cf-zIl"/>
|
||||
<constraint firstItem="WoO-mw-61q" firstAttribute="top" secondItem="4Jk-er-UUa" secondAttribute="bottom" constant="62" id="KuK-fw-2Rl"/>
|
||||
<constraint firstItem="4Jk-er-UUa" firstAttribute="top" secondItem="UMh-FO-rZJ" secondAttribute="bottom" constant="4" id="OO0-G5-dtz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WoO-mw-61q" secondAttribute="trailing" id="TPX-ju-dpb"/>
|
||||
<constraint firstItem="UMh-FO-rZJ" firstAttribute="top" secondItem="dCP-Yu-fFz" secondAttribute="bottom" constant="8" id="V6Z-td-GYY"/>
|
||||
<constraint firstAttribute="bottom" secondItem="WoO-mw-61q" secondAttribute="bottom" id="VtK-N5-abK"/>
|
||||
<constraint firstItem="UMh-FO-rZJ" firstAttribute="leading" secondItem="QHe-qU-OhV" secondAttribute="leading" constant="20" id="Xj3-co-r3p"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4Jk-er-UUa" secondAttribute="trailing" constant="20" id="ZpC-EO-4eh"/>
|
||||
<constraint firstItem="4Jk-er-UUa" firstAttribute="leading" secondItem="QHe-qU-OhV" secondAttribute="leading" constant="20" id="evP-bA-hNa"/>
|
||||
<constraint firstItem="dCP-Yu-fFz" firstAttribute="top" secondItem="QHe-qU-OhV" secondAttribute="top" constant="47" id="uSN-xL-tc6"/>
|
||||
<constraint firstItem="WoO-mw-61q" firstAttribute="leading" secondItem="QHe-qU-OhV" secondAttribute="leading" id="xdU-9j-1oK"/>
|
||||
<constraint firstItem="dCP-Yu-fFz" firstAttribute="centerX" secondItem="QHe-qU-OhV" secondAttribute="centerX" id="y66-M2-Vf5"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="jpF-nO-kZW"/>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t7L-Pc-YZX">
|
||||
<rect key="frame" x="16" y="12" width="347" height="20"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium14"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="t7L-Pc-YZX" firstAttribute="leading" secondItem="RFj-It-lNu" secondAttribute="leading" constant="16" id="7Rf-Gu-Wi8"/>
|
||||
<constraint firstAttribute="trailing" secondItem="t7L-Pc-YZX" secondAttribute="trailing" constant="12" id="8Tr-Aa-zs5"/>
|
||||
<constraint firstAttribute="trailing" secondItem="QHe-qU-OhV" secondAttribute="trailing" constant="8" id="QPQ-SE-hkT"/>
|
||||
<constraint firstItem="QHe-qU-OhV" firstAttribute="leading" secondItem="RFj-It-lNu" secondAttribute="leading" constant="8" id="TrD-vm-3uZ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="QHe-qU-OhV" secondAttribute="bottom" id="oan-1Y-uuz"/>
|
||||
<constraint firstItem="QHe-qU-OhV" firstAttribute="top" secondItem="t7L-Pc-YZX" secondAttribute="bottom" constant="12" id="pKH-cU-c4t"/>
|
||||
<constraint firstItem="t7L-Pc-YZX" firstAttribute="top" secondItem="RFj-It-lNu" secondAttribute="top" constant="12" id="xTp-3J-4fU"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="actionButton" destination="WoO-mw-61q" id="uVo-Xb-CnX"/>
|
||||
<outlet property="containerView" destination="QHe-qU-OhV" id="jlb-3b-Nms"/>
|
||||
<outlet property="header" destination="t7L-Pc-YZX" id="zw1-e1-mc1"/>
|
||||
<outlet property="spinner" destination="dCP-Yu-fFz" id="0nk-0c-1AG"/>
|
||||
<outlet property="subtitle" destination="4Jk-er-UUa" id="oHh-a4-HLJ"/>
|
||||
<outlet property="title" destination="UMh-FO-rZJ" id="Bqr-Qj-R0g"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-188" y="125.93703148425789"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
|
@ -3,15 +3,6 @@ class DiscoveryCollectionHolder: UITableViewCell {
|
|||
@IBOutlet fileprivate weak var header: UILabel!
|
||||
}
|
||||
|
||||
@objc(MWMDiscoveryLocalExpertCollectionHolderCell)
|
||||
final class DiscoveryLocalExpertCollectionHolderCell: DiscoveryCollectionHolder {
|
||||
@objc func config() {
|
||||
header.text = L("discovery_button_subtitle_local_guides").uppercased()
|
||||
collectionView.register(cellClass: DiscoveryLocalExpertCell.self)
|
||||
collectionView.register(cellClass: DiscoveryMoreCell.self)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(MWMDiscoverySearchCollectionHolderCell)
|
||||
final class DiscoverySearchCollectionHolderCell: DiscoveryCollectionHolder {
|
||||
@objc func configAttractionsCell() {
|
||||
|
@ -37,3 +28,12 @@ final class DiscoveryBookingCollectionHolderCell: DiscoveryCollectionHolder {
|
|||
collectionView.register(cellClass: DiscoveryMoreCell.self)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(MWMDiscoveryGuideCollectionHolderCell)
|
||||
final class DiscoveryGuideCollectionHolderCell: DiscoveryCollectionHolder {
|
||||
@objc func config() {
|
||||
header.text = L("discovery_button_subtitle_guides").uppercased()
|
||||
collectionView.register(cellClass: DiscoveryGuideCell.self)
|
||||
collectionView.register(cellClass: DiscoveryMoreCell.self)
|
||||
}
|
||||
}
|
|
@ -1,26 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="DiscoveryLocalExpertCollectionHolderCell" rowHeight="245" id="kOb-uR-NfL" customClass="MWMDiscoveryLocalExpertCollectionHolderCell" propertyAccessControl="all">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="248"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="kOb-uR-NfL" id="HJe-Ad-Mjp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="247.5"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="DiscoveryGuideCollectionHolderCell" rowHeight="235" id="KGk-i7-Jjw" customClass="MWMDiscoveryGuideCollectionHolderCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="391" height="235"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="391" height="234.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mVI-Rn-1Ht">
|
||||
<rect key="frame" x="16" y="12" width="327" height="26"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BeQ-ih-VTq">
|
||||
<rect key="frame" x="16" y="12" width="363" height="15.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -29,14 +29,14 @@
|
|||
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium14"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="hb0-w1-X0p" customClass="MWMDiscoveryCollectionView">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="197"/>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="NFk-MT-sfu" customClass="MWMDiscoveryCollectionView">
|
||||
<rect key="frame" x="0.0" y="39.5" width="391" height="195"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="197" id="EJY-mn-vpT"/>
|
||||
<constraint firstAttribute="height" constant="195" id="Nkd-D4-A27"/>
|
||||
</constraints>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="8" minimumInteritemSpacing="0.0" id="XgH-zm-NQn">
|
||||
<size key="itemSize" width="160" height="196"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="8" minimumInteritemSpacing="0.0" id="QhS-4e-r8U">
|
||||
<size key="itemSize" width="160" height="138"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="8" minY="0.0" maxX="8" maxY="0.0"/>
|
||||
|
@ -45,27 +45,22 @@
|
|||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="hb0-w1-X0p" firstAttribute="top" secondItem="mVI-Rn-1Ht" secondAttribute="bottom" constant="12" id="2HX-P3-y34"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="mVI-Rn-1Ht" secondAttribute="trailing" constant="16" id="Krm-7b-e90"/>
|
||||
<constraint firstItem="mVI-Rn-1Ht" firstAttribute="leading" secondItem="HJe-Ad-Mjp" secondAttribute="leading" constant="16" id="O0N-tB-zHS"/>
|
||||
<constraint firstItem="mVI-Rn-1Ht" firstAttribute="top" secondItem="HJe-Ad-Mjp" secondAttribute="top" constant="12" id="Pjh-uR-2fV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="hb0-w1-X0p" secondAttribute="trailing" id="TZ9-cR-8ob"/>
|
||||
<constraint firstAttribute="bottom" secondItem="hb0-w1-X0p" secondAttribute="bottom" id="ekR-z5-imZ"/>
|
||||
<constraint firstItem="hb0-w1-X0p" firstAttribute="leading" secondItem="HJe-Ad-Mjp" secondAttribute="leading" id="uPC-mg-zsI"/>
|
||||
<constraint firstItem="NFk-MT-sfu" firstAttribute="top" secondItem="BeQ-ih-VTq" secondAttribute="bottom" constant="12" id="1gL-Ci-yMY"/>
|
||||
<constraint firstItem="NFk-MT-sfu" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="8ct-AF-P13"/>
|
||||
<constraint firstItem="BeQ-ih-VTq" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="12" id="C1z-tx-ppW"/>
|
||||
<constraint firstItem="BeQ-ih-VTq" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="Inc-RA-BDU"/>
|
||||
<constraint firstAttribute="bottom" secondItem="NFk-MT-sfu" secondAttribute="bottom" id="IsQ-zk-Inu"/>
|
||||
<constraint firstAttribute="trailing" secondItem="NFk-MT-sfu" secondAttribute="trailing" id="ZFO-zN-y6P"/>
|
||||
<constraint firstAttribute="trailing" secondItem="BeQ-ih-VTq" secondAttribute="trailing" constant="12" id="jkL-TY-BMW"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="pressBackground"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<connections>
|
||||
<outlet property="collectionView" destination="hb0-w1-X0p" id="CRZ-o9-rpF"/>
|
||||
<outlet property="header" destination="mVI-Rn-1Ht" id="0SB-Lz-CRU"/>
|
||||
<outlet property="collectionView" destination="NFk-MT-sfu" id="VEm-Jg-B49"/>
|
||||
<outlet property="header" destination="BeQ-ih-VTq" id="lvK-TC-7VT"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-179.5" y="58"/>
|
||||
<point key="canvasLocation" x="190.57971014492756" y="225"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
|
@ -0,0 +1,30 @@
|
|||
#include "map/discovery/discovery_client_params.hpp"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MWMDiscoveryMapObjects;
|
||||
@class MWMDiscoveryCityGalleryObjects;
|
||||
@class MWMDiscoverySearchViewModel;
|
||||
@class MWMDiscoveryHotelViewModel;
|
||||
@class MWMDiscoveryGuideViewModel;
|
||||
|
||||
@interface MWMDiscoveryControllerViewModel : NSObject
|
||||
|
||||
@property(nonatomic, readonly) MWMDiscoveryMapObjects *attractions;
|
||||
@property(nonatomic, readonly) MWMDiscoveryMapObjects *cafes;
|
||||
@property(nonatomic, readonly) MWMDiscoveryMapObjects *hotels;
|
||||
@property(nonatomic, readonly) MWMDiscoveryCityGalleryObjects *guides;
|
||||
|
||||
- (void)updateMapObjects:(MWMDiscoveryMapObjects *)objects
|
||||
forType:(discovery::ItemType const)type;
|
||||
- (void)updateCityGalleryObjects:(MWMDiscoveryCityGalleryObjects *)objects;
|
||||
- (NSUInteger)itemsCountForType:(discovery::ItemType const)type;
|
||||
|
||||
- (MWMDiscoverySearchViewModel *)attractionAtIndex:(NSUInteger)index;
|
||||
- (MWMDiscoverySearchViewModel *)cafeAtIndex:(NSUInteger)index;
|
||||
- (MWMDiscoveryHotelViewModel *)hotelAtIndex:(NSUInteger)index;
|
||||
- (MWMDiscoveryGuideViewModel *)guideAtIndex:(NSUInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,184 @@
|
|||
#import "MWMDiscoveryControllerViewModel.h"
|
||||
#import "MWMDiscoveryCityGalleryObjects.h"
|
||||
#import "MWMDiscoveryMapObjects.h"
|
||||
#import "MWMDiscoveryHotelViewModel.h"
|
||||
#import "MWMDiscoverySearchViewModel.h"
|
||||
#import "MWMDiscoveryGuideViewModel.h"
|
||||
#import "MWMRatingSummaryViewValueType.h"
|
||||
|
||||
#include "map/place_page_info.hpp"
|
||||
|
||||
#include "platform/localization.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include "geometry/distance_on_sphere.hpp"
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
using namespace discovery;
|
||||
|
||||
@interface MWMDiscoveryControllerViewModel()
|
||||
|
||||
@property(nonatomic, readwrite) MWMDiscoveryMapObjects *attractions;
|
||||
@property(nonatomic, readwrite) MWMDiscoveryMapObjects *cafes;
|
||||
@property(nonatomic, readwrite) MWMDiscoveryMapObjects *hotels;
|
||||
@property(nonatomic, readwrite) MWMDiscoveryCityGalleryObjects *guides;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryControllerViewModel
|
||||
|
||||
- (void)updateMapObjects:(MWMDiscoveryMapObjects *)objects
|
||||
forType:(ItemType const)type {
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
self.attractions = objects;
|
||||
break;
|
||||
case ItemType::Cafes:
|
||||
self.cafes = objects;
|
||||
break;
|
||||
case ItemType::Hotels:
|
||||
self.hotels = objects;
|
||||
break;
|
||||
case ItemType::Promo:
|
||||
break;
|
||||
case ItemType::LocalExperts:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateCityGalleryObjects:(MWMDiscoveryCityGalleryObjects *)objects {
|
||||
self.guides = objects;
|
||||
}
|
||||
|
||||
- (NSUInteger)itemsCountForType:(ItemType const)type {
|
||||
switch (type) {
|
||||
case ItemType::Attractions:
|
||||
return self.attractions.count;
|
||||
case ItemType::Cafes:
|
||||
return self.cafes.count;
|
||||
case ItemType::Hotels:
|
||||
return self.hotels.count;
|
||||
case ItemType::Promo:
|
||||
return self.guides.count;
|
||||
case ItemType::LocalExperts:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (MWMDiscoverySearchViewModel *)attractionAtIndex:(NSUInteger)index {
|
||||
search::Result const &result = [self.attractions searchResultAtIndex:index];
|
||||
search::ProductInfo const &info = [self.attractions productInfoAtIndex:index];
|
||||
m2::PointD const ¢er = [self.attractions viewPortCenter];
|
||||
return [self searchViewModelForResult:result
|
||||
productInfo:info
|
||||
viewPortCenter:center];
|
||||
}
|
||||
|
||||
- (MWMDiscoverySearchViewModel *)cafeAtIndex:(NSUInteger)index {
|
||||
search::Result const &result = [self.cafes searchResultAtIndex:index];
|
||||
search::ProductInfo const &info = [self.cafes productInfoAtIndex:index];
|
||||
m2::PointD const ¢er = [self.cafes viewPortCenter];
|
||||
return [self searchViewModelForResult:result
|
||||
productInfo:info
|
||||
viewPortCenter:center];
|
||||
}
|
||||
|
||||
- (MWMDiscoveryHotelViewModel *)hotelAtIndex:(NSUInteger)index {
|
||||
search::Result const &result = [self.hotels searchResultAtIndex:index];
|
||||
search::ProductInfo const &info = [self.hotels productInfoAtIndex:index];
|
||||
m2::PointD const ¢er = [self.hotels viewPortCenter];
|
||||
return [self hotelViewModelForResult:result
|
||||
productInfo:info
|
||||
viewPortCenter:center];
|
||||
}
|
||||
|
||||
- (MWMDiscoveryGuideViewModel *)guideAtIndex:(NSUInteger)index {
|
||||
promo::CityGallery::Item const &item = [self.guides galleryItemAtIndex:index];
|
||||
return [self guideViewModelForItem:item];
|
||||
}
|
||||
|
||||
#pragma mark - Builders
|
||||
|
||||
- (MWMDiscoverySearchViewModel *)searchViewModelForResult:(search::Result const &)result
|
||||
productInfo:(search::ProductInfo const &)info
|
||||
viewPortCenter:(m2::PointD const &)center {
|
||||
|
||||
auto const readableType = classif().GetReadableObjectName(result.GetFeatureType());
|
||||
NSString *subtitle = @(platform::GetLocalizedTypeName(readableType).c_str());
|
||||
NSString *title = result.GetString().empty() ? subtitle : @(result.GetString().c_str());
|
||||
|
||||
NSString *ratingValue = [self ratingValueForProductInfo:info];
|
||||
MWMRatingSummaryViewValueType ratingType = [self ratingTypeForProductInfo:info];
|
||||
|
||||
NSString *distance = [self distanceFrom:center
|
||||
to:result.GetFeatureCenter()];
|
||||
|
||||
BOOL isPopular = result.GetRankingInfo().m_popularity > 0;
|
||||
|
||||
return [[MWMDiscoverySearchViewModel alloc] initWithTitle:title
|
||||
subtitle:subtitle
|
||||
distance:distance
|
||||
isPopular:isPopular
|
||||
ratingValue:ratingValue
|
||||
ratingType:ratingType];
|
||||
}
|
||||
|
||||
- (MWMDiscoveryHotelViewModel *)hotelViewModelForResult:(search::Result const &)result
|
||||
productInfo:(search::ProductInfo const &)info
|
||||
viewPortCenter:(m2::PointD const &)center {
|
||||
|
||||
auto const readableType = classif().GetReadableObjectName(result.GetFeatureType());
|
||||
NSString *subtitle = @(platform::GetLocalizedTypeName(readableType).c_str());
|
||||
NSString *title = result.GetString().empty() ? subtitle : @(result.GetString().c_str());
|
||||
NSUInteger starsCount = result.GetStarsCount();
|
||||
if (starsCount > 0) {
|
||||
subtitle = [@"" stringByPaddingToLength:starsCount
|
||||
withString:@"★"
|
||||
startingAtIndex:0];
|
||||
}
|
||||
NSString *price = @(result.GetHotelApproximatePricing().c_str());
|
||||
|
||||
NSString *ratingValue = [self ratingValueForProductInfo:info];
|
||||
MWMRatingSummaryViewValueType ratingType = [self ratingTypeForProductInfo:info];
|
||||
|
||||
NSString *distance = [self distanceFrom:center
|
||||
to:result.GetFeatureCenter()];
|
||||
|
||||
BOOL isPopular = result.GetRankingInfo().m_popularity > 0;
|
||||
|
||||
return [[MWMDiscoveryHotelViewModel alloc] initWithTitle:title
|
||||
subtitle:subtitle
|
||||
price:price
|
||||
distance:distance
|
||||
isPopular:isPopular
|
||||
ratingValue:ratingValue
|
||||
ratingType:ratingType];
|
||||
}
|
||||
|
||||
- (MWMDiscoveryGuideViewModel *)guideViewModelForItem:(promo::CityGallery::Item const &)item {
|
||||
return [[MWMDiscoveryGuideViewModel alloc] initWithTitle:@(item.m_name.c_str())
|
||||
subtitle:@(item.m_author.m_name.c_str())
|
||||
label:@(item.m_luxCategory.m_name.c_str())
|
||||
imageURL:@(item.m_imageUrl.c_str())];
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (NSString *)distanceFrom:(m2::PointD const &)startPoint
|
||||
to:(m2::PointD const &)endPoint {
|
||||
string distance;
|
||||
auto const f = MercatorBounds::ToLatLon(startPoint);
|
||||
auto const t = MercatorBounds::ToLatLon(endPoint);
|
||||
measurement_utils::FormatDistance(ms::DistanceOnEarth(f.m_lat, f.m_lon, t.m_lat, t.m_lon), distance);
|
||||
return @(distance.c_str());
|
||||
}
|
||||
|
||||
- (NSString *)ratingValueForProductInfo:(search::ProductInfo const &)info {
|
||||
return @(place_page::rating::GetRatingFormatted(info.m_ugcRating).c_str());
|
||||
}
|
||||
|
||||
- (MWMRatingSummaryViewValueType)ratingTypeForProductInfo:(search::ProductInfo const &)info {
|
||||
return (MWMRatingSummaryViewValueType)place_page::rating::GetImpress(info.m_ugcRating);
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,17 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MWMDiscoveryGuideViewModel : NSObject
|
||||
|
||||
@property(nonatomic, readonly) NSString *title;
|
||||
@property(nonatomic, readonly) NSString *subtitle;
|
||||
@property(nonatomic, nullable, readonly) NSString *label;
|
||||
@property(nonatomic, nullable, readonly) NSString *imagePath;
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
label:(nullable NSString *)label
|
||||
imageURL:(nullable NSString *) imagePath;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,28 @@
|
|||
#import "MWMDiscoveryGuideViewModel.h"
|
||||
|
||||
@interface MWMDiscoveryGuideViewModel()
|
||||
|
||||
@property(nonatomic, readwrite) NSString *title;
|
||||
@property(nonatomic, readwrite) NSString *subtitle;
|
||||
@property(nonatomic, readwrite) NSString *label;
|
||||
@property(nonatomic, readwrite) NSString *imagePath;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryGuideViewModel
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
label:(NSString *)label
|
||||
imageURL:(NSString *) imagePath {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.title = title;
|
||||
self.subtitle = subtitle;
|
||||
self.label = label;
|
||||
self.imagePath = imagePath;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,25 @@
|
|||
#import "MWMRatingSummaryViewValueType.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MWMDiscoveryHotelViewModel : NSObject
|
||||
|
||||
@property(nonatomic, readonly) NSString *title;
|
||||
@property(nonatomic, readonly) NSString *subtitle;
|
||||
@property(nonatomic, readonly) NSString *price;
|
||||
@property(nonatomic, readonly) NSString *distance;
|
||||
@property(nonatomic, readonly) BOOL isPopular;
|
||||
@property(nonatomic, readonly) NSString *ratingValue;
|
||||
@property(nonatomic, readonly) MWMRatingSummaryViewValueType ratingType;
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
price:(NSString *)price
|
||||
distance:(NSString *)distance
|
||||
isPopular:(BOOL)isPopular
|
||||
ratingValue:(NSString *) ratingValue
|
||||
ratingType:(MWMRatingSummaryViewValueType)ratingType;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,37 @@
|
|||
#import "MWMDiscoveryHotelViewModel.h"
|
||||
|
||||
@interface MWMDiscoveryHotelViewModel()
|
||||
|
||||
@property(nonatomic, readwrite) NSString *title;
|
||||
@property(nonatomic, readwrite) NSString *subtitle;
|
||||
@property(nonatomic, readwrite) NSString *price;
|
||||
@property(nonatomic, readwrite) NSString *distance;
|
||||
@property(nonatomic, readwrite) BOOL isPopular;
|
||||
@property(nonatomic, readwrite) NSString *ratingValue;
|
||||
@property(nonatomic, readwrite) MWMRatingSummaryViewValueType ratingType;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoveryHotelViewModel
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
price:(NSString *)price
|
||||
distance:(NSString *)distance
|
||||
isPopular:(BOOL)isPopular
|
||||
ratingValue:(NSString *) ratingValue
|
||||
ratingType:(MWMRatingSummaryViewValueType)ratingType {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.title = title;
|
||||
self.subtitle = subtitle;
|
||||
self.price = price;
|
||||
self.distance = distance;
|
||||
self.isPopular = isPopular;
|
||||
self.ratingValue = ratingValue;
|
||||
self.ratingType = ratingType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,22 @@
|
|||
#import "MWMRatingSummaryViewValueType.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MWMDiscoverySearchViewModel : NSObject
|
||||
|
||||
@property(nonatomic, readonly) NSString *title;
|
||||
@property(nonatomic, readonly) NSString *subtitle;
|
||||
@property(nonatomic, readonly) NSString *distance;
|
||||
@property(nonatomic, readonly) BOOL isPopular;
|
||||
@property(nonatomic, readonly) NSString *ratingValue;
|
||||
@property(nonatomic, readonly) MWMRatingSummaryViewValueType ratingType;
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
distance:(NSString *)distance
|
||||
isPopular:(BOOL)isPopular
|
||||
ratingValue:(NSString *) ratingValue
|
||||
ratingType:(MWMRatingSummaryViewValueType)ratingType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,34 @@
|
|||
#import "MWMDiscoverySearchViewModel.h"
|
||||
|
||||
@interface MWMDiscoverySearchViewModel()
|
||||
|
||||
@property(nonatomic, readwrite) NSString *title;
|
||||
@property(nonatomic, readwrite) NSString *subtitle;
|
||||
@property(nonatomic, readwrite) NSString *distance;
|
||||
@property(nonatomic, readwrite) BOOL isPopular;
|
||||
@property(nonatomic, readwrite) NSString *ratingValue;
|
||||
@property(nonatomic, readwrite) MWMRatingSummaryViewValueType ratingType;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMDiscoverySearchViewModel
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title
|
||||
subtitle:(NSString *)subtitle
|
||||
distance:(NSString *)distance
|
||||
isPopular:(BOOL)isPopular
|
||||
ratingValue:(NSString *) ratingValue
|
||||
ratingType:(MWMRatingSummaryViewValueType)ratingType {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.title = title;
|
||||
self.subtitle = subtitle;
|
||||
self.distance = distance;
|
||||
self.isPopular = isPopular;
|
||||
self.ratingValue = ratingValue;
|
||||
self.ratingType = ratingType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
Loading…
Add table
Reference in a new issue