diff options
author | Ilya Grechuhin <i.grechuhin@gmail.com> | 2017-09-28 12:23:44 +0300 |
---|---|---|
committer | Roman Kuznetsov <r.kuznetsow@gmail.com> | 2017-09-28 15:31:24 +0300 |
commit | 6737cd92217fdd9e02ee0e19eddc45156e7b104a (patch) | |
tree | 6bb77bf206eb8daffdf71f2441885e4f92245749 | |
parent | 1ae5be9bbb65916abebeea638b66bdd22544fa97 (diff) |
[google] [ios] Added Google banners to search.
-rw-r--r-- | iphone/Maps/Categories/UIView+Hierarchy.swift | 5 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/BannerType.swift | 24 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/BannersCache.swift | 64 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/CoreBanner.swift | 16 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/Facebook/FacebookBanner.swift | 2 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/Google/GoogleFallbackBanner.swift | 137 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/Google/GoogleNativeBanner.swift | 90 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/MWMBanner.h | 4 | ||||
-rw-r--r-- | iphone/Maps/Core/Ads/MWMBannerHelpers.h | 10 | ||||
-rw-r--r-- | iphone/Maps/Core/Search/MWMSearch.mm | 13 | ||||
-rw-r--r-- | iphone/Maps/Core/Search/MWMSearchItemType.h | 1 | ||||
-rw-r--r-- | iphone/Maps/Core/Search/SearchBanners.swift | 3 | ||||
-rw-r--r-- | iphone/Maps/Maps.xcodeproj/project.pbxproj | 27 | ||||
-rw-r--r-- | iphone/Maps/Maps_Prefix.pch | 1 | ||||
-rw-r--r-- | iphone/Maps/UI/Ads/AdBanner.swift | 66 | ||||
-rw-r--r-- | iphone/Maps/UI/Ads/AdBanner.xib | 276 | ||||
-rw-r--r-- | iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm | 23 |
17 files changed, 587 insertions, 175 deletions
diff --git a/iphone/Maps/Categories/UIView+Hierarchy.swift b/iphone/Maps/Categories/UIView+Hierarchy.swift index fc2ce2e376..e76f07a676 100644 --- a/iphone/Maps/Categories/UIView+Hierarchy.swift +++ b/iphone/Maps/Categories/UIView+Hierarchy.swift @@ -2,4 +2,9 @@ extension UIView { @objc func hasSubview(viewClass: AnyClass) -> Bool { return !subviews.filter { type(of: $0) == viewClass }.isEmpty } + + func clearTreeBackground() { + backgroundColor = UIColor.clear + subviews.forEach { $0.clearTreeBackground() } + } } diff --git a/iphone/Maps/Core/Ads/BannerType.swift b/iphone/Maps/Core/Ads/BannerType.swift index e66850037e..aa1ec5f7db 100644 --- a/iphone/Maps/Core/Ads/BannerType.swift +++ b/iphone/Maps/Core/Ads/BannerType.swift @@ -3,15 +3,15 @@ enum BannerType { case facebook(String) case rb(String) case mopub(String) - case google(String) + case google(String, String) var banner: Banner? { switch self { case .none: return nil - case .facebook(let id): return FacebookBanner(bannerID: id) - case .rb(let id): return RBBanner(bannerID: id) - case .mopub(let id): return MopubBanner(bannerID: id) - case .google: return nil + case let .facebook(id): return FacebookBanner(bannerID: id) + case let .rb(id): return RBBanner(bannerID: id) + case let .mopub(id): return MopubBanner(bannerID: id) + case let .google(id, query): return GoogleFallbackBanner(bannerID: id, query: query) } } @@ -25,13 +25,13 @@ enum BannerType { } } - init(type: MWMBannerType, id: String) { + init(type: MWMBannerType, id: String, query: String = "") { switch type { case .none: self = .none case .facebook: self = .facebook(id) case .rb: self = .rb(id) case .mopub: self = .mopub(id) - case .google: self = .google(id) + case .google: self = .google(id, query) } } } @@ -43,7 +43,7 @@ extension BannerType: Equatable { case let (.facebook(l), .facebook(r)): return l == r case let (.rb(l), .rb(r)): return l == r case let (.mopub(l), .mopub(r)): return l == r - case let (.google(l), .google(r)): return l == r + case let (.google(l1, l2), .google(r1, r2)): return l1 == r1 && l2 == r2 case (.none, _), (.facebook, _), (.rb, _), @@ -57,10 +57,10 @@ extension BannerType: Hashable { var hashValue: Int { switch self { case .none: return mwmType.hashValue - case .facebook(let id): return mwmType.hashValue ^ id.hashValue - case .rb(let id): return mwmType.hashValue ^ id.hashValue - case .mopub(let id): return mwmType.hashValue ^ id.hashValue - case .google(let id): return mwmType.hashValue ^ id.hashValue + case let .facebook(id): return mwmType.hashValue ^ id.hashValue + case let .rb(id): return mwmType.hashValue ^ id.hashValue + case let .mopub(id): return mwmType.hashValue ^ id.hashValue + case let .google(id, query): return mwmType.hashValue ^ id.hashValue ^ query.hashValue } } } diff --git a/iphone/Maps/Core/Ads/BannersCache.swift b/iphone/Maps/Core/Ads/BannersCache.swift index e377c71341..edb4cb045d 100644 --- a/iphone/Maps/Core/Ads/BannersCache.swift +++ b/iphone/Maps/Core/Ads/BannersCache.swift @@ -6,10 +6,21 @@ final class BannersCache: NSObject { @objc static let cache = BannersCache() private override init() {} - private enum LoadState { + private enum LoadState: Equatable { case notLoaded(BannerType) case loaded(BannerType) - case error + case error(BannerType) + + static func ==(lhs: LoadState, rhs: LoadState) -> Bool { + switch (lhs, rhs) { + case let (.notLoaded(l), .notLoaded(r)): return l == r + case let (.loaded(l), .loaded(r)): return l == r + case let (.error(l), .error(r)): return l == r + case (.notLoaded, _), + (.loaded, _), + (.error, _): return false + } + } } typealias Completion = (MWMBanner, Bool) -> Void @@ -40,27 +51,41 @@ final class BannersCache: NSObject { completion(banner, isAsync) banner.isBannerOnScreen = true self.completion = nil + loadStates = nil } } @objc func get(coreBanners: [CoreBanner], cacheOnly: Bool, loadNew: Bool = true, completion: @escaping Completion) { self.completion = completion self.cacheOnly = cacheOnly - loadStates = coreBanners.map { coreBanner in - let bannerType = BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID) + loadStates = loadStates ?? [] + coreBanners.forEach { coreBanner in + let bannerType = BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID, query: coreBanner.query) if let banner = cache[bannerType], (!banner.isPossibleToReload || banner.isNeedToRetain) { - return .loaded(bannerType) + appendLoadState(.loaded(bannerType)) } else { if loadNew { get(bannerType: bannerType) } - return .notLoaded(bannerType) + appendLoadState(.notLoaded(bannerType)) } } onCompletion(isAsync: false) } + @objc func refresh(coreBanners: [CoreBanner]) { + loadStates = loadStates ?? [] + coreBanners.forEach { coreBanner in + let bannerType = BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID, query: coreBanner.query) + let state = LoadState.notLoaded(bannerType) + if loadStates.index(of: state) == nil { + get(bannerType: bannerType) + appendLoadState(state) + } + } + } + private func get(bannerType: BannerType) { guard requests[bannerType] == nil else { return } @@ -81,6 +106,11 @@ final class BannersCache: NSObject { }) } + private func appendLoadState(_ state: LoadState) { + guard loadStates.index(of: state) == nil else { return } + loadStates.append(state) + } + private func notLoadedIndex(bannerType: BannerType) -> Array<LoadState>.Index? { return loadStates.index(where: { if case let .notLoaded(type) = $0, type == bannerType { @@ -92,22 +122,30 @@ final class BannersCache: NSObject { private func setLoaded(banner: Banner) { let bannerType = banner.type - if let notLoadedIndex = notLoadedIndex(bannerType: bannerType) { - loadStates[notLoadedIndex] = .loaded(bannerType) - } cache[bannerType] = banner requests[bannerType] = nil + + guard loadStates != nil else { return } + + if let notLoadedIndex = loadStates.index(of: .notLoaded(bannerType)) { + loadStates[notLoadedIndex] = .loaded(bannerType) + } if !cacheOnly { onCompletion(isAsync: true) } } private func setError(bannerType: BannerType) { - if let notLoadedIndex = notLoadedIndex(bannerType: bannerType) { - loadStates[notLoadedIndex] = .error - } requests[bannerType] = nil - onCompletion(isAsync: true) + + guard loadStates != nil else { return } + + if let notLoadedIndex = loadStates.index(of: .notLoaded(bannerType)) { + loadStates[notLoadedIndex] = .error(bannerType) + } + if !cacheOnly { + onCompletion(isAsync: true) + } } @objc func bannerIsOutOfScreen(coreBanner: MWMBanner) { diff --git a/iphone/Maps/Core/Ads/CoreBanner.swift b/iphone/Maps/Core/Ads/CoreBanner.swift index da09c3bcdd..91a5ed2324 100644 --- a/iphone/Maps/Core/Ads/CoreBanner.swift +++ b/iphone/Maps/Core/Ads/CoreBanner.swift @@ -2,9 +2,23 @@ final class CoreBanner: NSObject, MWMBanner { let mwmType: MWMBannerType let bannerID: String + let query: String - @objc init(mwmType: MWMBannerType, bannerID: String) { + @objc init(mwmType: MWMBannerType, bannerID: String, query: String) { self.mwmType = mwmType self.bannerID = bannerID + self.query = query + } + + override var debugDescription: String { + let type: String + switch mwmType { + case .none: type = "none" + case .facebook: type = "facebook" + case .rb: type = "rb" + case .mopub: type = "mopub" + case .google: type = "google" + } + return "Type: <\(type)> | id: <\(bannerID)> | query: <\(query)>" } } diff --git a/iphone/Maps/Core/Ads/Facebook/FacebookBanner.swift b/iphone/Maps/Core/Ads/Facebook/FacebookBanner.swift index b6b61ddc09..96169335d9 100644 --- a/iphone/Maps/Core/Ads/Facebook/FacebookBanner.swift +++ b/iphone/Maps/Core/Ads/Facebook/FacebookBanner.swift @@ -131,7 +131,7 @@ extension FacebookBanner: FBNativeAdDelegate { guard nativeAd === self.nativeAd else { return } // https://developers.facebook.com/docs/audience-network/testing - var params: [String: Any] = [kStatBanner: nativeAd.placementID, kStatProvider: kStatFacebook] + var params: [String: Any] = statisticsDescription let e = error as NSError let event: String diff --git a/iphone/Maps/Core/Ads/Google/GoogleFallbackBanner.swift b/iphone/Maps/Core/Ads/Google/GoogleFallbackBanner.swift new file mode 100644 index 0000000000..05e56e67f2 --- /dev/null +++ b/iphone/Maps/Core/Ads/Google/GoogleFallbackBanner.swift @@ -0,0 +1,137 @@ +import GoogleMobileAds + +@objc(MWMGoogleFallbackBannerDynamicSizeDelegate) +protocol GoogleFallbackBannerDynamicSizeDelegate { + func dynamicSizeUpdated(banner: GoogleFallbackBanner) +} + +@objc(MWMGoogleFallbackBanner) +final class GoogleFallbackBanner: GADSearchBannerView, Banner { + private enum Limits { + static let minTimeSinceLastRequest: TimeInterval = 5 + } + + fileprivate var success: Banner.Success! + fileprivate var failure: Banner.Failure! + fileprivate var click: Banner.Click! + + private var requestDate: Date? + var isBannerOnScreen: Bool = false + var isNeedToRetain: Bool { return true } + var isPossibleToReload: Bool { + if let date = requestDate { + return Date().timeIntervalSince(date) > Limits.minTimeSinceLastRequest + } + return true + } + var type: BannerType { return .google(bannerID, query) } + var mwmType: MWMBannerType { return type.mwmType } + var bannerID: String! { return adUnitID } + var statisticsDescription: [String: String] { + return [kStatBanner: bannerID, kStatProvider: kStatGoogle] + } + let query: String + + @objc var dynamicSizeDelegate: GoogleFallbackBannerDynamicSizeDelegate? + fileprivate(set) var dynamicSize = CGSize.zero { + didSet { + dynamicSizeDelegate?.dynamicSizeUpdated(banner: self) + } + } + @objc var cellIndexPath: IndexPath! + + init(bannerID: String, query: String) { + self.query = query + super.init(adSize: kGADAdSizeFluid) + adUnitID = bannerID + frame = CGRect.zero + + delegate = self + adSizeDelegate = self + } + + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func reload(success: @escaping Success, failure: @escaping Failure, click: @escaping Click) { + self.success = success + self.failure = failure + self.click = click + + let searchRequest = GADDynamicHeightSearchRequest() + searchRequest.query = query + searchRequest.numberOfAds = 1 + if let loc = MWMLocationManager.lastLocation() { + searchRequest.setLocationWithLatitude(CGFloat(loc.coordinate.latitude), + longitude: CGFloat(loc.coordinate.longitude), + accuracy: CGFloat(loc.horizontalAccuracy)) + } + searchRequest.cssWidth = "100%" + let isNightMode = UIColor.isNightMode() + searchRequest.adBorderCSSSelections = "bottom" + searchRequest.adBorderColor = isNightMode ? "#53575A" : "#E0E0E0" + searchRequest.adjustableLineHeight = 18 + searchRequest.annotationFontSize = 12 + searchRequest.annotationTextColor = isNightMode ? "#C8C9CA" : "#75726D" + searchRequest.attributionBottomSpacing = 4 + searchRequest.attributionFontSize = 12 + searchRequest.attributionTextColor = isNightMode ? "#C8C9CA" : "#75726D" + searchRequest.backgroundColor = isNightMode ? "#484B50" : "#FFF9EF" + searchRequest.boldTitleEnabled = true + searchRequest.clickToCallExtensionEnabled = true + searchRequest.descriptionFontSize = 12 + searchRequest.domainLinkColor = isNightMode ? "#51B5E6" : "#1E96F0" + searchRequest.domainLinkFontSize = 12 + searchRequest.locationExtensionEnabled = true + searchRequest.locationExtensionFontSize = 12 + searchRequest.locationExtensionTextColor = isNightMode ? "#C8C9CA" : "#75726D" + searchRequest.sellerRatingsExtensionEnabled = false + searchRequest.siteLinksExtensionEnabled = false + searchRequest.textColor = isNightMode ? "#C8C9CA" : "#75726D" + searchRequest.titleFontSize = 12 + searchRequest.titleLinkColor = isNightMode ? "#FFFFFF" : "#21201E" + searchRequest.titleUnderlineHidden = true + + load(searchRequest) + requestDate = Date() + } + + func unregister() {} + + static func ==(lhs: GoogleFallbackBanner, rhs: GoogleFallbackBanner) -> Bool { + return lhs.adUnitID == rhs.adUnitID && lhs.query == rhs.query + } +} + +extension GoogleFallbackBanner: GADBannerViewDelegate { + func adViewDidReceiveAd(_ bannerView: GADBannerView) { + guard let banner = bannerView as? GoogleFallbackBanner, banner == self else { return } + success(self) + } + + func adView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: GADRequestError) { + guard let banner = bannerView as? GoogleFallbackBanner, banner == self else { return } + var params: [String: Any] = statisticsDescription + params[kStatErrorCode] = error.code + + failure(type, kStatPlacePageBannerError, params, error) + } + + func adViewWillPresentScreen(_: GADBannerView) { + click(self) + } + + func adViewWillLeaveApplication(_: GADBannerView) { + click(self) + } +} + +extension GoogleFallbackBanner: GADAdSizeDelegate { + func adView(_: GADBannerView, willChangeAdSizeTo size: GADAdSize) { + var newFrame = frame + newFrame.size.height = size.size.height + frame = newFrame + dynamicSize = size.size + } +} diff --git a/iphone/Maps/Core/Ads/Google/GoogleNativeBanner.swift b/iphone/Maps/Core/Ads/Google/GoogleNativeBanner.swift new file mode 100644 index 0000000000..bef821b460 --- /dev/null +++ b/iphone/Maps/Core/Ads/Google/GoogleNativeBanner.swift @@ -0,0 +1,90 @@ +import GoogleMobileAds + +final class GoogleNativeBanner: NSObject, Banner { + private enum Limits { + static let minTimeSinceLastRequest: TimeInterval = 5 + } + + fileprivate var success: Banner.Success! + fileprivate var failure: Banner.Failure! + fileprivate var click: Banner.Click! + + private var requestDate: Date? + var isBannerOnScreen: Bool = false + var isNeedToRetain: Bool { return true } + var isPossibleToReload: Bool { + if let date = requestDate { + return Date().timeIntervalSince(date) > Limits.minTimeSinceLastRequest + } + return true + } + var type: BannerType { return .google(bannerID, query) } + var mwmType: MWMBannerType { return type.mwmType } + var bannerID: String! { return adLoader.adUnitID } + var statisticsDescription: [String: String] { + return [kStatBanner: bannerID, kStatProvider: kStatGoogle] + } + private let query: String + private let adLoader: GADAdLoader + + fileprivate var nativeAd: GADNativeAd! + + init(bannerID _: String, query: String) { + self.query = query + adLoader = GADAdLoader(adUnitID: "ca-app-pub-6656946757675080/8014770099", + rootViewController: UIViewController.topViewController(), + adTypes: [GADAdLoaderAdType.nativeAppInstall, GADAdLoaderAdType.nativeContent], + options: nil) + super.init() + adLoader.delegate = self + } + + func reload(success: @escaping Success, failure: @escaping Failure, click: @escaping Click) { + self.success = success + self.failure = failure + self.click = click + + let request = GADSearchRequest() + request.testDevices = [kGADSimulatorID] + request.query = query + if let loc = MWMLocationManager.lastLocation() { + request.setLocationWithLatitude(CGFloat(loc.coordinate.latitude), + longitude: CGFloat(loc.coordinate.longitude), + accuracy: CGFloat(loc.horizontalAccuracy)) + } + + adLoader.load(request) + requestDate = Date() + } + + func unregister() { + switch nativeAd { + case let nativeAppInstallAd as GADNativeAppInstallAd: nativeAppInstallAd.unregisterAdView() + case let nativeContentAd as GADNativeContentAd: nativeContentAd.unregisterAdView() + default: assert(false) + } + } +} + +extension GoogleNativeBanner: GADAdLoaderDelegate { + func adLoader(_: GADAdLoader, didFailToReceiveAdWithError error: GADRequestError) { + var params: [String: Any] = statisticsDescription + params[kStatErrorCode] = error.code + + failure(type, kStatPlacePageBannerError, params, error) + } +} + +extension GoogleNativeBanner: GADNativeAppInstallAdLoaderDelegate { + func adLoader(_: GADAdLoader, didReceive nativeAppInstallAd: GADNativeAppInstallAd) { + nativeAd = nativeAppInstallAd + success(self) + } +} + +extension GoogleNativeBanner: GADNativeContentAdLoaderDelegate { + func adLoader(_: GADAdLoader, didReceive nativeContentAd: GADNativeContentAd) { + nativeAd = nativeContentAd + success(self) + } +} diff --git a/iphone/Maps/Core/Ads/MWMBanner.h b/iphone/Maps/Core/Ads/MWMBanner.h index 1766a78a48..b16f1912e9 100644 --- a/iphone/Maps/Core/Ads/MWMBanner.h +++ b/iphone/Maps/Core/Ads/MWMBanner.h @@ -6,7 +6,7 @@ typedef NS_ENUM(NSInteger, MWMBannerType) { MWMBannerTypeGoogle }; -@protocol MWMBanner +@protocol MWMBanner <NSObject> @property(nonatomic, readonly) enum MWMBannerType mwmType; -@property(nonatomic, readonly) NSString * bannerID; +@property(copy, nonatomic, readonly) NSString * bannerID; @end diff --git a/iphone/Maps/Core/Ads/MWMBannerHelpers.h b/iphone/Maps/Core/Ads/MWMBannerHelpers.h index 4662ee60a9..a4000339bb 100644 --- a/iphone/Maps/Core/Ads/MWMBannerHelpers.h +++ b/iphone/Maps/Core/Ads/MWMBannerHelpers.h @@ -19,18 +19,18 @@ static inline MWMBannerType MatchBannerType(ads::Banner::Type coreType) } } -static inline MWMCoreBanner * MatchBanner(ads::Banner const & banner) +static inline MWMCoreBanner * MatchBanner(ads::Banner const & banner, NSString * query) { return [[MWMCoreBanner alloc] initWithMwmType:MatchBannerType(banner.m_type) - bannerID:@(banner.m_bannerId.c_str())]; + bannerID:@(banner.m_bannerId.c_str()) + query:query]; } -static inline NSArray<MWMCoreBanner *> * MatchPriorityBanners( - std::vector<ads::Banner> const & banners) +static inline NSArray<MWMCoreBanner *> * MatchPriorityBanners(std::vector<ads::Banner> const & banners, NSString * query = @"") { NSMutableArray<MWMCoreBanner *> * mBanners = [@[] mutableCopy]; for (auto const & banner : banners) - [mBanners addObject:MatchBanner(banner)]; + [mBanners addObject:MatchBanner(banner, query)]; return [mBanners copy]; } } diff --git a/iphone/Maps/Core/Search/MWMSearch.mm b/iphone/Maps/Core/Search/MWMSearch.mm index 3ada774ff3..0f6658329a 100644 --- a/iphone/Maps/Core/Search/MWMSearch.mm +++ b/iphone/Maps/Core/Search/MWMSearch.mm @@ -44,6 +44,8 @@ using Observers = NSHashTable<Observer>; @property(nonatomic) NSInteger searchCount; +@property(copy, nonatomic) NSString * lastQuery; + @end @implementation MWMSearch @@ -220,10 +222,17 @@ using Observers = NSHashTable<Observer>; manager->m_everywhereParams.m_inputLocale = locale; manager->m_viewportParams.m_inputLocale = locale; } - string const text = query.precomposedStringWithCompatibilityMapping.UTF8String; + manager.lastQuery = query.precomposedStringWithCompatibilityMapping; + string const text = manager.lastQuery.UTF8String; manager->m_everywhereParams.m_query = text; manager->m_viewportParams.m_query = text; manager.textChanged = YES; + auto const & adsEngine = GetFramework().GetAdsEngine(); + if (![MWMSettings adForbidden] && adsEngine.HasSearchBanner()) + { + auto coreBanners = banner_helpers::MatchPriorityBanners(adsEngine.GetSearchBanners(), manager.lastQuery); + [[MWMBannersCache cache] refreshWithCoreBanners:coreBanners]; + } [manager update]; } @@ -326,7 +335,7 @@ using Observers = NSHashTable<Observer>; self.banners = [[MWMSearchBanners alloc] initWithSearchIndex:itemsIndex]; __weak auto weakSelf = self; [[MWMBannersCache cache] - getWithCoreBanners:banner_helpers::MatchPriorityBanners(adsEngine.GetSearchBanners()) + getWithCoreBanners:banner_helpers::MatchPriorityBanners(adsEngine.GetSearchBanners(), self.lastQuery) cacheOnly:YES loadNew:reloadBanner completion:^(id<MWMBanner> ad, BOOL isAsync) { diff --git a/iphone/Maps/Core/Search/MWMSearchItemType.h b/iphone/Maps/Core/Search/MWMSearchItemType.h index 77bd68e899..f6fa223d39 100644 --- a/iphone/Maps/Core/Search/MWMSearchItemType.h +++ b/iphone/Maps/Core/Search/MWMSearchItemType.h @@ -3,5 +3,6 @@ typedef NS_ENUM(NSUInteger, MWMSearchItemType) { MWMSearchItemTypeRegular, MWMSearchItemTypeMopub, MWMSearchItemTypeFacebook, + MWMSearchItemTypeGoogle, MWMSearchItemTypeSuggestion }; diff --git a/iphone/Maps/Core/Search/SearchBanners.swift b/iphone/Maps/Core/Search/SearchBanners.swift index a395fd6c53..2f27fe7836 100644 --- a/iphone/Maps/Core/Search/SearchBanners.swift +++ b/iphone/Maps/Core/Search/SearchBanners.swift @@ -21,6 +21,9 @@ final class SearchBanners: NSObject { case .facebook: type = .facebook prefferedPosition = 2 + case .google: + type = .google + prefferedPosition = 4 default: assert(false, "Unsupported banner type") type = .regular diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index fe8225210e..0c6113fb62 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -108,6 +108,9 @@ 340475801E081B3300C92850 /* iosOGLContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3404757C1E081B3300C92850 /* iosOGLContextFactory.mm */; }; 340475811E081B3300C92850 /* iosOGLContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3404757C1E081B3300C92850 /* iosOGLContextFactory.mm */; }; 340475821E081B3300C92850 /* iosOGLContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3404757C1E081B3300C92850 /* iosOGLContextFactory.mm */; }; + 34065A101F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34065A0F1F45E7F8006684E5 /* GoogleFallbackBanner.swift */; }; + 34065A111F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34065A0F1F45E7F8006684E5 /* GoogleFallbackBanner.swift */; }; + 34065A121F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34065A0F1F45E7F8006684E5 /* GoogleFallbackBanner.swift */; }; 3406FA151C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3406FA141C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm */; }; 3406FA161C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3406FA141C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm */; }; 3406FA181C6E0D8F00E9FAD2 /* MWMMapDownloadDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3406FA171C6E0D8F00E9FAD2 /* MWMMapDownloadDialog.xib */; }; @@ -175,6 +178,9 @@ 340E1EFE1E2F614400CE49BF /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 340E1EEA1E2F614400CE49BF /* Welcome.storyboard */; }; 340E1EFF1E2F614400CE49BF /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 340E1EEA1E2F614400CE49BF /* Welcome.storyboard */; }; 3411387D1C15AE73002E3B3E /* libeditor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3411387C1C15AE73002E3B3E /* libeditor.a */; }; + 3411E7631F7CE5DD00A49FCD /* GoogleMobileAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3411E7621F7CE5DC00A49FCD /* GoogleMobileAds.framework */; }; + 3411E7641F7CE5DF00A49FCD /* GoogleMobileAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3411E7621F7CE5DC00A49FCD /* GoogleMobileAds.framework */; }; + 3411E7651F7CE5E000A49FCD /* GoogleMobileAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3411E7621F7CE5DC00A49FCD /* GoogleMobileAds.framework */; }; 341522BF1B666A550077AA8F /* MWMAPIBarView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 341522BE1B666A550077AA8F /* MWMAPIBarView.mm */; }; 341B10761E55B15B00071C74 /* MWMMobileInternetAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = 349A13811DEC138C00C7DB60 /* MWMMobileInternetAlert.xib */; }; 341C2A571B72092A00AD41A1 /* 02_droidsans-fallback.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9DF04B231B71010E00DACAF1 /* 02_droidsans-fallback.ttf */; }; @@ -529,6 +535,9 @@ 34BC72241B0DECAE0012A34B /* MWMMapViewControlsManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34BC72111B0DECAE0012A34B /* MWMMapViewControlsManager.mm */; }; 34BF0CC61C31304A00D097EB /* MWMAuthorizationCommon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34BF0CC51C31304A00D097EB /* MWMAuthorizationCommon.mm */; }; 34BF0CC71C31304A00D097EB /* MWMAuthorizationCommon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34BF0CC51C31304A00D097EB /* MWMAuthorizationCommon.mm */; }; + 34C0A69C1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C0A69B1F4C1B380007CE5B /* GoogleNativeBanner.swift */; }; + 34C0A69D1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C0A69B1F4C1B380007CE5B /* GoogleNativeBanner.swift */; }; + 34C0A69E1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C0A69B1F4C1B380007CE5B /* GoogleNativeBanner.swift */; }; 34C5B80F1F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C5B80E1F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift */; }; 34C5B8101F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C5B80E1F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift */; }; 34C5B8111F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C5B80E1F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift */; }; @@ -1825,6 +1834,7 @@ 3404757B1E081B3300C92850 /* iosOGLContextFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iosOGLContextFactory.h; sourceTree = "<group>"; }; 3404757C1E081B3300C92850 /* iosOGLContextFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = iosOGLContextFactory.mm; sourceTree = "<group>"; }; 340537621BBED98600D452C6 /* MWMMapViewControlsCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MWMMapViewControlsCommon.h; path = APIBar/MWMMapViewControlsCommon.h; sourceTree = "<group>"; }; + 34065A0F1F45E7F8006684E5 /* GoogleFallbackBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleFallbackBanner.swift; sourceTree = "<group>"; }; 3406FA131C6E0C3300E9FAD2 /* MWMMapDownloadDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloadDialog.h; sourceTree = "<group>"; }; 3406FA141C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloadDialog.mm; sourceTree = "<group>"; }; 3406FA171C6E0D8F00E9FAD2 /* MWMMapDownloadDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMMapDownloadDialog.xib; sourceTree = "<group>"; }; @@ -2070,6 +2080,7 @@ 34BC72111B0DECAE0012A34B /* MWMMapViewControlsManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMMapViewControlsManager.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 34BF0CC51C31304A00D097EB /* MWMAuthorizationCommon.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMAuthorizationCommon.mm; sourceTree = "<group>"; }; 34BF0CC81C31306300D097EB /* MWMAuthorizationCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMAuthorizationCommon.h; sourceTree = "<group>"; }; + 34C0A69B1F4C1B380007CE5B /* GoogleNativeBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleNativeBanner.swift; sourceTree = "<group>"; }; 34C5B80E1F335BA8005E50B6 /* RouteManagerViewModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteManagerViewModelProtocol.swift; sourceTree = "<group>"; }; 34C5B8121F335BCA005E50B6 /* RouteManagerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteManagerViewModel.swift; sourceTree = "<group>"; }; 34C5B81A1F3367E1005E50B6 /* RouteManagerTransitioningManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteManagerTransitioningManager.swift; sourceTree = "<group>"; }; @@ -3152,6 +3163,15 @@ path = Traffic; sourceTree = "<group>"; }; + 34065A0E1F45E7E1006684E5 /* Google */ = { + isa = PBXGroup; + children = ( + 34065A0F1F45E7F8006684E5 /* GoogleFallbackBanner.swift */, + 34C0A69B1F4C1B380007CE5B /* GoogleNativeBanner.swift */, + ); + path = Google; + sourceTree = "<group>"; + }; 340837101B7243B500B5C185 /* Share */ = { isa = PBXGroup; children = ( @@ -3717,6 +3737,7 @@ 34F4071C1E9E1AFF00E57AC0 /* Ads */ = { isa = PBXGroup; children = ( + 34065A0E1F45E7E1006684E5 /* Google */, 34F4071D1E9E1AFF00E57AC0 /* Banner.swift */, 34F4071E1E9E1AFF00E57AC0 /* BannersCache.swift */, 34F4071F1E9E1AFF00E57AC0 /* BannerType.swift */, @@ -5775,6 +5796,7 @@ 340837131B7243CE00B5C185 /* MWMActivityViewController.mm in Sources */, 3486B5181E27AD3B0069C126 /* MWMFrameworkListener.mm in Sources */, 3404756A1E081A4600C92850 /* MWMSearch+CoreSpotlight.mm in Sources */, + 34065A101F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */, F653CE111C6DEB5A00A453F1 /* MWMDropDown.mm in Sources */, 3404755B1E081A4600C92850 /* MWMLocationManager.mm in Sources */, 3454D7BB1E07F045004AF2AD /* CLLocation+Mercator.mm in Sources */, @@ -5859,6 +5881,7 @@ 34B924421DC8A29C0008D971 /* MWMMailViewController.mm in Sources */, 34E7760F1F14B165003040B3 /* VisibleArea.swift in Sources */, F6E2FF171E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */, + 34C0A69C1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */, F64F199B1AB81A00006EAF7E /* MWMAlert.mm in Sources */, 3488B0191E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */, 34AC8FD01EFC028600E7F910 /* NavigationAddPointToastView.swift in Sources */, @@ -6120,6 +6143,7 @@ F626D52F1C3E83F800C17D15 /* MWMTableViewCell.mm in Sources */, 3486B5191E27AD3B0069C126 /* MWMFrameworkListener.mm in Sources */, 3404756B1E081A4600C92850 /* MWMSearch+CoreSpotlight.mm in Sources */, + 34065A111F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */, F653CE121C6DEC8E00A453F1 /* MWMDropDown.mm in Sources */, 3404755C1E081A4600C92850 /* MWMLocationManager.mm in Sources */, 3454D7BC1E07F045004AF2AD /* CLLocation+Mercator.mm in Sources */, @@ -6204,6 +6228,7 @@ F6E2FF181E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */, 346DB83D1E5C4F6700E3123E /* GalleryModel.swift in Sources */, 34E776101F14B165003040B3 /* VisibleArea.swift in Sources */, + 34C0A69D1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */, 3454D7D71E07F045004AF2AD /* UIKitCategories.mm in Sources */, 34AB39C21D2BD8310021857D /* MWMStopButton.mm in Sources */, 3488B01A1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */, @@ -6465,6 +6490,7 @@ 849CF7151DE842290024A8A5 /* MWMInputEmailValidator.mm in Sources */, 3486B51A1E27AD3B0069C126 /* MWMFrameworkListener.mm in Sources */, 845E4B1D1DEC83AE00D6BED8 /* MWMMobileInternetAlert.mm in Sources */, + 34065A121F45E7F8006684E5 /* GoogleFallbackBanner.swift in Sources */, 849CF7171DE842290024A8A5 /* BookmarksRootVC.mm in Sources */, 849CF7191DE842290024A8A5 /* MWMActivityViewController.mm in Sources */, 849CF71A1DE842290024A8A5 /* MWMDropDown.mm in Sources */, @@ -6549,6 +6575,7 @@ 346DB83E1E5C4F6700E3123E /* GalleryModel.swift in Sources */, 849CF7611DE842290024A8A5 /* MWMMailViewController.mm in Sources */, 34E776111F14B165003040B3 /* VisibleArea.swift in Sources */, + 34C0A69E1F4C1B380007CE5B /* GoogleNativeBanner.swift in Sources */, F6E2FF191E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */, 3404754E1E081A4600C92850 /* MWMKeyboard.mm in Sources */, 3488B01B1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */, diff --git a/iphone/Maps/Maps_Prefix.pch b/iphone/Maps/Maps_Prefix.pch index 19d5cc075e..9935ab9240 100644 --- a/iphone/Maps/Maps_Prefix.pch +++ b/iphone/Maps/Maps_Prefix.pch @@ -5,6 +5,7 @@ #ifdef __OBJC__ #import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> + #import <GoogleMobileAds/GoogleMobileAds.h> #import "MWMConsts.h" #import "MWMMacros.h" diff --git a/iphone/Maps/UI/Ads/AdBanner.swift b/iphone/Maps/UI/Ads/AdBanner.swift index f0b615f84d..f1ecc92999 100644 --- a/iphone/Maps/UI/Ads/AdBanner.swift +++ b/iphone/Maps/UI/Ads/AdBanner.swift @@ -41,8 +41,30 @@ final class AdBanner: UITableViewCell { @IBOutlet private weak var adCallToActionButtonDetailed: UIButton! @IBOutlet private weak var adCallToActionButtonCustom: UIButton! @IBOutlet private weak var adPrivacyButton: UIButton! + @IBOutlet private weak var nativeAdView: UIView! + @IBOutlet private weak var fallbackAdView: UIView! + @IBOutlet private var nativeAdViewBottom: NSLayoutConstraint! + @IBOutlet private var fallbackAdViewBottom: NSLayoutConstraint! + @IBOutlet private var fallbackAdViewHeight: NSLayoutConstraint! @objc static let detailedBannerExcessHeight: Float = 36 + enum AdType { + case native + case fallback + } + + var adType = AdType.native { + didSet { + let isNative = adType == .native + nativeAdView.isHidden = !isNative + fallbackAdView.isHidden = isNative + + nativeAdViewBottom.isActive = isNative + fallbackAdViewBottom.isActive = !isNative + fallbackAdViewHeight.isActive = !isNative + } + } + @objc var state = AdBannerState.unset { didSet { guard state != .unset else { @@ -82,6 +104,14 @@ final class AdBanner: UITableViewCell { } } + override func layoutSubviews() { + super.layoutSubviews() + switch nativeAd { + case let ad as GoogleFallbackBanner: updateFallbackBannerLayout(ad: ad) + default: break + } + } + func reset() { state = .unset } @@ -96,17 +126,13 @@ final class AdBanner: UITableViewCell { } nativeAd = ad as? Banner - switch ad.mwmType { - case .none: - assert(false) - case .facebook: - configFBBanner(ad: (ad as! FacebookBanner).nativeAd) - case .rb: - configRBBanner(ad: ad as! MTRGNativeAd) - case .mopub: - configMopubBanner(ad: ad as! MopubBanner) - case .google: - assert(false) + switch ad { + case let ad as FacebookBanner: configFBBanner(ad: ad.nativeAd) + case let ad as RBBanner: configRBBanner(ad: ad) + case let ad as MopubBanner: configMopubBanner(ad: ad) + case let ad as GoogleFallbackBanner: configGoogleFallbackBanner(ad: ad) + case let ad as GoogleNativeBanner: configGoogleNativeBanner(ad: ad) + default: assert(false) } } @@ -133,6 +159,7 @@ final class AdBanner: UITableViewCell { } private func configFBBanner(ad: FBNativeAd) { + adType = .native let adCallToActionButtons: [UIView] if state == .search { adCallToActionButtons = [self, adCallToActionButtonCompact] @@ -164,6 +191,7 @@ final class AdBanner: UITableViewCell { private func configRBBanner(ad: MTRGNativeAd) { guard let banner = ad.banner else { return } + adType = .native MTRGNativeAd.loadImage(banner.icon, to: adIconImageView) @@ -188,6 +216,7 @@ final class AdBanner: UITableViewCell { private func configMopubBanner(ad: MopubBanner) { mpNativeAd = ad.nativeAd + adType = .native let adCallToActionButtons: [UIButton] if state == .search { @@ -216,6 +245,21 @@ final class AdBanner: UITableViewCell { adPrivacyButton.isHidden = ad.privacyInfoURL == nil } + private func configGoogleFallbackBanner(ad: GoogleFallbackBanner) { + adType = .fallback + fallbackAdView.subviews.forEach { $0.removeFromSuperview() } + fallbackAdView.addSubview(ad) + updateFallbackBannerLayout(ad: ad) + } + + private func updateFallbackBannerLayout(ad: GoogleFallbackBanner) { + ad.width = fallbackAdView.width + fallbackAdViewHeight.constant = ad.dynamicSize.height + } + + private func configGoogleNativeBanner(ad _: GoogleNativeBanner) { + } + private func refreshBannerIfNeeded() { if let ad = nativeAd as? MTRGNativeAd { let clickableView: UIView diff --git a/iphone/Maps/UI/Ads/AdBanner.xib b/iphone/Maps/UI/Ads/AdBanner.xib index 481d13b578..e7143623c2 100644 --- a/iphone/Maps/UI/Ads/AdBanner.xib +++ b/iphone/Maps/UI/Ads/AdBanner.xib @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12118" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" 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="12086"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> @@ -14,144 +14,167 @@ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WK2-gA-ocn" customClass="MWMAdBanner"> <rect key="frame" x="0.0" y="0.0" width="375" height="110"/> <autoresizingMask key="autoresizingMask"/> - <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WK2-gA-ocn" id="f76-qn-ne4"> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WK2-gA-ocn" id="f76-qn-ne5"> <rect key="frame" x="0.0" y="0.0" width="375" height="109.5"/> <autoresizingMask key="autoresizingMask"/> <subviews> - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="EuF-Rm-DHQ"> - <rect key="frame" x="-40" y="8" width="40" height="40"/> - <constraints> - <constraint firstAttribute="width" constant="40" id="dih-tk-IV1"/> - <constraint firstAttribute="height" constant="40" id="eTa-1E-6Of"/> - </constraints> - </imageView> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zWu-Gh-Vf7"> - <rect key="frame" x="16" y="10" width="20" height="12"/> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="f76-qn-ne4"> + <rect key="frame" x="0.0" y="0.0" width="375" height="109.5"/> <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ads" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iWR-j0-gpt"> - <rect key="frame" x="0.0" y="0.0" width="20" height="12"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> - <fontDescription key="fontDescription" type="system" weight="medium" pointSize="8"/> - <color key="textColor" red="1" green="0.98431372549019602" blue="0.94901960784313721" alpha="1" colorSpace="calibratedRGB"/> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="EuF-Rm-DHQ"> + <rect key="frame" x="-40" y="8" width="40" height="40"/> + <constraints> + <constraint firstAttribute="width" constant="40" id="dih-tk-IV1"/> + <constraint firstAttribute="height" constant="40" id="eTa-1E-6Of"/> + </constraints> + </imageView> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zWu-Gh-Vf7"> + <rect key="frame" x="16" y="10" width="20" height="12"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ads" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iWR-j0-gpt"> + <rect key="frame" x="0.0" y="0.0" width="20" height="12"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="8"/> + <color key="textColor" red="1" green="0.98431372549019602" blue="0.94901960784313721" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.23999999999999999" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="iWR-j0-gpt" firstAttribute="top" secondItem="zWu-Gh-Vf7" secondAttribute="top" id="1Ar-tP-Uoj"/> + <constraint firstAttribute="width" constant="20" id="TMB-lh-n1g"/> + <constraint firstAttribute="bottom" secondItem="iWR-j0-gpt" secondAttribute="bottom" id="j0v-gq-9l0"/> + <constraint firstAttribute="trailing" secondItem="iWR-j0-gpt" secondAttribute="trailing" id="jDy-yc-aSX"/> + <constraint firstAttribute="height" constant="12" id="mwW-Ni-one"/> + <constraint firstItem="iWR-j0-gpt" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="zek-Of-Clw"/> + </constraints> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="300" text="Delivery Club" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kIR-cO-v6L"> + <rect key="frame" x="16" y="8" width="270" height="15"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> <nil key="highlightedColor"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="bold12"/> + <userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/> + </userDefinedRuntimeAttributes> </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="451" verticalHuggingPriority="249" horizontalCompressionResistancePriority="249" text="Как " textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ev3-yY-ql1"> + <rect key="frame" x="16" y="27" width="270" height="74.5"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/> + <userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/> + </userDefinedRuntimeAttributes> + </label> + <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="551" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9qA-JC-fkn"> + <rect key="frame" x="290" y="18" width="69" height="24"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="64" id="N7a-ng-e6p"/> + <constraint firstAttribute="height" constant="24" id="XME-fd-3O8"/> + </constraints> + <fontDescription key="fontDescription" type="system" pointSize="12"/> + <inset key="contentEdgeInsets" minX="8" minY="0.0" maxX="8" maxY="0.0"/> + <state key="normal" title="Заказать"> + <color key="titleColor" red="0.59999999999999998" green="0.58823529411764708" blue="0.56862745098039214" alpha="0.40000000000000002" colorSpace="calibratedRGB"/> + </state> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/> + <userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="blackSecondaryText"/> + <userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor"> + <color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth"> + <integer key="value" value="1"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius"> + <integer key="value" value="4"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NKM-3R-3g1"> + <rect key="frame" x="0.0" y="109.5" width="375" height="36"/> + <color key="backgroundColor" red="0.95294117647058818" green="0.92156862745098034" blue="0.85490196078431369" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="36" id="JMM-je-O9e"/> + </constraints> + <state key="normal" title="Заказать"> + <color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="0.40000000000000002" colorSpace="calibratedRGB"/> + </state> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular15"/> + <userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="bannerButtonBackground"/> + <userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="blackSecondaryText"/> + </userDefinedRuntimeAttributes> + </button> + <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="54O-iN-1Gg"> + <rect key="frame" x="0.0" y="0.0" width="375" height="109.5"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </button> + <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="So8-wM-Cgz"> + <rect key="frame" x="14" y="8" width="24" height="16"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + <connections> + <action selector="privacyAction" destination="WK2-gA-ocn" eventType="touchUpInside" id="ma2-uV-7hH"/> + </connections> + </button> </subviews> - <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.23999999999999999" colorSpace="calibratedRGB"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <constraints> - <constraint firstItem="iWR-j0-gpt" firstAttribute="top" secondItem="zWu-Gh-Vf7" secondAttribute="top" id="1Ar-tP-Uoj"/> - <constraint firstAttribute="width" constant="20" id="TMB-lh-n1g"/> - <constraint firstAttribute="bottom" secondItem="iWR-j0-gpt" secondAttribute="bottom" id="j0v-gq-9l0"/> - <constraint firstAttribute="trailing" secondItem="iWR-j0-gpt" secondAttribute="trailing" id="jDy-yc-aSX"/> - <constraint firstAttribute="height" constant="12" id="mwW-Ni-one"/> - <constraint firstItem="iWR-j0-gpt" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="zek-Of-Clw"/> + <constraint firstAttribute="trailing" secondItem="9qA-JC-fkn" secondAttribute="leading" priority="250" id="5CH-Fo-S70"/> + <constraint firstAttribute="bottom" secondItem="Ev3-yY-ql1" secondAttribute="bottom" priority="500" constant="8" id="FJI-xF-QTM"/> + <constraint firstItem="NKM-3R-3g1" firstAttribute="top" relation="greaterThanOrEqual" secondItem="EuF-Rm-DHQ" secondAttribute="bottom" constant="8" id="Fjs-IQ-LQv"/> + <constraint firstItem="Ev3-yY-ql1" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="bottom" priority="250" constant="8" id="HHb-Vh-rIl"/> + <constraint firstItem="EuF-Rm-DHQ" firstAttribute="trailing" secondItem="f76-qn-ne4" secondAttribute="leading" priority="500" id="HLI-Zw-ETh"/> + <constraint firstItem="54O-iN-1Gg" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" id="JWc-kJ-RaK"/> + <constraint firstItem="EuF-Rm-DHQ" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="8" id="KEp-1t-yK0"/> + <constraint firstItem="NKM-3R-3g1" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" id="Ls8-rz-N1Q"/> + <constraint firstItem="Ev3-yY-ql1" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="bottom" priority="700" constant="4" id="NmE-r2-ZNA"/> + <constraint firstAttribute="trailing" secondItem="kIR-cO-v6L" secondAttribute="trailing" priority="250" constant="16" id="POq-M6-rLU"/> + <constraint firstItem="zWu-Gh-Vf7" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="top" constant="2" id="Q0s-7L-aih"/> + <constraint firstAttribute="trailing" secondItem="54O-iN-1Gg" secondAttribute="trailing" id="S6I-ea-HJN"/> + <constraint firstItem="9qA-JC-fkn" firstAttribute="leading" secondItem="Ev3-yY-ql1" secondAttribute="trailing" priority="500" constant="4" id="YNA-Lu-LXQ"/> + <constraint firstItem="kIR-cO-v6L" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="ZVP-Gs-m00"/> + <constraint firstAttribute="trailing" secondItem="NKM-3R-3g1" secondAttribute="trailing" id="ZiW-Tk-SOB"/> + <constraint firstItem="kIR-cO-v6L" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="8" id="ajZ-XY-N1h"/> + <constraint firstItem="So8-wM-Cgz" firstAttribute="bottom" secondItem="zWu-Gh-Vf7" secondAttribute="bottom" constant="2" id="akC-Fs-8Iv"/> + <constraint firstAttribute="trailing" secondItem="9qA-JC-fkn" secondAttribute="trailing" priority="500" constant="16" id="dww-N9-1tY"/> + <constraint firstItem="Ev3-yY-ql1" firstAttribute="trailing" secondItem="kIR-cO-v6L" secondAttribute="trailing" id="eM3-Nv-zVj"/> + <constraint firstItem="So8-wM-Cgz" firstAttribute="top" secondItem="zWu-Gh-Vf7" secondAttribute="top" constant="-2" id="fNs-FC-pga"/> + <constraint firstItem="EuF-Rm-DHQ" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" priority="250" constant="16" id="gJI-DA-6rn"/> + <constraint firstItem="54O-iN-1Gg" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" id="ge7-AI-110"/> + <constraint firstItem="NKM-3R-3g1" firstAttribute="top" secondItem="Ev3-yY-ql1" secondAttribute="bottom" constant="8" id="hn7-T4-7Zo"/> + <constraint firstAttribute="bottom" secondItem="NKM-3R-3g1" secondAttribute="bottom" priority="250" id="hzn-4Y-A0H"/> + <constraint firstItem="So8-wM-Cgz" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" constant="-2" id="sAg-zL-vMW"/> + <constraint firstAttribute="bottom" secondItem="54O-iN-1Gg" secondAttribute="bottom" id="tOj-8H-AsH"/> + <constraint firstItem="Ev3-yY-ql1" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="tVH-Tk-6D6"/> + <constraint firstItem="9qA-JC-fkn" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="18" id="u8g-fp-l2o"/> + <constraint firstItem="zWu-Gh-Vf7" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" priority="600" constant="16" id="vlX-zx-nfP"/> + <constraint firstItem="zWu-Gh-Vf7" firstAttribute="leading" secondItem="EuF-Rm-DHQ" secondAttribute="trailing" priority="250" constant="8" id="w5K-BT-1ED"/> + <constraint firstItem="So8-wM-Cgz" firstAttribute="trailing" secondItem="zWu-Gh-Vf7" secondAttribute="trailing" constant="2" id="zGz-Sf-G1b"/> </constraints> </view> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="300" text="Delivery Club" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kIR-cO-v6L"> - <rect key="frame" x="16" y="8" width="270" height="15"/> - <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/> - <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> - <nil key="highlightedColor"/> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="bold12"/> - <userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/> - </userDefinedRuntimeAttributes> - </label> - <label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="451" verticalHuggingPriority="249" horizontalCompressionResistancePriority="249" text="Как " textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ev3-yY-ql1"> - <rect key="frame" x="16" y="27" width="270" height="74.5"/> - <fontDescription key="fontDescription" type="system" pointSize="12"/> - <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> - <nil key="highlightedColor"/> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/> - <userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackSecondaryText"/> - </userDefinedRuntimeAttributes> - </label> - <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="551" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9qA-JC-fkn"> - <rect key="frame" x="290" y="18" width="69" height="24"/> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ucm-4E-iB7"> + <rect key="frame" x="12" y="0.0" width="351" height="109.5"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <constraints> - <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="64" id="N7a-ng-e6p"/> - <constraint firstAttribute="height" constant="24" id="XME-fd-3O8"/> - </constraints> - <fontDescription key="fontDescription" type="system" pointSize="12"/> - <inset key="contentEdgeInsets" minX="8" minY="0.0" maxX="8" maxY="0.0"/> - <state key="normal" title="Заказать"> - <color key="titleColor" red="0.59999999999999998" green="0.58823529411764708" blue="0.56862745098039214" alpha="0.40000000000000002" colorSpace="calibratedRGB"/> - </state> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular12"/> - <userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="blackSecondaryText"/> - <userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor"> - <color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth"> - <integer key="value" value="1"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius"> - <integer key="value" value="4"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NKM-3R-3g1"> - <rect key="frame" x="0.0" y="109.5" width="375" height="36"/> - <color key="backgroundColor" red="0.95294117647058818" green="0.92156862745098034" blue="0.85490196078431369" alpha="1" colorSpace="calibratedRGB"/> - <constraints> - <constraint firstAttribute="height" constant="36" id="JMM-je-O9e"/> + <constraint firstAttribute="height" constant="109.5" id="9T6-aq-miV"/> </constraints> - <state key="normal" title="Заказать"> - <color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="0.40000000000000002" colorSpace="calibratedRGB"/> - </state> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular15"/> - <userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="bannerButtonBackground"/> - <userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="blackSecondaryText"/> - </userDefinedRuntimeAttributes> - </button> - <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="54O-iN-1Gg"> - <rect key="frame" x="0.0" y="0.0" width="375" height="109.5"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> - </button> - <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="So8-wM-Cgz"> - <rect key="frame" x="14" y="8" width="24" height="16"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> - <connections> - <action selector="privacyAction" destination="WK2-gA-ocn" eventType="touchUpInside" id="ma2-uV-7hH"/> - </connections> - </button> + </view> </subviews> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <constraints> - <constraint firstAttribute="trailing" secondItem="9qA-JC-fkn" secondAttribute="leading" priority="250" id="5CH-Fo-S70"/> - <constraint firstAttribute="bottom" secondItem="Ev3-yY-ql1" secondAttribute="bottom" priority="500" constant="8" id="FJI-xF-QTM"/> - <constraint firstItem="NKM-3R-3g1" firstAttribute="top" relation="greaterThanOrEqual" secondItem="EuF-Rm-DHQ" secondAttribute="bottom" constant="8" id="Fjs-IQ-LQv"/> - <constraint firstItem="Ev3-yY-ql1" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="bottom" priority="250" constant="8" id="HHb-Vh-rIl"/> - <constraint firstItem="EuF-Rm-DHQ" firstAttribute="trailing" secondItem="f76-qn-ne4" secondAttribute="leading" priority="500" id="HLI-Zw-ETh"/> - <constraint firstItem="54O-iN-1Gg" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" id="JWc-kJ-RaK"/> - <constraint firstItem="EuF-Rm-DHQ" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="8" id="KEp-1t-yK0"/> - <constraint firstItem="NKM-3R-3g1" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" id="Ls8-rz-N1Q"/> - <constraint firstItem="Ev3-yY-ql1" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="bottom" priority="700" constant="4" id="NmE-r2-ZNA"/> - <constraint firstAttribute="trailing" secondItem="kIR-cO-v6L" secondAttribute="trailing" priority="250" constant="16" id="POq-M6-rLU"/> - <constraint firstItem="zWu-Gh-Vf7" firstAttribute="top" secondItem="kIR-cO-v6L" secondAttribute="top" constant="2" id="Q0s-7L-aih"/> - <constraint firstAttribute="trailing" secondItem="54O-iN-1Gg" secondAttribute="trailing" id="S6I-ea-HJN"/> - <constraint firstItem="9qA-JC-fkn" firstAttribute="leading" secondItem="Ev3-yY-ql1" secondAttribute="trailing" priority="500" constant="4" id="YNA-Lu-LXQ"/> - <constraint firstItem="kIR-cO-v6L" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="ZVP-Gs-m00"/> - <constraint firstAttribute="trailing" secondItem="NKM-3R-3g1" secondAttribute="trailing" id="ZiW-Tk-SOB"/> - <constraint firstItem="kIR-cO-v6L" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="8" id="ajZ-XY-N1h"/> - <constraint firstItem="So8-wM-Cgz" firstAttribute="bottom" secondItem="zWu-Gh-Vf7" secondAttribute="bottom" constant="2" id="akC-Fs-8Iv"/> - <constraint firstAttribute="trailing" secondItem="9qA-JC-fkn" secondAttribute="trailing" priority="500" constant="16" id="dww-N9-1tY"/> - <constraint firstItem="Ev3-yY-ql1" firstAttribute="trailing" secondItem="kIR-cO-v6L" secondAttribute="trailing" id="eM3-Nv-zVj"/> - <constraint firstItem="So8-wM-Cgz" firstAttribute="top" secondItem="zWu-Gh-Vf7" secondAttribute="top" constant="-2" id="fNs-FC-pga"/> - <constraint firstItem="EuF-Rm-DHQ" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" priority="250" constant="16" id="gJI-DA-6rn"/> - <constraint firstItem="54O-iN-1Gg" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" id="ge7-AI-110"/> - <constraint firstItem="NKM-3R-3g1" firstAttribute="top" secondItem="Ev3-yY-ql1" secondAttribute="bottom" constant="8" id="hn7-T4-7Zo"/> - <constraint firstAttribute="bottom" secondItem="NKM-3R-3g1" secondAttribute="bottom" priority="250" id="hzn-4Y-A0H"/> - <constraint firstItem="So8-wM-Cgz" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" constant="-2" id="sAg-zL-vMW"/> - <constraint firstAttribute="bottom" secondItem="54O-iN-1Gg" secondAttribute="bottom" id="tOj-8H-AsH"/> - <constraint firstItem="Ev3-yY-ql1" firstAttribute="leading" secondItem="zWu-Gh-Vf7" secondAttribute="leading" id="tVH-Tk-6D6"/> - <constraint firstItem="9qA-JC-fkn" firstAttribute="top" secondItem="f76-qn-ne4" secondAttribute="top" constant="18" id="u8g-fp-l2o"/> - <constraint firstItem="zWu-Gh-Vf7" firstAttribute="leading" secondItem="f76-qn-ne4" secondAttribute="leading" priority="600" constant="16" id="vlX-zx-nfP"/> - <constraint firstItem="zWu-Gh-Vf7" firstAttribute="leading" secondItem="EuF-Rm-DHQ" secondAttribute="trailing" priority="250" constant="8" id="w5K-BT-1ED"/> - <constraint firstItem="So8-wM-Cgz" firstAttribute="trailing" secondItem="zWu-Gh-Vf7" secondAttribute="trailing" constant="2" id="zGz-Sf-G1b"/> + <constraint firstItem="f76-qn-ne4" firstAttribute="top" secondItem="f76-qn-ne5" secondAttribute="top" id="5de-Xp-prZ"/> + <constraint firstAttribute="bottom" secondItem="f76-qn-ne4" secondAttribute="bottom" id="7c6-rR-ue5"/> + <constraint firstAttribute="trailing" secondItem="f76-qn-ne4" secondAttribute="trailing" id="9IQ-Gl-EXk"/> + <constraint firstItem="f76-qn-ne4" firstAttribute="leading" secondItem="f76-qn-ne5" secondAttribute="leading" id="Bht-aF-E0n"/> + <constraint firstAttribute="bottom" secondItem="ucm-4E-iB7" secondAttribute="bottom" id="DdI-tM-5Yy"/> + <constraint firstAttribute="trailing" secondItem="ucm-4E-iB7" secondAttribute="trailing" constant="12" id="XfZ-ns-v6e"/> + <constraint firstItem="ucm-4E-iB7" firstAttribute="top" secondItem="f76-qn-ne5" secondAttribute="top" id="cA5-OB-yRM"/> + <constraint firstItem="ucm-4E-iB7" firstAttribute="leading" secondItem="f76-qn-ne5" secondAttribute="leading" constant="12" id="w4s-WH-a6c"/> </constraints> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="bannerBackground"/> @@ -167,6 +190,11 @@ <outlet property="adIconImageView" destination="EuF-Rm-DHQ" id="Edf-Ak-VAy"/> <outlet property="adPrivacyButton" destination="So8-wM-Cgz" id="tY6-tl-gGx"/> <outlet property="adTitleLabel" destination="kIR-cO-v6L" id="OOh-tX-yBM"/> + <outlet property="fallbackAdView" destination="ucm-4E-iB7" id="dOb-SQ-pex"/> + <outlet property="fallbackAdViewBottom" destination="DdI-tM-5Yy" id="Tyv-gy-gf7"/> + <outlet property="fallbackAdViewHeight" destination="9T6-aq-miV" id="gze-UL-E6b"/> + <outlet property="nativeAdView" destination="f76-qn-ne4" id="9hb-za-zgw"/> + <outlet property="nativeAdViewBottom" destination="7c6-rR-ue5" id="8x7-ar-cxz"/> <outletCollection property="detailedModeConstraints" destination="w5K-BT-1ED" collectionClass="NSMutableArray" id="Lv4-E4-dYV"/> <outletCollection property="detailedModeConstraints" destination="POq-M6-rLU" collectionClass="NSMutableArray" id="rqF-JD-SZe"/> <outletCollection property="detailedModeConstraints" destination="gJI-DA-6rn" collectionClass="NSMutableArray" id="Bf5-KV-Yq1"/> diff --git a/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm b/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm index 165b97c084..4fe7fee391 100644 --- a/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm +++ b/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm @@ -5,7 +5,7 @@ #import "Statistics.h" #import "SwiftBridge.h" -@interface MWMSearchTableViewController ()<UITableViewDataSource, UITableViewDelegate> +@interface MWMSearchTableViewController ()<UITableViewDataSource, UITableViewDelegate, MWMGoogleFallbackBannerDynamicSizeDelegate> @property(weak, nonatomic) IBOutlet UITableView * tableView; @@ -100,10 +100,17 @@ } case MWMSearchItemTypeMopub: case MWMSearchItemTypeFacebook: + case MWMSearchItemTypeGoogle: { - auto cell = static_cast<MWMAdBanner *>( - [tableView dequeueReusableCellWithCellClass:[MWMAdBanner class] indexPath:indexPath]); + auto cell = static_cast<MWMAdBanner *>([tableView dequeueReusableCellWithCellClass:[MWMAdBanner class] indexPath:indexPath]); auto ad = [MWMSearch adWithContainerIndex:containerIndex]; + if ([ad isKindOfClass:[MWMGoogleFallbackBanner class]]) + { + auto fallbackAd = static_cast<MWMGoogleFallbackBanner *>(ad); + fallbackAd.cellIndexPath = indexPath; + fallbackAd.dynamicSizeDelegate = self; + [cell configWithAd:fallbackAd containerType:MWMAdBannerContainerTypeSearch]; + } [cell configWithAd:ad containerType:MWMAdBannerContainerTypeSearch]; return cell; } @@ -120,6 +127,13 @@ } } +#pragma mark - MWMGoogleFallbackBannerDynamicSizeDelegate + +- (void)dynamicSizeUpdatedWithBanner:(MWMGoogleFallbackBanner * _Nonnull)banner +{ + [self.tableView reloadRowsAtIndexPaths:@[banner.cellIndexPath] withRowAnimation:UITableViewRowAnimationFade]; +} + #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath @@ -138,7 +152,8 @@ break; } case MWMSearchItemTypeMopub: - case MWMSearchItemTypeFacebook: break; + case MWMSearchItemTypeFacebook: + case MWMSearchItemTypeGoogle: break; case MWMSearchItemTypeSuggestion: { auto const & suggestion = [MWMSearch resultWithContainerIndex:containerIndex]; |