[MAPSME-4213] [ios] Added banners support to search.

This commit is contained in:
Ilya Grechuhin 2017-04-17 16:21:21 +03:00 committed by Sergey Yershov
parent 4dd4bd9c0a
commit d09064eff5
13 changed files with 306 additions and 51 deletions

View file

@ -26,6 +26,7 @@
#import "MWMPlacePageCellUpdateProtocol.h"
#import "MWMPushNotifications.h"
#import "MWMRouter.h"
#import "MWMSearchItemType.h"
#import "MWMSearchNoResults.h"
#import "MWMSettings.h"
#import "MWMTableViewCell.h"

View file

@ -18,6 +18,7 @@ final class BannersCache: NSObject {
private var requests: [BannerType : Banner] = [:]
private var completion: Completion?
private var loadStates: [LoadState]!
private var cacheOnly = false
private func onCompletion(isAsync: Bool) {
guard let completion = completion else { return }
@ -43,8 +44,9 @@ final class BannersCache: NSObject {
self.completion = nil
}
func get(coreBanners: [CoreBanner], completion: @escaping Completion) {
func get(coreBanners: [CoreBanner], completion: @escaping Completion, cacheOnly: Bool) {
self.completion = completion
self.cacheOnly = cacheOnly
loadStates = coreBanners.map { coreBanner in
let bannerType = BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID)
if let banner = cache[bannerType], (!banner.isPossibleToReload || banner.isNeedToRetain) {
@ -93,7 +95,9 @@ final class BannersCache: NSObject {
}
cache[bannerType] = banner
requests[bannerType] = nil
onCompletion(isAsync: true)
if !cacheOnly {
onCompletion(isAsync: true)
}
}
private func setError(bannerType: BannerType) {

View file

@ -1,4 +1,6 @@
#import "MWMBanner.h"
#import "MWMSearchFilterViewController.h"
#import "MWMSearchItemType.h"
#import "MWMSearchObserver.h"
#include "search/result.hpp"
@ -13,7 +15,11 @@
+ (void)showResult:(search::Result const &)result;
+ (search::Result const &)resultAtIndex:(NSUInteger)index;
+ (MWMSearchItemType)resultTypeWithIndex:(NSUInteger)index;
+ (NSUInteger)containerIndexWithIndex:(NSUInteger)index;
+ (search::Result const &)resultWithContainerIndex:(NSUInteger)index;
+ (id<MWMBanner>)adWithContainerIndex:(NSUInteger)index;
+ (void)update;
+ (void)clear;

View file

@ -1,12 +1,16 @@
#import "MWMSearch.h"
#import <Crashlytics/Crashlytics.h>
#import "MWMCommon.h"
#import "MWMAlertViewController.h"
#import "MWMBannerHelpers.h"
#import "MWMCommon.h"
#import "MWMLocationManager.h"
#import "MWMSearchHotelsFilterViewController.h"
#import "SwiftBridge.h"
#include "Framework.h"
#include "partners_api/ads_engine.hpp"
#include "search/everywhere_search_params.hpp"
#include "search/hotels_classifier.hpp"
#include "search/query_saver.hpp"
@ -37,6 +41,10 @@ using TObservers = NSHashTable<__kindof TObserver>;
@property(nonatomic) BOOL viewportResultsEmpty;
@property(nonatomic) MWMSearchIndex * itemsIndex;
@property(nonatomic) MWMSearchBanners * banners;
@end
@implementation MWMSearch
@ -97,6 +105,7 @@ using TObservers = NSHashTable<__kindof TObserver>;
{
self->m_everywhereResults = results;
self.suggestionsCount = results.GetSuggestsCount();
[self updateItemsIndex];
[self onSearchResultsUpdated];
}
};
@ -208,30 +217,48 @@ using TObservers = NSHashTable<__kindof TObserver>;
}
+ (void)showResult:(search::Result const &)result { GetFramework().ShowSearchResult(result); }
+ (search::Result const &)resultAtIndex:(NSUInteger)index
+ (search::Result const &)resultWithContainerIndex:(NSUInteger)index
{
return [MWMSearch manager]->m_everywhereResults.GetResult(index);
}
+ (id<MWMBanner>)adWithContainerIndex:(NSUInteger)index
{
return [[MWMSearch manager].banners bannerAtIndex:index];
}
+ (MWMSearchItemType)resultTypeWithIndex:(NSUInteger)index
{
auto itemsIndex = [MWMSearch manager].itemsIndex;
return [itemsIndex resultTypeWithIndex:index];
}
+ (NSUInteger)containerIndexWithIndex:(NSUInteger)index
{
auto itemsIndex = [MWMSearch manager].itemsIndex;
return [itemsIndex resultContainerIndexWithIndex:index];
}
+ (void)update { [[MWMSearch manager] update]; }
+ (void)reset
{
MWMSearch * manager = [MWMSearch manager];
auto manager = [MWMSearch manager];
manager.lastSearchStamp++;
GetFramework().CancelAllSearches();
manager.everywhereSearchCompleted = NO;
manager.viewportSearchCompleted = NO;
if (manager->m_filterQuery != manager->m_everywhereParams.m_query)
manager.isHotelResults = NO;
manager.suggestionsCount = 0;
[manager onSearchResultsUpdated];
}
+ (void)clear
{
[MWMSearch manager]->m_everywhereResults.Clear();
auto manager = [MWMSearch manager];
manager->m_everywhereResults.Clear();
manager.suggestionsCount = 0;
[manager updateItemsIndex];
[self reset];
}
@ -248,9 +275,7 @@ using TObservers = NSHashTable<__kindof TObserver>;
}
+ (NSUInteger)suggestionsCount { return [MWMSearch manager].suggestionsCount; }
+ (NSUInteger)resultsCount { return [MWMSearch manager]->m_everywhereResults.GetCount(); }
+ (NSUInteger)resultsCount { return [MWMSearch manager].itemsIndex.count; }
+ (BOOL)isHotelResults { return [MWMSearch manager].isHotelResults; }
#pragma mark - Filters
@ -270,6 +295,40 @@ using TObservers = NSHashTable<__kindof TObserver>;
MWMSearch * manager = [MWMSearch manager];
manager.filter = nil;
[manager update];
[manager onSearchCompleted];
}
- (void)updateItemsIndex
{
auto resultsCount = self->m_everywhereResults.GetCount();
auto itemsIndex = [[MWMSearchIndex alloc] initWithSuggestionsCount:self.suggestionsCount
resultsCount:resultsCount];
auto bannersCache = [MWMBannersCache cache];
if (resultsCount > 0)
{
auto const & adsEngine = GetFramework().GetAdsEngine();
if (adsEngine.HasSearchBanner())
{
self.banners = [[MWMSearchBanners alloc] initWithSearchIndex:itemsIndex];
__weak auto weakSelf = self;
[bannersCache
getWithCoreBanners:banner_helpers::MatchPriorityBanners(adsEngine.GetSearchBanners())
completion:^(id<MWMBanner> ad, BOOL isAsync) {
__strong auto self = weakSelf;
if (!self)
return;
NSAssert(isAsync == NO, @"Banner is not from cache!");
[self.banners add:ad];
}
cacheOnly:YES];
}
}
else
{
self.banners = nil;
}
[itemsIndex build];
self.itemsIndex = itemsIndex;
}
#pragma mark - Notifications

View file

@ -0,0 +1,6 @@
typedef NS_ENUM(NSUInteger, MWMSearchItemType) {
// Order == priority.
MWMSearchItemTypeRegular,
MWMSearchItemTypeMopub,
MWMSearchItemTypeSuggestion
};

View file

@ -0,0 +1,36 @@
@objc(MWMSearchBanners)
final class SearchBanners: NSObject {
private var banners: [MWMBanner] = []
weak var searchIndex: SearchIndex?
init(searchIndex: SearchIndex) {
self.searchIndex = searchIndex
super.init()
}
func add(_ banner: MWMBanner) {
guard let searchIndex = searchIndex else { return }
banners.append(banner)
let type: MWMSearchItemType
let prefferedPosition: Int
switch banner.mwmType {
case .mopub:
type = .mopub
prefferedPosition = 2
default:
assert(false, "Unsupported banner type")
type = .regular
prefferedPosition = 0
}
searchIndex.addItem(type: type, prefferedPosition: prefferedPosition, containerIndex: banners.count - 1)
}
func banner(atIndex index: Int) -> MWMBanner {
return banners[index]
}
deinit {
banners.forEach { BannersCache.cache.bannerIsOutOfScreen(coreBanner: $0) }
}
}

View file

@ -0,0 +1,85 @@
@objc(MWMSearchIndex)
final class SearchIndex: NSObject {
fileprivate struct Item {
let type: MWMSearchItemType
let containerIndex: Int
}
fileprivate struct PositionItem {
let item: Item
var position: Int
}
private var positionItems: [PositionItem] = []
private var items: [Item] = []
var count: Int {
return items.count
}
init(suggestionsCount: Int, resultsCount: Int) {
for index in 0..<resultsCount {
let type: MWMSearchItemType = index < suggestionsCount ? .suggestion : .regular
positionItems.append(PositionItem(item: Item(type: type, containerIndex: index), position: index))
}
super.init()
}
func addItem(type: MWMSearchItemType, prefferedPosition: Int, containerIndex: Int) {
assert(type != .suggestion && type != .regular)
positionItems.append(PositionItem(item: Item(type: type, containerIndex: containerIndex), position: prefferedPosition))
}
func build() {
positionItems.sort(by: >)
var itemsDict: [Int: Item] = [:]
positionItems.forEach { item in
var position = item.position
while itemsDict[position] != nil {
position += 1
}
itemsDict[position] = item.item
}
items.removeAll()
let keys = itemsDict.keys.sorted()
for index in 0..<keys.count {
let key = keys[index]
if index == key {
items.append(itemsDict[key]!)
}
}
}
func resultType(index: Int) -> MWMSearchItemType {
return items[index].type
}
func resultContainerIndex(index: Int) -> Int {
return items[index].containerIndex
}
}
extension SearchIndex.PositionItem: Equatable {
static func ==(lhs: SearchIndex.PositionItem, rhs: SearchIndex.PositionItem) -> Bool {
let lhsCache = lhs.item
let rhsCache = rhs.item
return lhsCache.type == rhsCache.type &&
lhs.position == rhs.position &&
lhsCache.containerIndex == rhsCache.containerIndex
}
}
extension SearchIndex.PositionItem: Comparable {
static func <(lhs: SearchIndex.PositionItem, rhs: SearchIndex.PositionItem) -> Bool {
let lhsCache = lhs.item
let rhsCache = rhs.item
guard lhsCache.type == rhsCache.type else {
return lhsCache.type.rawValue < rhsCache.type.rawValue
}
guard lhs.position == rhs.position else {
return lhs.position > rhs.position
}
return lhsCache.containerIndex < rhsCache.containerIndex
}
}

View file

@ -157,6 +157,9 @@
342CC5F21C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342CC5F01C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm */; };
342EE4111C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342EE4101C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm */; };
342EE4121C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342EE4101C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm */; };
343064401E9FDC7300DC7665 /* SearchIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430643F1E9FDC7300DC7665 /* SearchIndex.swift */; };
343064411E9FDC7300DC7665 /* SearchIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430643F1E9FDC7300DC7665 /* SearchIndex.swift */; };
343064421E9FDC7300DC7665 /* SearchIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430643F1E9FDC7300DC7665 /* SearchIndex.swift */; };
3432E1781E49B3A2008477E9 /* Bolts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E1771E49B3A2008477E9 /* Bolts.framework */; };
3432E1791E49B3A2008477E9 /* Bolts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E1771E49B3A2008477E9 /* Bolts.framework */; };
3432E17A1E49B3A2008477E9 /* Bolts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E1771E49B3A2008477E9 /* Bolts.framework */; };
@ -302,6 +305,9 @@
3490D2E11CE9DD2500D0B838 /* MWMSideButtonsView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3490D2DC1CE9DD2500D0B838 /* MWMSideButtonsView.mm */; };
3490D2E21CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3490D2DD1CE9DD2500D0B838 /* MWMSideButtonsView.xib */; };
3490D2E31CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3490D2DD1CE9DD2500D0B838 /* MWMSideButtonsView.xib */; };
34926BE61EA4C2A700DCF14C /* SearchBanners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34926BE51EA4C2A700DCF14C /* SearchBanners.swift */; };
34926BE71EA4C2A700DCF14C /* SearchBanners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34926BE51EA4C2A700DCF14C /* SearchBanners.swift */; };
34926BE81EA4C2A700DCF14C /* SearchBanners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34926BE51EA4C2A700DCF14C /* SearchBanners.swift */; };
34943BB61E26222300B14F84 /* WelcomeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34943BB51E26222300B14F84 /* WelcomeProtocol.swift */; };
34943BB71E26222300B14F84 /* WelcomeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34943BB51E26222300B14F84 /* WelcomeProtocol.swift */; };
34943BB81E26222300B14F84 /* WelcomeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34943BB51E26222300B14F84 /* WelcomeProtocol.swift */; };
@ -1619,11 +1625,13 @@
341C2A5A1B720B8A00AD41A1 /* MWMAPIBarView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMAPIBarView.xib; sourceTree = "<group>"; };
341F09831C20138100F18AC5 /* libpugixml.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpugixml.a; path = "../../../omim-xcode-build/Debug/libpugixml.a"; sourceTree = "<group>"; };
34201E0B1DC0E33100D24118 /* libtracking.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtracking.a; path = "../../../omim-xcode-build/Debug/libtracking.a"; sourceTree = "<group>"; };
342639461EA0FDB30025EB89 /* MWMSearchItemType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchItemType.h; sourceTree = "<group>"; };
3427AF0B1E49E3A500D466DB /* MWMConsts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMConsts.h; sourceTree = "<group>"; };
342CC5EF1C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMAuthorizationLoginViewController.h; sourceTree = "<group>"; };
342CC5F01C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMAuthorizationLoginViewController.mm; sourceTree = "<group>"; };
342EE40F1C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMAuthorizationWebViewLoginViewController.h; sourceTree = "<group>"; };
342EE4101C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMAuthorizationWebViewLoginViewController.mm; sourceTree = "<group>"; };
3430643F1E9FDC7300DC7665 /* SearchIndex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchIndex.swift; sourceTree = "<group>"; };
3432E1771E49B3A2008477E9 /* Bolts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Bolts.framework; sourceTree = "<group>"; };
343E75951E5B1EE20041226A /* MWMCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMCollectionViewController.h; sourceTree = "<group>"; };
343E75961E5B1EE20041226A /* MWMCollectionViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMCollectionViewController.mm; sourceTree = "<group>"; };
@ -1714,6 +1722,7 @@
3490D2DB1CE9DD2500D0B838 /* MWMSideButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSideButtonsView.h; sourceTree = "<group>"; };
3490D2DC1CE9DD2500D0B838 /* MWMSideButtonsView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSideButtonsView.mm; sourceTree = "<group>"; };
3490D2DD1CE9DD2500D0B838 /* MWMSideButtonsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMSideButtonsView.xib; sourceTree = "<group>"; };
34926BE51EA4C2A700DCF14C /* SearchBanners.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBanners.swift; sourceTree = "<group>"; };
34943BB51E26222300B14F84 /* WelcomeProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeProtocol.swift; sourceTree = "<group>"; };
34943BB91E2626B200B14F84 /* WelcomePageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomePageController.swift; sourceTree = "<group>"; };
3497A9361B5CF8A900F51E55 /* MWMNavigationDashboardManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMNavigationDashboardManager.h; sourceTree = "<group>"; };
@ -2784,6 +2793,9 @@
3404753C1E081A4600C92850 /* MWMSearch.h */,
3404753D1E081A4600C92850 /* MWMSearch.mm */,
3404753E1E081A4600C92850 /* MWMSearchObserver.h */,
3430643F1E9FDC7300DC7665 /* SearchIndex.swift */,
342639461EA0FDB30025EB89 /* MWMSearchItemType.h */,
34926BE51EA4C2A700DCF14C /* SearchBanners.swift */,
);
path = Search;
sourceTree = "<group>";
@ -5069,6 +5081,7 @@
F6E2FE1E1E097BA00083EBEC /* MWMOpeningHoursCommon.mm in Sources */,
F6BC1E521ACBF98600EF0360 /* MWMFacebookAlert.mm in Sources */,
F6E2FF5C1E097BA00083EBEC /* MWMRecentTrackSettingsController.mm in Sources */,
343064401E9FDC7300DC7665 /* SearchIndex.swift in Sources */,
F6664BF91E6459CB00E703C2 /* PPFacilityCell.swift in Sources */,
F6E2FDE81E097BA00083EBEC /* MWMObjectsCategorySelectorController.mm in Sources */,
F64F199D1AB81A00006EAF7E /* MWMDefaultAlert.mm in Sources */,
@ -5291,6 +5304,7 @@
F6E2FDA31E097BA00083EBEC /* MWMCuisineEditorViewController.mm in Sources */,
346EDADB1B9F0E35004F8DB5 /* MWMMultilineLabel.mm in Sources */,
34D3B0291E389D05004100F9 /* MWMEditorAdditionalNameTableViewCell.mm in Sources */,
34926BE61EA4C2A700DCF14C /* SearchBanners.swift in Sources */,
34D4FA621E26572D003F53EF /* FirstLaunchController.swift in Sources */,
34C9BD041C6DB693000DC38D /* MWMViewController.mm in Sources */,
3404165B1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,
@ -5359,6 +5373,7 @@
F6E2FE1F1E097BA00083EBEC /* MWMOpeningHoursCommon.mm in Sources */,
3454D7B91E07F045004AF2AD /* CALayer+RuntimeAttributes.mm in Sources */,
F6E2FF5D1E097BA00083EBEC /* MWMRecentTrackSettingsController.mm in Sources */,
343064411E9FDC7300DC7665 /* SearchIndex.swift in Sources */,
F6664BFA1E6459CB00E703C2 /* PPFacilityCell.swift in Sources */,
F6E2FDE91E097BA00083EBEC /* MWMObjectsCategorySelectorController.mm in Sources */,
6741A9A81BF340DE002C974C /* MWMFacebookAlert.mm in Sources */,
@ -5581,6 +5596,7 @@
34C9BD051C6DB693000DC38D /* MWMViewController.mm in Sources */,
F6E2FDA41E097BA00083EBEC /* MWMCuisineEditorViewController.mm in Sources */,
3454D7CB1E07F045004AF2AD /* UIColor+MapsMeColor.mm in Sources */,
34926BE71EA4C2A700DCF14C /* SearchBanners.swift in Sources */,
34D3B02A1E389D05004100F9 /* MWMEditorAdditionalNameTableViewCell.mm in Sources */,
340475711E081A4600C92850 /* MWMSettings.mm in Sources */,
3404165C1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,
@ -5649,6 +5665,7 @@
F6E2FE201E097BA00083EBEC /* MWMOpeningHoursCommon.mm in Sources */,
849CF6891DE842290024A8A5 /* MWMFacebookAlert.mm in Sources */,
F6E2FF5E1E097BA00083EBEC /* MWMRecentTrackSettingsController.mm in Sources */,
343064421E9FDC7300DC7665 /* SearchIndex.swift in Sources */,
F6664BFB1E6459CB00E703C2 /* PPFacilityCell.swift in Sources */,
F6E2FDEA1E097BA00083EBEC /* MWMObjectsCategorySelectorController.mm in Sources */,
849CF68A1DE842290024A8A5 /* MWMDefaultAlert.mm in Sources */,
@ -5871,6 +5888,7 @@
3454D7C31E07F045004AF2AD /* NSString+Categories.mm in Sources */,
34D4FA641E26572D003F53EF /* FirstLaunchController.swift in Sources */,
34D3B02B1E389D05004100F9 /* MWMEditorAdditionalNameTableViewCell.mm in Sources */,
34926BE81EA4C2A700DCF14C /* SearchBanners.swift in Sources */,
849CF7371DE842290024A8A5 /* MWMTaxiCollectionLayout.mm in Sources */,
3454D7C61E07F045004AF2AD /* UIButton+Orientation.mm in Sources */,
3404165D1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,

View file

@ -6,6 +6,7 @@ enum AdBannerState: Int {
case unset
case compact
case detailed
case search
func config() -> (priority: UILayoutPriority, numberOfTitleLines: Int, numberOfBodyLines: Int) {
switch self {
@ -15,15 +16,24 @@ enum AdBannerState: Int {
case .compact:
return alternative(iPhone: (priority: UILayoutPriorityDefaultLow, numberOfTitleLines: 1, numberOfBodyLines: 2),
iPad: (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0))
case .search:
return (priority: UILayoutPriorityDefaultLow, numberOfTitleLines: 2, numberOfBodyLines: 0)
case .detailed:
return (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0)
}
}
}
@objc(MWMAdBannerContainerType)
enum AdBannerContainerType: Int {
case placePage
case search
}
@objc(MWMAdBanner)
final class AdBanner: UITableViewCell {
@IBOutlet private var detailedModeConstraints: [NSLayoutConstraint]!
@IBOutlet private weak var adCallToActionButtonCompactLeading: NSLayoutConstraint!
@IBOutlet private weak var adIconImageView: UIImageView!
@IBOutlet private weak var adTitleLabel: UILabel!
@IBOutlet private weak var adBodyLabel: UILabel!
@ -37,6 +47,9 @@ final class AdBanner: UITableViewCell {
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
detailedModeConstraints.forEach { $0.priority = config.priority }
if state == .search {
adCallToActionButtonCompactLeading.priority = UILayoutPriorityDefaultHigh
}
setNeedsLayout()
UIView.animate(withDuration: kDefaultAnimationDuration) { self.layoutIfNeeded() }
refreshBannerIfNeeded()
@ -51,8 +64,14 @@ final class AdBanner: UITableViewCell {
private var nativeAd: MWMBanner?
func config(ad: MWMBanner) {
state = alternative(iPhone: AdBannerState.compact, iPad: AdBannerState.detailed)
func config(ad: MWMBanner, containerType: AdBannerContainerType) {
switch containerType {
case .placePage:
state = alternative(iPhone: .compact, iPad: .detailed)
case .search:
state = .search
}
nativeAd = ad
switch ad.mwmType {
case .none:
@ -90,7 +109,12 @@ final class AdBanner: UITableViewCell {
private func configFBBanner(ad: FBNativeAd) {
ad.unregisterView()
let adCallToActionButtons = [adCallToActionButtonCompact!, adCallToActionButtonDetailed!]
let adCallToActionButtons: [UIView]
if (state == .search) {
adCallToActionButtons = [self]
} else {
adCallToActionButtons = [adCallToActionButtonCompact, adCallToActionButtonDetailed]
}
ad.registerView(forInteraction: self, with: nil, withClickableViews: adCallToActionButtons)
ad.icon?.loadAsync { [weak self] image in
@ -109,7 +133,7 @@ final class AdBanner: UITableViewCell {
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
adCallToActionButtons.forEach { $0.setTitle(ad.callToAction, for: .normal) }
[adCallToActionButtonCompact, adCallToActionButtonDetailed].forEach { $0.setTitle(ad.callToAction, for: .normal) }
}
private func configRBBanner(ad: MTRGNativeAd) {
@ -168,6 +192,7 @@ final class AdBanner: UITableViewCell {
clickableView = adCallToActionButtonCompact
case .compact: clickableView = adCallToActionButtonCompact
case .detailed: clickableView = adCallToActionButtonDetailed
case .search: clickableView = self
}
ad.register(clickableView, with: UIViewController.topViewController())
}

View file

@ -142,6 +142,7 @@
<connections>
<outlet property="adBodyLabel" destination="Ev3-yY-ql1" id="xw6-9k-OYn"/>
<outlet property="adCallToActionButtonCompact" destination="9qA-JC-fkn" id="2AF-5i-Wey"/>
<outlet property="adCallToActionButtonCompactLeading" destination="5CH-Fo-S70" id="Vdl-uS-6Gd"/>
<outlet property="adCallToActionButtonDetailed" destination="NKM-3R-3g1" id="diP-AI-tNi"/>
<outlet property="adIconImageView" destination="EuF-Rm-DHQ" id="Edf-Ak-VAy"/>
<outlet property="adTitleLabel" destination="kIR-cO-v6L" id="OOh-tX-yBM"/>

View file

@ -113,7 +113,8 @@ using namespace place_page;
self->m_previewRows.push_back(PreviewRows::Banner);
if (isAsync)
self.bannerIsReadyCallback();
}];
}
cacheOnly:NO];
}
}

View file

@ -235,7 +235,7 @@ array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTi
return c;
case PreviewRows::Banner:
auto bannerCell = static_cast<MWMAdBanner *>(c);
[bannerCell configWithAd:data.nativeAd];
[bannerCell configWithAd:data.nativeAd containerType:MWMAdBannerContainerTypePlacePage];
self.cachedBannerCell = bannerCell;
return bannerCell;
}

View file

@ -48,19 +48,7 @@
tableView.rowHeight = UITableViewAutomaticDimension;
[tableView registerWithCellClass:[MWMSearchSuggestionCell class]];
[tableView registerWithCellClass:[MWMSearchCommonCell class]];
}
- (Class)cellClassForIndexPath:(NSIndexPath *)indexPath
{
size_t const numSuggests = [MWMSearch suggestionsCount];
if (numSuggests > 0 && indexPath.row < numSuggests)
return [MWMSearchSuggestionCell class];
return [MWMSearchCommonCell class];
}
- (search::Result const &)searchResultForIndexPath:(NSIndexPath *)indexPath
{
return [MWMSearch resultAtIndex:indexPath.row];
[tableView registerWithCellClass:[MWMAdBanner class]];
}
- (void)reloadData { [self.tableView reloadData]; }
@ -86,41 +74,66 @@
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Class cls = [self cellClassForIndexPath:indexPath];
auto cell = [tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath];
if (cls == [MWMSearchSuggestionCell class])
auto const row = indexPath.row;
auto const containerIndex = [MWMSearch containerIndexWithIndex:row];
switch ([MWMSearch resultTypeWithIndex:row])
{
auto tCell = static_cast<MWMSearchSuggestionCell *>(cell);
[tCell config:[self searchResultForIndexPath:indexPath]];
tCell.isLastCell = indexPath.row == [MWMSearch suggestionsCount] - 1;
}
else if (cls == [MWMSearchCommonCell class])
case MWMSearchItemTypeRegular:
{
auto tCell = static_cast<MWMSearchCommonCell *>(cell);
[tCell config:[self searchResultForIndexPath:indexPath]];
auto cell = static_cast<MWMSearchSuggestionCell *>([tableView
dequeueReusableCellWithCellClass:[MWMSearchCommonCell class]
indexPath:indexPath]);
auto result = [MWMSearch resultWithContainerIndex:containerIndex];
[cell config:result];
return cell;
}
case MWMSearchItemTypeMopub:
{
auto cell = static_cast<MWMAdBanner *>(
[tableView dequeueReusableCellWithCellClass:[MWMAdBanner class] indexPath:indexPath]);
auto ad = [MWMSearch adWithContainerIndex:containerIndex];
[cell configWithAd:ad containerType:MWMAdBannerContainerTypeSearch];
return cell;
}
case MWMSearchItemTypeSuggestion:
{
auto cell = static_cast<MWMSearchSuggestionCell *>([tableView
dequeueReusableCellWithCellClass:[MWMSearchSuggestionCell class]
indexPath:indexPath]);
auto suggestion = [MWMSearch resultWithContainerIndex:containerIndex];
[cell config:suggestion];
cell.isLastCell = row == [MWMSearch suggestionsCount] - 1;
return cell;
}
}
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Class cls = [self cellClassForIndexPath:indexPath];
id<MWMSearchTableViewProtocol> delegate = self.delegate;
search::Result const & result = [self searchResultForIndexPath:indexPath];
if (cls == [MWMSearchSuggestionCell class])
auto const row = indexPath.row;
auto const containerIndex = [MWMSearch containerIndexWithIndex:row];
switch ([MWMSearch resultTypeWithIndex:row])
{
NSString * suggestionString = @(result.GetSuggestionString());
case MWMSearchItemTypeRegular:
{
MWMSearchTextField * textField = delegate.searchTextField;
[MWMSearch saveQuery:textField.text forInputLocale:textField.textInputMode.primaryLanguage];
auto result = [MWMSearch resultWithContainerIndex:containerIndex];
[delegate processSearchWithResult:result];
break;
}
case MWMSearchItemTypeMopub: break;
case MWMSearchItemTypeSuggestion:
{
auto suggestion = [MWMSearch resultWithContainerIndex:containerIndex];
NSString * suggestionString = @(suggestion.GetSuggestionString());
[Statistics logEvent:kStatEventName(kStatSearch, kStatSelectResult)
withParameters:@{kStatValue : suggestionString, kStatScreen : kStatSearch}];
[delegate searchText:suggestionString forInputLocale:nil];
}
else if (cls == [MWMSearchCommonCell class])
{
MWMSearchTextField * textField = delegate.searchTextField;
[MWMSearch saveQuery:textField.text forInputLocale:textField.textInputMode.primaryLanguage];
[delegate processSearchWithResult:result];
}
}