[MAPSME-4137,MAPSME-4153,MAPSME-4157] [ios] Added RB banners.

This commit is contained in:
Ilya Grechuhin 2017-03-31 18:19:10 +03:00 committed by Vladimir Byko-Ianko
parent 5e47f4a1d4
commit 3c7b7e7e35
21 changed files with 722 additions and 262 deletions

View file

@ -2,14 +2,18 @@
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <MyTargetSDK/MyTargetSDK.h>
#import <UIKit/UIKit.h>
#import "3party/Alohalytics/src/alohalytics_objc.h"
#import "private.h"
#import "AppInfo.h"
#import "MWMCollectionViewController.h"
#import "MWMConsts.h"
#import "MWMController.h"
#import "MWMCoreBanner.h"
#import "MWMFrameworkHelper.h"
#import "MWMKeyboard.h"
#import "MWMLocationManager.h"
@ -24,6 +28,7 @@
#import "MWMTypes.h"
#import "MWMViewController.h"
#import "Statistics.h"
#import "UIButton+RuntimeAttributes.h"
#import "UIColor+MapsMeColor.h"
#import "UIFont+MapsMeFonts.h"
#import "UIKitCategories.h"

View file

@ -0,0 +1,32 @@
//
// UIColor+Modifications.swift
// Maps
//
// Created by Ilya Grechuhin on 30.03.17.
// Copyright © 2017 MapsWithMe. All rights reserved.
//
import UIKit
extension UIColor {
func lighter(percent: CGFloat) -> UIColor {
return colorWithBrightnessFactor(factor: 1 + percent)
}
func darker(percent: CGFloat) -> UIColor {
return colorWithBrightnessFactor(factor: 1 - percent)
}
private func colorWithBrightnessFactor(factor: CGFloat) -> UIColor {
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
var alpha: CGFloat = 0
if getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
return UIColor(hue: hue, saturation: saturation, brightness: brightness * factor, alpha: alpha)
} else {
return self;
}
}
}

View file

@ -158,6 +158,7 @@ static NSString * const kStatPlacePage = @"Place page";
static NSString * const kStatPlacePageBannerBlank = @"Placepage_Banner_blank";
static NSString * const kStatPlacePageBannerError = @"Placepage_Banner_error";
static NSString * const kStatPlacePageBannerShow = @"Placepage_Banner_show";
static NSString * const kStatRB = @"RB";
static NSString * const kPlacePageHotelBook = @"Placepage_Hotel_book";
static NSString * const kPlacePageHotelDetails = @"Placepage_Hotel_details";
static NSString * const kPlacePageHotelFacilities = @"PlacePage_Hotel_Facilities_open";

View file

@ -0,0 +1,12 @@
protocol Banner: MWMBanner {
typealias EventName = String
typealias ErrorDetails = [String : Any]
typealias Success = (Banner) -> Void
typealias Failure = (Banner, EventName, ErrorDetails, NSError) -> Void
func reload(success: @escaping Success, failure: @escaping Failure)
var isBannerOnScreen: Bool { get set }
var isNeedToRetain: Bool { get }
var isPossibleToReload: Bool { get }
var type: BannerType { get }
}

View file

@ -0,0 +1,62 @@
import Foundation
enum BannerType {
case none
case facebook(String)
case rb(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)
}
}
var statisticsDescription: [String: String] {
switch self {
case .none: return [:]
case .facebook(let id): return [kStatBanner: id, kStatProvider: kStatFacebook]
case .rb(let id): return [kStatBanner: id, kStatProvider: kStatRB]
}
}
var mwmType: MWMBannerType {
switch self {
case .none: return .none
case .facebook: return .facebook
case .rb: return .rb
}
}
init(type: MWMBannerType, id: String) {
switch type {
case .none: self = .none
case .facebook: self = .facebook(id)
case .rb: self = .rb(id)
}
}
}
extension BannerType: Equatable {
static func ==(lhs: BannerType, rhs: BannerType) -> Bool {
switch (lhs, rhs) {
case (.none, .none): return true
case let (.facebook(l), .facebook(r)): return l == r
case let (.rb(l), .rb(r)): return l == r
case (.none, _),
(.facebook, _),
(.rb, _): return false
}
}
}
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
}
}
}

View file

@ -0,0 +1,112 @@
import Crashlytics
@objc (MWMBannersCache)
final class BannersCache: NSObject {
static let cache = BannersCache()
private override init() {}
private enum LoadState {
case notLoaded(BannerType)
case loaded(BannerType)
case error
}
typealias Completion = (MWMBanner, Bool) -> Void
private var cache: [BannerType : Banner] = [:]
private var requests: [BannerType : Banner] = [:]
private var completion: Completion?
private var loadStates: [LoadState]!
private func onCompletion(isAsync: Bool) {
guard let completion = completion else { return }
var bannerType: BannerType?
for loadState in loadStates {
switch loadState {
case .notLoaded(_): return
case .loaded(let type):
bannerType = type
break
case .error: continue
}
}
guard bannerType != nil else { return }
guard let banner = cache[bannerType!] else {
assert(false)
return
}
completion(banner, isAsync)
banner.isBannerOnScreen = true
self.completion = nil
}
func get(coreBanners: [MWMCoreBanner], completion: @escaping Completion) {
self.completion = completion
loadStates = coreBanners.map { coreBanner in
let bannerType = BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID)
if let banner = cache[bannerType], (!banner.isPossibleToReload || banner.isNeedToRetain) {
return .loaded(bannerType)
} else {
get(bannerType: bannerType)
return .notLoaded(bannerType)
}
}
onCompletion(isAsync: false)
}
private func get(bannerType: BannerType) {
guard requests[bannerType] == nil else { return }
let banner = bannerType.banner!
requests[bannerType] = banner
banner.reload(success: { [unowned self] banner in
Statistics.logEvent(kStatPlacePageBannerShow, withParameters: banner.type.statisticsDescription)
self.setLoaded(banner: banner)
}, failure: { [unowned self] banner, event, errorDetails, error in
var statParams = errorDetails
statParams[kStatErrorMessage] = (error as NSError).userInfo.reduce("") { $0 + "\($1.key) : \($1.value)\n" }
Statistics.logEvent(event, withParameters: statParams)
Crashlytics.sharedInstance().recordError(error)
self.setError(banner: banner)
})
}
private func notLoadedIndex(bannerType: BannerType) -> Array<LoadState>.Index? {
return loadStates.index(where: {
if case .notLoaded(let type) = $0, type == bannerType {
return true
}
return false
})
}
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
onCompletion(isAsync: true)
}
private func setError(banner: Banner) {
let bannerType = banner.type
if let notLoadedIndex = notLoadedIndex(bannerType: bannerType) {
loadStates[notLoadedIndex] = .error
}
requests[bannerType] = nil
onCompletion(isAsync: true)
}
func bannerIsOutOfScreen(coreBanner: MWMBanner) {
bannerIsOutOfScreen(bannerType: BannerType(type: coreBanner.mwmType, id: coreBanner.bannerID))
}
func bannerIsOutOfScreen(bannerType: BannerType) {
completion = nil
if let cached = cache[bannerType], cached.isBannerOnScreen {
cached.isBannerOnScreen = false
}
}
}

View file

@ -1,31 +1,18 @@
import FBAudienceNetwork
// MARK: CacheableFacebookBanner
final class CacheableFacebookBanner: FBNativeAd, Cacheable {
// MARK: FacebookBanner
final class FacebookBanner: FBNativeAd, Banner {
fileprivate var success: Banner.Success!
fileprivate var failure: Banner.Failure!
fileprivate var success: Cacheable.Success!
fileprivate var failure: Cacheable.Failure!
func reload(success: @escaping Banner.Success, failure: @escaping Banner.Failure) {
self.success = success
self.failure = failure
func reload(_ suc: @escaping Cacheable.Success, failure fail: @escaping Cacheable.Failure) {
success = suc
failure = fail
mediaCachePolicy = .all
delegate = self
load()
requestDate = Date()
}
func bannerIsOutOfScreen() {
stopCountTimeOnScreen()
isBannerOnScreen = false
}
func bannerIsOnScreen() {
isBannerOnScreen = true
startCountTimeOnScreen()
}
var isPossibleToReload: Bool {
if let date = requestDate {
return Date().timeIntervalSince(date) > Limits.minTimeSinceLastRequest
@ -34,8 +21,18 @@ final class CacheableFacebookBanner: FBNativeAd, Cacheable {
}
var isNeedToRetain: Bool = true
var adID: String { return placementID }
private(set) var isBannerOnScreen = false
var type: BannerType { return .facebook(bannerID) }
var mwmType: MWMBannerType { return type.mwmType }
var bannerID: String! { return placementID }
var isBannerOnScreen = false {
didSet {
if isBannerOnScreen {
startCountTimeOnScreen()
} else {
stopCountTimeOnScreen()
}
}
}
// MARK: Helpers
private var requestDate: Date?
@ -76,8 +73,10 @@ final class CacheableFacebookBanner: FBNativeAd, Cacheable {
isNeedToRetain = false
}
override init(placementID: String) {
super.init(placementID: placementID)
init(bannerID: String) {
super.init(placementID: bannerID)
mediaCachePolicy = .all
delegate = self
let center = NotificationCenter.default
center.addObserver(self,
selector: #selector(enterForeground),
@ -104,11 +103,10 @@ final class CacheableFacebookBanner: FBNativeAd, Cacheable {
deinit {
NotificationCenter.default.removeObserver(self)
}
}
// MARK: CacheableFaceebookBanner: FBNativeAdDelegate
extension CacheableFacebookBanner: FBNativeAdDelegate {
// MARK: FacebookBanner: FBNativeAdDelegate
extension FacebookBanner: FBNativeAdDelegate {
func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
success(self)
@ -126,16 +124,9 @@ extension CacheableFacebookBanner: FBNativeAdDelegate {
} else {
event = kStatPlacePageBannerError
params[kStatErrorCode] = e.code
var message: String = ""
for (k, v) in e.userInfo {
message += "\(k) : \(v)\n"
}
params[kStatErrorMessage] = message
}
failure(event, params, e)
failure(self, event, params, e)
}
}

View file

@ -0,0 +1,31 @@
#import "MWMCoreBanner.h"
#import "SwiftBridge.h"
#include "partners_api/banner.hpp"
namespace banner_helpers
{
static inline MWMBannerType MatchBannerType(ads::Banner::Type coreType)
{
switch (coreType)
{
case ads::Banner::Type::None: return MWMBannerTypeNone;
case ads::Banner::Type::Facebook: return MWMBannerTypeFacebook;
case ads::Banner::Type::RB: return MWMBannerTypeRb;
}
}
static inline MWMCoreBanner * MatchBanner(ads::Banner const & banner)
{
return [[MWMCoreBanner alloc] initWith:MatchBannerType(banner.m_type)
bannerID:@(banner.m_bannerId.c_str())];
}
static inline NSArray<MWMCoreBanner *> * MatchPriorityBanners(vector<ads::Banner> const & banners)
{
NSMutableArray<MWMCoreBanner *> * mBanners = [@[] mutableCopy];
for (auto const & banner : banners)
[mBanners addObject:MatchBanner(banner)];
return [mBanners copy];
}
}

View file

@ -0,0 +1,19 @@
typedef NS_ENUM(NSInteger, MWMBannerType) {
MWMBannerTypeNone = 0,
MWMBannerTypeFacebook = 1,
MWMBannerTypeRb = 2,
};
@protocol MWMBanner
@property(nonatomic, readonly) enum MWMBannerType mwmType;
@property(copy, nonatomic, readonly) NSString * bannerID;
@end
@interface MWMCoreBanner : NSObject<MWMBanner>
- (instancetype)initWith:(MWMBannerType)type bannerID:(NSString *)bannerID;
@property(nonatomic, readonly) enum MWMBannerType mwmType;
@property(copy, nonatomic, readonly) NSString * bannerID;
@end

View file

@ -0,0 +1,22 @@
#import "MWMCoreBanner.h"
@interface MWMCoreBanner ()
@property(copy, nonatomic, readwrite) NSString * bannerID;
@end
@implementation MWMCoreBanner
- (instancetype)initWith:(MWMBannerType)type bannerID:(NSString *)bannerID
{
self = [super init];
if (self)
{
_mwmType = type;
_bannerID = bannerID;
}
return self;
}
@end

View file

@ -0,0 +1,131 @@
final class RBBanner: MTRGNativeAd, Banner {
private enum Limits {
static let minTimeOnScreen: TimeInterval = 3
static let minTimeSinceLastRequest: TimeInterval = 30
}
fileprivate enum Settings {
static let placementIDKey = "_SITEZONE"
}
fileprivate var success: Banner.Success!
fileprivate var failure: Banner.Failure!
fileprivate var requestDate: Date?
private var showDate: Date?
private var remainingTime = Limits.minTimeOnScreen
init!(bannerID: String) {
super.init(slotId: UInt(MY_TARGET_RB_KEY))
delegate = self
self.bannerID = bannerID
let center = NotificationCenter.default
center.addObserver(self,
selector: #selector(enterForeground),
name: .UIApplicationWillEnterForeground,
object: nil)
center.addObserver(self,
selector: #selector(enterBackground),
name: .UIApplicationDidEnterBackground,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc private func enterForeground() {
if isBannerOnScreen {
startCountTimeOnScreen()
}
}
@objc private func enterBackground() {
if (isBannerOnScreen) {
stopCountTimeOnScreen()
}
}
private func startCountTimeOnScreen() {
if showDate == nil {
showDate = Date()
}
if (remainingTime > 0) {
perform(#selector(setEnoughTimeOnScreen), with: nil, afterDelay: remainingTime)
}
}
private func stopCountTimeOnScreen() {
guard let date = showDate else {
assert(false)
return
}
let timePassed = Date().timeIntervalSince(date)
if (timePassed < Limits.minTimeOnScreen) {
remainingTime = Limits.minTimeOnScreen - timePassed
NSObject.cancelPreviousPerformRequests(withTarget: self)
} else {
remainingTime = 0
}
}
@objc private func setEnoughTimeOnScreen() {
isNeedToRetain = false
}
//MARK: - Banner
func reload(success: @escaping Banner.Success, failure: @escaping Banner.Failure) {
self.success = success
self.failure = failure
load()
requestDate = Date()
}
var isBannerOnScreen = false {
didSet {
if isBannerOnScreen {
startCountTimeOnScreen()
} else {
stopCountTimeOnScreen()
}
}
}
var isNeedToRetain = false
var isPossibleToReload: Bool {
if let date = requestDate {
return Date().timeIntervalSince(date) > Limits.minTimeSinceLastRequest
}
return true
}
var type: BannerType { return .rb(bannerID) }
var mwmType: MWMBannerType { return type.mwmType }
var bannerID: String! {
get {
return customParams.customParam(forKey: Settings.placementIDKey)
}
set {
customParams.setCustomParam(newValue, forKey: Settings.placementIDKey)
}
}
}
extension RBBanner: MTRGNativeAdDelegate {
func onLoad(with promoBanner: MTRGNativePromoBanner!, nativeAd: MTRGNativeAd!) {
guard nativeAd == self else { return }
success(self)
}
func onNoAd(withReason reason: String!, nativeAd: MTRGNativeAd!) {
guard nativeAd == self else { return }
let params: [String: Any] = [kStatBanner : bannerID, kStatProvider : kStatRB]
let event = kStatPlacePageBannerError
let error = NSError(domain: kMapsmeErrorDomain, code: 1001, userInfo: params)
failure(self, event, params, error)
}
}

View file

@ -159,12 +159,6 @@
3432E17C1E49B484008477E9 /* FBAudienceNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E17B1E49B484008477E9 /* FBAudienceNetwork.framework */; };
3432E17D1E49B484008477E9 /* FBAudienceNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E17B1E49B484008477E9 /* FBAudienceNetwork.framework */; };
3432E17E1E49B484008477E9 /* FBAudienceNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3432E17B1E49B484008477E9 /* FBAudienceNetwork.framework */; };
3432E1811E49BF09008477E9 /* FBAdsBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3432E1801E49BF09008477E9 /* FBAdsBanner.swift */; };
3432E1821E49BF09008477E9 /* FBAdsBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3432E1801E49BF09008477E9 /* FBAdsBanner.swift */; };
3432E1831E49BF09008477E9 /* FBAdsBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3432E1801E49BF09008477E9 /* FBAdsBanner.swift */; };
3432E1851E49BF5C008477E9 /* FBAdsBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3432E1841E49BF5C008477E9 /* FBAdsBanner.xib */; };
3432E1861E49BF5C008477E9 /* FBAdsBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3432E1841E49BF5C008477E9 /* FBAdsBanner.xib */; };
3432E1871E49BF5C008477E9 /* FBAdsBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3432E1841E49BF5C008477E9 /* FBAdsBanner.xib */; };
343E75971E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 343E75961E5B1EE20041226A /* MWMCollectionViewController.mm */; };
343E75981E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 343E75961E5B1EE20041226A /* MWMCollectionViewController.mm */; };
343E75991E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 343E75961E5B1EE20041226A /* MWMCollectionViewController.mm */; };
@ -289,6 +283,33 @@
3486B51D1E27AD590069C126 /* MWMFrameworkHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3486B51C1E27AD590069C126 /* MWMFrameworkHelper.mm */; };
3486B51E1E27AD590069C126 /* MWMFrameworkHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3486B51C1E27AD590069C126 /* MWMFrameworkHelper.mm */; };
3486B51F1E27AD590069C126 /* MWMFrameworkHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3486B51C1E27AD590069C126 /* MWMFrameworkHelper.mm */; };
3488AFFE1E9D0AD00068AFD8 /* Banner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF61E9D0AD00068AFD8 /* Banner.swift */; };
3488AFFF1E9D0AD00068AFD8 /* Banner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF61E9D0AD00068AFD8 /* Banner.swift */; };
3488B0001E9D0AD00068AFD8 /* Banner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF61E9D0AD00068AFD8 /* Banner.swift */; };
3488B0011E9D0AD00068AFD8 /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF71E9D0AD00068AFD8 /* BannersCache.swift */; };
3488B0021E9D0AD00068AFD8 /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF71E9D0AD00068AFD8 /* BannersCache.swift */; };
3488B0031E9D0AD00068AFD8 /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF71E9D0AD00068AFD8 /* BannersCache.swift */; };
3488B0041E9D0AD00068AFD8 /* BannerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF81E9D0AD00068AFD8 /* BannerType.swift */; };
3488B0051E9D0AD00068AFD8 /* BannerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF81E9D0AD00068AFD8 /* BannerType.swift */; };
3488B0061E9D0AD00068AFD8 /* BannerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF81E9D0AD00068AFD8 /* BannerType.swift */; };
3488B0071E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF91E9D0AD00068AFD8 /* FacebookBanner.swift */; };
3488B0081E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF91E9D0AD00068AFD8 /* FacebookBanner.swift */; };
3488B0091E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFF91E9D0AD00068AFD8 /* FacebookBanner.swift */; };
3488B00A1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFC1E9D0AD00068AFD8 /* MWMCoreBanner.mm */; };
3488B00B1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFC1E9D0AD00068AFD8 /* MWMCoreBanner.mm */; };
3488B00C1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFC1E9D0AD00068AFD8 /* MWMCoreBanner.mm */; };
3488B00D1E9D0AD00068AFD8 /* RBBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFD1E9D0AD00068AFD8 /* RBBanner.swift */; };
3488B00E1E9D0AD00068AFD8 /* RBBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFD1E9D0AD00068AFD8 /* RBBanner.swift */; };
3488B00F1E9D0AD00068AFD8 /* RBBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488AFFD1E9D0AD00068AFD8 /* RBBanner.swift */; };
3488B0121E9D0AEC0068AFD8 /* AdBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0101E9D0AEC0068AFD8 /* AdBanner.swift */; };
3488B0131E9D0AEC0068AFD8 /* AdBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0101E9D0AEC0068AFD8 /* AdBanner.swift */; };
3488B0141E9D0AEC0068AFD8 /* AdBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0101E9D0AEC0068AFD8 /* AdBanner.swift */; };
3488B0151E9D0AEC0068AFD8 /* AdBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3488B0111E9D0AEC0068AFD8 /* AdBanner.xib */; };
3488B0161E9D0AEC0068AFD8 /* AdBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3488B0111E9D0AEC0068AFD8 /* AdBanner.xib */; };
3488B0171E9D0AEC0068AFD8 /* AdBanner.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3488B0111E9D0AEC0068AFD8 /* AdBanner.xib */; };
3488B0191E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0181E9D0B230068AFD8 /* UIColor+Modifications.swift */; };
3488B01A1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0181E9D0B230068AFD8 /* UIColor+Modifications.swift */; };
3488B01B1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3488B0181E9D0B230068AFD8 /* UIColor+Modifications.swift */; };
3490D2DE1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3490D2DA1CE9DD2500D0B838 /* MWMSideButtons.mm */; };
3490D2DF1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3490D2DA1CE9DD2500D0B838 /* MWMSideButtons.mm */; };
3490D2E01CE9DD2500D0B838 /* MWMSideButtonsView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3490D2DC1CE9DD2500D0B838 /* MWMSideButtonsView.mm */; };
@ -830,18 +851,12 @@
F623DA6B1C9C2731006A3436 /* opening_hours_how_to_edit.html in Resources */ = {isa = PBXBuildFile; fileRef = F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */; };
F623DA6C1C9C2731006A3436 /* opening_hours_how_to_edit.html in Resources */ = {isa = PBXBuildFile; fileRef = F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */; };
F623DA6F1C9C2E62006A3436 /* MWMAddPlaceNavigationBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = F653CE171C71F62400A453F1 /* MWMAddPlaceNavigationBar.xib */; };
F624592F1E80185500E7AE9E /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F624592E1E80185500E7AE9E /* BannersCache.swift */; };
F62459301E80185500E7AE9E /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F624592E1E80185500E7AE9E /* BannersCache.swift */; };
F62459311E80185500E7AE9E /* BannersCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F624592E1E80185500E7AE9E /* BannersCache.swift */; };
F626D52E1C3E6CAA00C17D15 /* MWMTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F626D52D1C3E6CAA00C17D15 /* MWMTableViewCell.mm */; };
F626D52F1C3E83F800C17D15 /* MWMTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F626D52D1C3E6CAA00C17D15 /* MWMTableViewCell.mm */; };
F63774E71B59375E00BCF54D /* MWMRoutingDisclaimerAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = F63774E61B59375E00BCF54D /* MWMRoutingDisclaimerAlert.xib */; };
F63774EA1B59376F00BCF54D /* MWMRoutingDisclaimerAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F63774E91B59376F00BCF54D /* MWMRoutingDisclaimerAlert.mm */; };
F6381BF51CD12045004CA943 /* LocaleTranslator.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6381BF41CD12045004CA943 /* LocaleTranslator.mm */; };
F6381BF61CD12045004CA943 /* LocaleTranslator.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6381BF41CD12045004CA943 /* LocaleTranslator.mm */; };
F63B242F1E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = F63B242E1E890C8F008C9D3C /* CacheableFacebookBanner.swift */; };
F63B24301E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = F63B242E1E890C8F008C9D3C /* CacheableFacebookBanner.swift */; };
F63B24311E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = F63B242E1E890C8F008C9D3C /* CacheableFacebookBanner.swift */; };
F64D9C9F1C899C350063FA30 /* MWMEditorViralAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F64D9C9E1C899C350063FA30 /* MWMEditorViralAlert.mm */; };
F64D9CA01C899C350063FA30 /* MWMEditorViralAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F64D9C9E1C899C350063FA30 /* MWMEditorViralAlert.mm */; };
F64D9CA21C899C760063FA30 /* MWMEditorViralAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = F64D9CA11C899C760063FA30 /* MWMEditorViralAlert.xib */; };
@ -1580,8 +1595,6 @@
342EE4101C43DAA7009F6A49 /* MWMAuthorizationWebViewLoginViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMAuthorizationWebViewLoginViewController.mm; sourceTree = "<group>"; };
3432E1771E49B3A2008477E9 /* Bolts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Bolts.framework; sourceTree = "<group>"; };
3432E17B1E49B484008477E9 /* FBAudienceNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBAudienceNetwork.framework; sourceTree = "<group>"; };
3432E1801E49BF09008477E9 /* FBAdsBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FBAdsBanner.swift; sourceTree = "<group>"; };
3432E1841E49BF5C008477E9 /* FBAdsBanner.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FBAdsBanner.xib; 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>"; };
3446C6761DDCA9A200146687 /* libtraffic.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtraffic.a; path = "../../../omim-build/xcode/Debug/libtraffic.a"; sourceTree = "<group>"; };
@ -1661,6 +1674,17 @@
3486B5141E27AD3B0069C126 /* MWMFrameworkObservers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkObservers.h; sourceTree = "<group>"; };
3486B51B1E27AD590069C126 /* MWMFrameworkHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkHelper.h; sourceTree = "<group>"; };
3486B51C1E27AD590069C126 /* MWMFrameworkHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMFrameworkHelper.mm; sourceTree = "<group>"; };
3488AFF61E9D0AD00068AFD8 /* Banner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Banner.swift; sourceTree = "<group>"; };
3488AFF71E9D0AD00068AFD8 /* BannersCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannersCache.swift; sourceTree = "<group>"; };
3488AFF81E9D0AD00068AFD8 /* BannerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannerType.swift; sourceTree = "<group>"; };
3488AFF91E9D0AD00068AFD8 /* FacebookBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FacebookBanner.swift; sourceTree = "<group>"; };
3488AFFA1E9D0AD00068AFD8 /* MWMBannerHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMBannerHelpers.h; sourceTree = "<group>"; };
3488AFFB1E9D0AD00068AFD8 /* MWMCoreBanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMCoreBanner.h; sourceTree = "<group>"; };
3488AFFC1E9D0AD00068AFD8 /* MWMCoreBanner.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMCoreBanner.mm; sourceTree = "<group>"; };
3488AFFD1E9D0AD00068AFD8 /* RBBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RBBanner.swift; sourceTree = "<group>"; };
3488B0101E9D0AEC0068AFD8 /* AdBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdBanner.swift; sourceTree = "<group>"; };
3488B0111E9D0AEC0068AFD8 /* AdBanner.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AdBanner.xib; sourceTree = "<group>"; };
3488B0181E9D0B230068AFD8 /* UIColor+Modifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Modifications.swift"; sourceTree = "<group>"; };
348E57981B0F49D8000FA02A /* maps.me dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "maps.me dbg.app"; sourceTree = BUILT_PRODUCTS_DIR; };
3490D2D91CE9DD2500D0B838 /* MWMSideButtons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSideButtons.h; sourceTree = "<group>"; };
3490D2DA1CE9DD2500D0B838 /* MWMSideButtons.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSideButtons.mm; sourceTree = "<group>"; };
@ -1929,14 +1953,12 @@
F61579351AC2CEB60032D8E9 /* MWMRateAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMRateAlert.xib; sourceTree = "<group>"; };
F6172FA41BBD5A3E0081D325 /* MWMiPadRoutePreview.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMiPadRoutePreview.xib; sourceTree = "<group>"; };
F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = opening_hours_how_to_edit.html; path = ../../data/opening_hours_how_to_edit.html; sourceTree = "<group>"; };
F624592E1E80185500E7AE9E /* BannersCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannersCache.swift; sourceTree = "<group>"; };
F626D52C1C3E6CAA00C17D15 /* MWMTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMTableViewCell.h; sourceTree = "<group>"; };
F626D52D1C3E6CAA00C17D15 /* MWMTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMTableViewCell.mm; sourceTree = "<group>"; };
F63774E61B59375E00BCF54D /* MWMRoutingDisclaimerAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMRoutingDisclaimerAlert.xib; sourceTree = "<group>"; };
F63774E81B59376F00BCF54D /* MWMRoutingDisclaimerAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMRoutingDisclaimerAlert.h; sourceTree = "<group>"; };
F63774E91B59376F00BCF54D /* MWMRoutingDisclaimerAlert.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMRoutingDisclaimerAlert.mm; sourceTree = "<group>"; };
F6381BF41CD12045004CA943 /* LocaleTranslator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocaleTranslator.mm; sourceTree = "<group>"; };
F63B242E1E890C8F008C9D3C /* CacheableFacebookBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheableFacebookBanner.swift; sourceTree = "<group>"; };
F64D9C9D1C899C350063FA30 /* MWMEditorViralAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMEditorViralAlert.h; sourceTree = "<group>"; };
F64D9C9E1C899C350063FA30 /* MWMEditorViralAlert.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMEditorViralAlert.mm; sourceTree = "<group>"; };
F64D9CA11C899C760063FA30 /* MWMEditorViralAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMEditorViralAlert.xib; sourceTree = "<group>"; };
@ -2656,6 +2678,7 @@
340475281E081A4600C92850 /* Core */ = {
isa = PBXGroup;
children = (
3488AFF51E9D0AD00068AFD8 /* Ads */,
3486B50F1E27AD3B0069C126 /* Framework */,
340475291E081A4600C92850 /* Location */,
340475301E081A4600C92850 /* NetworkPolicy */,
@ -2777,8 +2800,8 @@
3432E17F1E49BEFA008477E9 /* Ads */ = {
isa = PBXGroup;
children = (
3432E1801E49BF09008477E9 /* FBAdsBanner.swift */,
3432E1841E49BF5C008477E9 /* FBAdsBanner.xib */,
3488B0101E9D0AEC0068AFD8 /* AdBanner.swift */,
3488B0111E9D0AEC0068AFD8 /* AdBanner.xib */,
);
path = Ads;
sourceTree = "<group>";
@ -2801,6 +2824,7 @@
34D3AFF41E37A36A004100F9 /* UICollectionView+Cells.swift */,
3454D7A41E07F045004AF2AD /* UIColor+MapsMeColor.h */,
3454D7A51E07F045004AF2AD /* UIColor+MapsMeColor.mm */,
3488B0181E9D0B230068AFD8 /* UIColor+Modifications.swift */,
3454D7A61E07F045004AF2AD /* UIFont+MapsMeFonts.h */,
3454D7A71E07F045004AF2AD /* UIFont+MapsMeFonts.mm */,
3454D7A81E07F045004AF2AD /* UIImage+RGBAData.h */,
@ -2820,14 +2844,14 @@
3454D7B31E07F045004AF2AD /* UITextField+RuntimeAttributes.mm */,
3454D7B41E07F045004AF2AD /* UITextView+RuntimeAttributes.h */,
3454D7B51E07F045004AF2AD /* UITextView+RuntimeAttributes.mm */,
3404164A1E7BF42D00E2B6D6 /* UIView+Coordinates.swift */,
34F5E0D21E3F254800B1C415 /* UIView+Hierarchy.swift */,
3454D7B61E07F045004AF2AD /* UIView+RuntimeAttributes.h */,
3454D7B71E07F045004AF2AD /* UIView+RuntimeAttributes.mm */,
340416461E7BF28E00E2B6D6 /* UIView+Snapshot.swift */,
349D1CE21E3F836900A878FD /* UIViewController+Hierarchy.swift */,
34F7422F1E0834F400AC1FD6 /* UIViewController+Navigation.h */,
34F742301E0834F400AC1FD6 /* UIViewController+Navigation.mm */,
340416461E7BF28E00E2B6D6 /* UIView+Snapshot.swift */,
3404164A1E7BF42D00E2B6D6 /* UIView+Coordinates.swift */,
);
path = Categories;
sourceTree = "<group>";
@ -2994,6 +3018,21 @@
path = Framework;
sourceTree = "<group>";
};
3488AFF51E9D0AD00068AFD8 /* Ads */ = {
isa = PBXGroup;
children = (
3488AFF61E9D0AD00068AFD8 /* Banner.swift */,
3488AFF71E9D0AD00068AFD8 /* BannersCache.swift */,
3488AFF81E9D0AD00068AFD8 /* BannerType.swift */,
3488AFF91E9D0AD00068AFD8 /* FacebookBanner.swift */,
3488AFFA1E9D0AD00068AFD8 /* MWMBannerHelpers.h */,
3488AFFB1E9D0AD00068AFD8 /* MWMCoreBanner.h */,
3488AFFC1E9D0AD00068AFD8 /* MWMCoreBanner.mm */,
3488AFFD1E9D0AD00068AFD8 /* RBBanner.swift */,
);
path = Ads;
sourceTree = "<group>";
};
34943BB01E2620C600B14F84 /* Welcome */ = {
isa = PBXGroup;
children = (
@ -3684,8 +3723,6 @@
F6E2FC931E097B9F0083EBEC /* DirectionView */,
F6E2FC971E097B9F0083EBEC /* MWMPlacePageData.h */,
F6E2FC981E097B9F0083EBEC /* MWMPlacePageData.mm */,
F624592E1E80185500E7AE9E /* BannersCache.swift */,
F63B242E1E890C8F008C9D3C /* CacheableFacebookBanner.swift */,
F6E2FC991E097B9F0083EBEC /* MWMPlacePageManager.h */,
F6E2FC9A1E097B9F0083EBEC /* MWMPlacePageManager.mm */,
F6E2FC9B1E097B9F0083EBEC /* MWMPlacePageProtocol.h */,
@ -4311,7 +4348,6 @@
4A00DBDF1AB704C400113624 /* drules_proto_dark.bin in Resources */,
6B9978351C89A316003B8AA0 /* editor.config in Resources */,
978D4A31199A11E600D72CA7 /* faq.html in Resources */,
3432E1851E49BF5C008477E9 /* FBAdsBanner.xib in Resources */,
EEFE7C1412F8C9E1006AF8C3 /* fonts_blacklist.txt in Resources */,
EEFE7C1512F8C9E1006AF8C3 /* fonts_whitelist.txt in Resources */,
34F73FA21E08300E00AC1FD6 /* Images.xcassets in Resources */,
@ -4391,6 +4427,7 @@
F63774E71B59375E00BCF54D /* MWMRoutingDisclaimerAlert.xib in Resources */,
F6E2FEFF1E097BA00083EBEC /* MWMSearchCategoryCell.xib in Resources */,
F69CE8DD1E5C51AB002B5881 /* CarouselElement.xib in Resources */,
3488B0151E9D0AEC0068AFD8 /* AdBanner.xib in Resources */,
F6E2FF321E097BA00083EBEC /* MWMSearchCommonCell.xib in Resources */,
BB7626B51E8559980031D71C /* icudt57l.dat in Resources */,
F6E2FF051E097BA00083EBEC /* MWMSearchHistoryClearCell.xib in Resources */,
@ -4478,7 +4515,6 @@
6741A97E1BF340DE002C974C /* drules_proto_dark.bin in Resources */,
6B9978361C89A316003B8AA0 /* editor.config in Resources */,
6741A9681BF340DE002C974C /* faq.html in Resources */,
3432E1861E49BF5C008477E9 /* FBAdsBanner.xib in Resources */,
6741A94C1BF340DE002C974C /* fonts_blacklist.txt in Resources */,
6741A9501BF340DE002C974C /* fonts_whitelist.txt in Resources */,
34F73FA31E08300E00AC1FD6 /* Images.xcassets in Resources */,
@ -4559,6 +4595,7 @@
F6E2FF001E097BA00083EBEC /* MWMSearchCategoryCell.xib in Resources */,
F6E2FF331E097BA00083EBEC /* MWMSearchCommonCell.xib in Resources */,
F6E2FF061E097BA00083EBEC /* MWMSearchHistoryClearCell.xib in Resources */,
3488B0161E9D0AEC0068AFD8 /* AdBanner.xib in Resources */,
F6E2FF0F1E097BA00083EBEC /* MWMSearchHistoryMyPositionCell.xib in Resources */,
BB7626B61E85599C0031D71C /* icudt57l.dat in Resources */,
F6E2FF151E097BA00083EBEC /* MWMSearchHistoryRequestCell.xib in Resources */,
@ -4646,7 +4683,6 @@
849CF64E1DE842290024A8A5 /* drules_proto_dark.bin in Resources */,
849CF64A1DE842290024A8A5 /* editor.config in Resources */,
849CF6291DE842290024A8A5 /* faq.html in Resources */,
3432E1871E49BF5C008477E9 /* FBAdsBanner.xib in Resources */,
849CF5F91DE842290024A8A5 /* fonts_blacklist.txt in Resources */,
849CF5FF1DE842290024A8A5 /* fonts_whitelist.txt in Resources */,
34F73FA41E08300E00AC1FD6 /* Images.xcassets in Resources */,
@ -4727,6 +4763,7 @@
849CF6191DE842290024A8A5 /* MWMRoutingDisclaimerAlert.xib in Resources */,
F6E2FF011E097BA00083EBEC /* MWMSearchCategoryCell.xib in Resources */,
F6E2FF341E097BA00083EBEC /* MWMSearchCommonCell.xib in Resources */,
3488B0171E9D0AEC0068AFD8 /* AdBanner.xib in Resources */,
F6E2FF071E097BA00083EBEC /* MWMSearchHistoryClearCell.xib in Resources */,
BB7626B71E85599C0031D71C /* icudt57l.dat in Resources */,
341B10761E55B15B00071C74 /* MWMMobileInternetAlert.xib in Resources */,
@ -4968,6 +5005,7 @@
346DB8391E5C4F6700E3123E /* GalleryItemModel.swift in Sources */,
3404757D1E081B3300C92850 /* iosOGLContext.mm in Sources */,
34D3AFF11E37945B004100F9 /* UITableView+Cells.swift in Sources */,
3488B00A1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */,
34D3B02F1E389D05004100F9 /* MWMEditorCategoryCell.mm in Sources */,
F6E2FD5B1E097BA00083EBEC /* MWMMapDownloaderCellHeader.mm in Sources */,
340475611E081A4600C92850 /* MWMNetworkPolicy.mm in Sources */,
@ -4990,7 +5028,6 @@
34D3B0171E389D05004100F9 /* EditorAdditionalNamePlaceholderTableViewCell.swift in Sources */,
346DB8271E5C4F6700E3123E /* GalleryCell.swift in Sources */,
3406FA151C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */,
3432E1811E49BF09008477E9 /* FBAdsBanner.swift in Sources */,
F6E2FECC1E097BA00083EBEC /* MWMSearchFilterTransitioningManager.mm in Sources */,
F6E2FF111E097BA00083EBEC /* MWMSearchHistoryRequestCell.mm in Sources */,
34C9BD021C6DB693000DC38D /* MWMTableViewController.mm in Sources */,
@ -5001,7 +5038,6 @@
F6E2FD5E1E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm in Sources */,
F6558DA11E642CC0002203AE /* MWMFacilitiesController.mm in Sources */,
F6E2FF471E097BA00083EBEC /* SettingsTableViewSelectableCell.swift in Sources */,
F624592F1E80185500E7AE9E /* BannersCache.swift in Sources */,
349D1ACE1E2E325B004A2006 /* MWMBottomMenuCollectionViewCell.mm in Sources */,
F6E2FF261E097BA00083EBEC /* MWMSearchTabButtonsView.mm in Sources */,
F6E2FE901E097BA00083EBEC /* MWMPlacePageTaxiCell.mm in Sources */,
@ -5031,6 +5067,7 @@
343E75971E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */,
3454D7DF1E07F045004AF2AD /* UITextField+RuntimeAttributes.mm in Sources */,
3486B50C1E27A6DA0069C126 /* MWMPushNotifications.mm in Sources */,
3488B00D1E9D0AD00068AFD8 /* RBBanner.swift in Sources */,
F6E2FEF91E097BA00083EBEC /* MWMSearchCategoriesManager.mm in Sources */,
F6E2FE421E097BA00083EBEC /* MWMDirectionView.mm in Sources */,
F6E2FD551E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.mm in Sources */,
@ -5086,6 +5123,7 @@
3454D7C71E07F045004AF2AD /* UIButton+RuntimeAttributes.mm in Sources */,
FAAEA7D5161D8D3100CCD661 /* BookmarksRootVC.mm in Sources */,
3404755E1E081A4600C92850 /* MWMLocationPredictor.mm in Sources */,
3488B0121E9D0AEC0068AFD8 /* AdBanner.swift in Sources */,
F6E2FE031E097BA00083EBEC /* MWMOpeningHoursDaysSelectorTableViewCell.mm in Sources */,
F6E2FE661E097BA00083EBEC /* MWMPlacePageButtonCell.mm in Sources */,
F6E2FE121E097BA00083EBEC /* MWMOpeningHoursTimeSelectorTableViewCell.mm in Sources */,
@ -5100,14 +5138,17 @@
34ED298A1E3BB9B40054D003 /* RoutePoint.swift in Sources */,
3497A93A1B5CF8A900F51E55 /* MWMNavigationDashboardManager.mm in Sources */,
F6E2FED81E097BA00083EBEC /* MWMSearchContentView.mm in Sources */,
3488B0071E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */,
F6E2FD881E097BA00083EBEC /* MWMMapDownloaderViewController.mm in Sources */,
34BC72241B0DECAE0012A34B /* MWMMapViewControlsManager.mm in Sources */,
F6E2FF4A1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */,
F6E2FE781E097BA00083EBEC /* MWMOpeningHoursLayoutHelper.mm in Sources */,
3488B0011E9D0AD00068AFD8 /* BannersCache.swift in Sources */,
F6BD1D201CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */,
F6B97B261CD0CA990009B612 /* MWMBookmarkNameCell.mm in Sources */,
F6E2FD7C1E097BA00083EBEC /* MWMMapDownloaderExtendedDataSource.mm in Sources */,
F6E2FED21E097BA00083EBEC /* MWMSearchHotelsFilterViewController.mm in Sources */,
3488B0041E9D0AD00068AFD8 /* BannerType.swift in Sources */,
34ABA6201C2D517500FE1BEC /* MWMInputValidator.mm in Sources */,
F6E2FF231E097BA00083EBEC /* MWMSearchTabbedViewLayout.mm in Sources */,
F6E2FF1D1E097BA00083EBEC /* MWMSearchTabbedViewController.mm in Sources */,
@ -5134,7 +5175,6 @@
3404165B1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,
340475701E081A4600C92850 /* MWMSettings.mm in Sources */,
3404756D1E081A4600C92850 /* MWMSearch.mm in Sources */,
F63B242F1E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */,
3486B5071E27A4B50069C126 /* LocalNotificationManager.mm in Sources */,
F6E2FEFC1E097BA00083EBEC /* MWMSearchCategoryCell.mm in Sources */,
3454D7CA1E07F045004AF2AD /* UIColor+MapsMeColor.mm in Sources */,
@ -5161,8 +5201,10 @@
3454D7D61E07F045004AF2AD /* UIKitCategories.mm in Sources */,
346DB83C1E5C4F6700E3123E /* GalleryModel.swift in Sources */,
34B924421DC8A29C0008D971 /* MWMMailViewController.mm in Sources */,
3488AFFE1E9D0AD00068AFD8 /* Banner.swift in Sources */,
F6E2FF171E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */,
F64F199B1AB81A00006EAF7E /* MWMAlert.mm in Sources */,
3488B0191E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */,
ED48BBB517C267F5003E7E92 /* ColorPickerView.mm in Sources */,
34F5E0D71E3F334700B1C415 /* Types.swift in Sources */,
F6E2FF561E097BA00083EBEC /* MWMMobileInternetViewController.mm in Sources */,
@ -5250,6 +5292,7 @@
346DB83A1E5C4F6700E3123E /* GalleryItemModel.swift in Sources */,
F6E2FD5C1E097BA00083EBEC /* MWMMapDownloaderCellHeader.mm in Sources */,
34D3AFF21E37945B004100F9 /* UITableView+Cells.swift in Sources */,
3488B00B1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */,
34D3B0301E389D05004100F9 /* MWMEditorCategoryCell.mm in Sources */,
F653CE191C71F62700A453F1 /* MWMAddPlaceNavigationBar.mm in Sources */,
340475621E081A4600C92850 /* MWMNetworkPolicy.mm in Sources */,
@ -5272,7 +5315,6 @@
34D3B0181E389D05004100F9 /* EditorAdditionalNamePlaceholderTableViewCell.swift in Sources */,
346DB8281E5C4F6700E3123E /* GalleryCell.swift in Sources */,
F6E2FF121E097BA00083EBEC /* MWMSearchHistoryRequestCell.mm in Sources */,
3432E1821E49BF09008477E9 /* FBAdsBanner.swift in Sources */,
F6FE3C391CC50FFD00A73196 /* MWMPlaceDoesntExistAlert.mm in Sources */,
F6E2FDFE1E097BA00083EBEC /* MWMOpeningHoursClosedSpanTableViewCell.mm in Sources */,
F6E2FEDC1E097BA00083EBEC /* MWMSearchManager+Filter.mm in Sources */,
@ -5283,7 +5325,6 @@
F6E2FF271E097BA00083EBEC /* MWMSearchTabButtonsView.mm in Sources */,
F6558DA21E642CC0002203AE /* MWMFacilitiesController.mm in Sources */,
F6E2FE911E097BA00083EBEC /* MWMPlacePageTaxiCell.mm in Sources */,
F62459301E80185500E7AE9E /* BannersCache.swift in Sources */,
349D1ACF1E2E325B004A2006 /* MWMBottomMenuCollectionViewCell.mm in Sources */,
F6E2FF451E097BA00083EBEC /* SettingsTableViewLinkCell.swift in Sources */,
34C9BD0A1C6DBCDA000DC38D /* MWMNavigationController.mm in Sources */,
@ -5313,6 +5354,7 @@
343E75981E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */,
F6E2FEFA1E097BA00083EBEC /* MWMSearchCategoriesManager.mm in Sources */,
F6664C131E645A4100E703C2 /* MWMPPReviewCell.mm in Sources */,
3488B00E1E9D0AD00068AFD8 /* RBBanner.swift in Sources */,
F6E2FE431E097BA00083EBEC /* MWMDirectionView.mm in Sources */,
3486B50D1E27A6DA0069C126 /* MWMPushNotifications.mm in Sources */,
F6E2FD561E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.mm in Sources */,
@ -5368,6 +5410,7 @@
F6E2FE9D1E097BA00083EBEC /* MWMiPhonePlacePageLayoutImpl.mm in Sources */,
3454D7C81E07F045004AF2AD /* UIButton+RuntimeAttributes.mm in Sources */,
6741AA041BF340DE002C974C /* MWMNavigationDashboardManager.mm in Sources */,
3488B0131E9D0AEC0068AFD8 /* AdBanner.swift in Sources */,
3404755F1E081A4600C92850 /* MWMLocationPredictor.mm in Sources */,
F6E2FE041E097BA00083EBEC /* MWMOpeningHoursDaysSelectorTableViewCell.mm in Sources */,
F6E2FE671E097BA00083EBEC /* MWMPlacePageButtonCell.mm in Sources */,
@ -5382,14 +5425,17 @@
34F5E0D41E3F254800B1C415 /* UIView+Hierarchy.swift in Sources */,
34ED298B1E3BB9B40054D003 /* RoutePoint.swift in Sources */,
6741AA0B1BF340DE002C974C /* MWMMapViewControlsManager.mm in Sources */,
3488B0081E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */,
F6E2FED91E097BA00083EBEC /* MWMSearchContentView.mm in Sources */,
F6E2FD891E097BA00083EBEC /* MWMMapDownloaderViewController.mm in Sources */,
F6BD1D211CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */,
F6E2FF4B1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */,
3488B0021E9D0AD00068AFD8 /* BannersCache.swift in Sources */,
F6E2FE791E097BA00083EBEC /* MWMOpeningHoursLayoutHelper.mm in Sources */,
F6B97B271CD0CA990009B612 /* MWMBookmarkNameCell.mm in Sources */,
34ABA6211C2D517500FE1BEC /* MWMInputValidator.mm in Sources */,
F6E2FD7D1E097BA00083EBEC /* MWMMapDownloaderExtendedDataSource.mm in Sources */,
3488B0051E9D0AD00068AFD8 /* BannerType.swift in Sources */,
F6E2FED31E097BA00083EBEC /* MWMSearchHotelsFilterViewController.mm in Sources */,
340475741E081A4600C92850 /* MWMStorage.mm in Sources */,
F6E2FF241E097BA00083EBEC /* MWMSearchTabbedViewLayout.mm in Sources */,
@ -5416,7 +5462,6 @@
3404165C1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,
34D4FA631E26572D003F53EF /* FirstLaunchController.swift in Sources */,
3404756E1E081A4600C92850 /* MWMSearch.mm in Sources */,
F63B24301E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */,
6741AA191BF340DE002C974C /* MWMDownloaderDialogCell.mm in Sources */,
F6E2FEFD1E097BA00083EBEC /* MWMSearchCategoryCell.mm in Sources */,
3486B5081E27A4B50069C126 /* LocalNotificationManager.mm in Sources */,
@ -5443,8 +5488,10 @@
340475651E081A4600C92850 /* MWMRouter.mm in Sources */,
F6E2FF181E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */,
346DB83D1E5C4F6700E3123E /* GalleryModel.swift in Sources */,
3488AFFF1E9D0AD00068AFD8 /* Banner.swift in Sources */,
3454D7D71E07F045004AF2AD /* UIKitCategories.mm in Sources */,
34AB39C21D2BD8310021857D /* MWMStopButton.mm in Sources */,
3488B01A1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */,
6741AA281BF340DE002C974C /* MWMAlert.mm in Sources */,
F6E2FF571E097BA00083EBEC /* MWMMobileInternetViewController.mm in Sources */,
34F5E0D81E3F334700B1C415 /* Types.swift in Sources */,
@ -5532,6 +5579,7 @@
346DB83B1E5C4F6700E3123E /* GalleryItemModel.swift in Sources */,
340475631E081A4600C92850 /* MWMNetworkPolicy.mm in Sources */,
34D3AFF31E37945B004100F9 /* UITableView+Cells.swift in Sources */,
3488B00C1E9D0AD00068AFD8 /* MWMCoreBanner.mm in Sources */,
34D3B0311E389D05004100F9 /* MWMEditorCategoryCell.mm in Sources */,
F6E2FD5D1E097BA00083EBEC /* MWMMapDownloaderCellHeader.mm in Sources */,
3454D7DB1E07F045004AF2AD /* UILabel+RuntimeAttributes.mm in Sources */,
@ -5554,7 +5602,6 @@
34D3B0191E389D05004100F9 /* EditorAdditionalNamePlaceholderTableViewCell.swift in Sources */,
346DB8291E5C4F6700E3123E /* GalleryCell.swift in Sources */,
340475781E081A4600C92850 /* MWMTrafficManager.mm in Sources */,
3432E1831E49BF09008477E9 /* FBAdsBanner.swift in Sources */,
F6E2FECE1E097BA00083EBEC /* MWMSearchFilterTransitioningManager.mm in Sources */,
F6E2FF131E097BA00083EBEC /* MWMSearchHistoryRequestCell.mm in Sources */,
849CF6D21DE842290024A8A5 /* MWMNavigationController.mm in Sources */,
@ -5565,7 +5612,6 @@
F6E2FD601E097BA00083EBEC /* MWMMapDownloaderLargeCountryTableViewCell.mm in Sources */,
F6558DA31E642CC0002203AE /* MWMFacilitiesController.mm in Sources */,
F6E2FF491E097BA00083EBEC /* SettingsTableViewSelectableCell.swift in Sources */,
F62459311E80185500E7AE9E /* BannersCache.swift in Sources */,
349D1AD01E2E325B004A2006 /* MWMBottomMenuCollectionViewCell.mm in Sources */,
F6E2FF281E097BA00083EBEC /* MWMSearchTabButtonsView.mm in Sources */,
F6E2FE921E097BA00083EBEC /* MWMPlacePageTaxiCell.mm in Sources */,
@ -5595,6 +5641,7 @@
343E75991E5B1EE20041226A /* MWMCollectionViewController.mm in Sources */,
3454D7CF1E07F045004AF2AD /* UIFont+MapsMeFonts.mm in Sources */,
3486B50E1E27A6DA0069C126 /* MWMPushNotifications.mm in Sources */,
3488B00F1E9D0AD00068AFD8 /* RBBanner.swift in Sources */,
F6E2FEFB1E097BA00083EBEC /* MWMSearchCategoriesManager.mm in Sources */,
F6E2FE441E097BA00083EBEC /* MWMDirectionView.mm in Sources */,
F6E2FD571E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.mm in Sources */,
@ -5650,6 +5697,7 @@
340475721E081A4600C92850 /* MWMSettings.mm in Sources */,
849CF7121DE842290024A8A5 /* SelectSetVC.mm in Sources */,
849CF7141DE842290024A8A5 /* AddSetVC.mm in Sources */,
3488B0141E9D0AEC0068AFD8 /* AdBanner.swift in Sources */,
F6E2FE051E097BA00083EBEC /* MWMOpeningHoursDaysSelectorTableViewCell.mm in Sources */,
F6E2FE681E097BA00083EBEC /* MWMPlacePageButtonCell.mm in Sources */,
F6E2FE141E097BA00083EBEC /* MWMOpeningHoursTimeSelectorTableViewCell.mm in Sources */,
@ -5664,14 +5712,17 @@
34ED298C1E3BB9B40054D003 /* RoutePoint.swift in Sources */,
849CF71D1DE842290024A8A5 /* MWMNavigationDashboardManager.mm in Sources */,
3454D7C91E07F045004AF2AD /* UIButton+RuntimeAttributes.mm in Sources */,
3488B0091E9D0AD00068AFD8 /* FacebookBanner.swift in Sources */,
F6E2FEDA1E097BA00083EBEC /* MWMSearchContentView.mm in Sources */,
F6E2FD8A1E097BA00083EBEC /* MWMMapDownloaderViewController.mm in Sources */,
F6E2FF4C1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */,
F6E2FE7A1E097BA00083EBEC /* MWMOpeningHoursLayoutHelper.mm in Sources */,
3488B0031E9D0AD00068AFD8 /* BannersCache.swift in Sources */,
849CF7251DE842290024A8A5 /* MWMMapViewControlsManager.mm in Sources */,
849CF7281DE842290024A8A5 /* MWMOsmAuthAlert.mm in Sources */,
F6E2FD7E1E097BA00083EBEC /* MWMMapDownloaderExtendedDataSource.mm in Sources */,
F6E2FED41E097BA00083EBEC /* MWMSearchHotelsFilterViewController.mm in Sources */,
3488B0061E9D0AD00068AFD8 /* BannerType.swift in Sources */,
849CF72B1DE842290024A8A5 /* MWMBookmarkNameCell.mm in Sources */,
F6E2FF251E097BA00083EBEC /* MWMSearchTabbedViewLayout.mm in Sources */,
F6E2FF1F1E097BA00083EBEC /* MWMSearchTabbedViewController.mm in Sources */,
@ -5698,7 +5749,6 @@
3404165D1E7C29AE00E2B6D6 /* PhotosInteractionAnimator.swift in Sources */,
340475571E081A4600C92850 /* Statistics.mm in Sources */,
3486B5091E27A4B50069C126 /* LocalNotificationManager.mm in Sources */,
F63B24311E890C8F008C9D3C /* CacheableFacebookBanner.swift in Sources */,
F6E2FEFE1E097BA00083EBEC /* MWMSearchCategoryCell.mm in Sources */,
3404754B1E081A4600C92850 /* AppInfo.mm in Sources */,
849CF73C1DE842290024A8A5 /* MWMMultilineLabel.mm in Sources */,
@ -5725,8 +5775,10 @@
849CF7601DE842290024A8A5 /* MWMStopButton.mm in Sources */,
346DB83E1E5C4F6700E3123E /* GalleryModel.swift in Sources */,
849CF7611DE842290024A8A5 /* MWMMailViewController.mm in Sources */,
3488B0001E9D0AD00068AFD8 /* Banner.swift in Sources */,
F6E2FF191E097BA00083EBEC /* MWMSearchTabbedCollectionViewCell.mm in Sources */,
3404754E1E081A4600C92850 /* MWMKeyboard.mm in Sources */,
3488B01B1E9D0B230068AFD8 /* UIColor+Modifications.swift in Sources */,
849CF7631DE842290024A8A5 /* MWMAlert.mm in Sources */,
34F5E0D91E3F334700B1C415 /* Types.swift in Sources */,
F6E2FF581E097BA00083EBEC /* MWMMobileInternetViewController.mm in Sources */,

View file

@ -0,0 +1,134 @@
import FBAudienceNetwork
@objc(MWMAdBannerState)
enum AdBannerState: Int {
case compact
case detailed
func config() -> (priority: UILayoutPriority, numberOfTitleLines: Int, numberOfBodyLines: Int) {
switch self {
case .compact:
return alternative(iPhone: (priority: UILayoutPriorityDefaultLow, numberOfTitleLines: 1, numberOfBodyLines: 2),
iPad: (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0))
case .detailed:
return (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0)
}
}
}
@objc(MWMAdBanner)
final class AdBanner: UITableViewCell {
@IBOutlet private var detailedModeConstraints: [NSLayoutConstraint]!
@IBOutlet private weak var adIconImageView: UIImageView!
@IBOutlet private weak var adTitleLabel: UILabel!
@IBOutlet private weak var adBodyLabel: UILabel!
@IBOutlet private var adCallToActionButtonCompact: UIButton!
@IBOutlet private var adCallToActionButtonDetailed: UIButton!
static let detailedBannerExcessHeight: Float = 36
var state = alternative(iPhone: AdBannerState.compact, iPad: AdBannerState.detailed) {
didSet {
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
detailedModeConstraints.forEach { $0.priority = config.priority }
setNeedsLayout()
UIView.animate(withDuration: kDefaultAnimationDuration) { self.layoutIfNeeded() }
registerRBBanner()
}
}
private var nativeAd: MWMBanner?
func config(ad: MWMBanner) {
nativeAd = ad
switch ad.mwmType {
case .none:
assert(false)
case .facebook:
configFBBanner(ad: ad as! FBNativeAd)
case .rb:
configRBBanner(ad: ad as! MTRGNativeAd)
}
}
func highlightButton() {
adCallToActionButtonDetailed.setBackgroundImage(nil, for: .normal)
adCallToActionButtonCompact.setBackgroundImage(nil, for: .normal)
adCallToActionButtonDetailed.backgroundColor = UIColor.bannerButtonBackground()
adCallToActionButtonCompact.backgroundColor = UIColor.bannerBackground()
let duration = 0.5 * kDefaultAnimationDuration
let darkerPercent: CGFloat = 0.2
UIView.animate(withDuration: duration, animations: {
self.adCallToActionButtonDetailed.backgroundColor = UIColor.bannerButtonBackground().darker(percent: darkerPercent)
self.adCallToActionButtonCompact.backgroundColor = UIColor.bannerBackground().darker(percent: darkerPercent)
}, completion: { _ in
UIView.animate(withDuration: duration, animations: {
self.adCallToActionButtonDetailed.backgroundColor = UIColor.bannerButtonBackground()
self.adCallToActionButtonCompact.backgroundColor = UIColor.bannerBackground()
}, completion: { _ in
self.adCallToActionButtonDetailed.setBackgroundColor(UIColor.bannerButtonBackground(), for: .normal)
self.adCallToActionButtonCompact.setBackgroundColor(UIColor.bannerBackground(), for: .normal)
})
})
}
private func configFBBanner(ad: FBNativeAd) {
ad.unregisterView()
let adCallToActionButtons = [adCallToActionButtonCompact!, adCallToActionButtonDetailed!]
ad.registerView(forInteraction: self, with: nil, withClickableViews: adCallToActionButtons)
ad.icon?.loadAsync { [weak self] image in
self?.adIconImageView.image = image
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 24
paragraphStyle.lineBreakMode = .byTruncatingTail
let adTitle = NSAttributedString(string: ad.title ?? "",
attributes: [NSParagraphStyleAttributeName: paragraphStyle,
NSFontAttributeName: UIFont.bold12(),
NSForegroundColorAttributeName: UIColor.blackSecondaryText()])
adTitleLabel.attributedText = adTitle
adBodyLabel.text = ad.body ?? ""
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
adCallToActionButtons.forEach { $0.setTitle(ad.callToAction, for: .normal) }
}
private func configRBBanner(ad: MTRGNativeAd) {
ad.unregisterView()
guard let banner = ad.banner else { return }
ad.loadIcon(to: adIconImageView)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 24
paragraphStyle.lineBreakMode = .byTruncatingTail
let adTitle = NSAttributedString(string: banner.title ?? "",
attributes: [NSParagraphStyleAttributeName: paragraphStyle,
NSFontAttributeName: UIFont.bold12(),
NSForegroundColorAttributeName: UIColor.blackSecondaryText()])
adTitleLabel.attributedText = adTitle
adBodyLabel.text = banner.descriptionText ?? ""
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
[adCallToActionButtonCompact, adCallToActionButtonDetailed].forEach { $0.setTitle(banner.ctaText, for: .normal) }
registerRBBanner()
}
private func registerRBBanner() {
guard let ad = nativeAd as? MTRGNativeAd else { return }
let clickableView: UIView
switch state {
case .compact: clickableView = adCallToActionButtonCompact
case .detailed: clickableView = adCallToActionButtonDetailed
}
ad.register(clickableView, with: UIViewController.topViewController())
}
}

View file

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<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">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WK2-gA-ocn" customClass="MWMFBAdsBanner">
<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">
@ -47,7 +47,7 @@
</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="258.5" height="15"/>
<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"/>

View file

@ -1,66 +0,0 @@
import FBAudienceNetwork
@objc(MWMFBAdsBannerState)
enum FBAdsBannerState: Int {
case compact
case detailed
func config() -> (priority: UILayoutPriority, numberOfTitleLines: Int, numberOfBodyLines: Int) {
switch self {
case .compact:
return alternative(iPhone: (priority: UILayoutPriorityDefaultLow, numberOfTitleLines: 1, numberOfBodyLines: 2),
iPad: (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0))
case .detailed:
return (priority: UILayoutPriorityDefaultHigh, numberOfTitleLines: 0, numberOfBodyLines: 0)
}
}
}
@objc(MWMFBAdsBanner)
final class FBAdsBanner: UITableViewCell {
@IBOutlet private var detailedModeConstraints: [NSLayoutConstraint]!
@IBOutlet private weak var adIconImageView: UIImageView!
@IBOutlet private weak var adTitleLabel: UILabel!
@IBOutlet private weak var adBodyLabel: UILabel!
@IBOutlet private var adCallToActionButtonCompact: UIButton!
@IBOutlet private var adCallToActionButtonDetailed: UIButton!
static let detailedBannerExcessHeight: Float = 36
var state = alternative(iPhone: FBAdsBannerState.compact, iPad: FBAdsBannerState.detailed) {
didSet {
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
detailedModeConstraints.forEach { $0.priority = config.priority }
setNeedsLayout()
UIView.animate(withDuration: kDefaultAnimationDuration) { self.layoutIfNeeded() }
}
}
private var nativeAd: FBNativeAd?
func config(ad: FBNativeAd) {
nativeAd = ad
ad.unregisterView()
let adCallToActionButtons = [adCallToActionButtonCompact!, adCallToActionButtonDetailed!]
ad.registerView(forInteraction: self, with: nil, withClickableViews: adCallToActionButtons)
ad.icon?.loadAsync { [weak self] image in
self?.adIconImageView.image = image
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 24
paragraphStyle.lineBreakMode = .byTruncatingTail
let adTitle = NSAttributedString(string: ad.title ?? "",
attributes: [NSParagraphStyleAttributeName: paragraphStyle,
NSFontAttributeName: UIFont.bold12(),
NSForegroundColorAttributeName: UIColor.blackSecondaryText()])
adTitleLabel.attributedText = adTitle
adBodyLabel.text = ad.body ?? ""
let config = state.config()
adTitleLabel.numberOfLines = config.numberOfTitleLines
adBodyLabel.numberOfLines = config.numberOfBodyLines
adCallToActionButtons.forEach { $0.setTitle(ad.callToAction, for: .normal) }
}
}

View file

@ -1,96 +0,0 @@
import Crashlytics
// MARK: Cacheable protocol
protocol Cacheable {
typealias EventName = String
typealias ErrorDetails = [String : Any]
typealias Success = (Cacheable) -> Void
typealias Failure = (EventName, ErrorDetails, NSError) -> Void
func reload(_ success: @escaping Success, failure: @escaping Failure)
func bannerIsOutOfScreen()
func bannerIsOnScreen()
var isNeedToRetain: Bool { get }
var isPossibleToReload: Bool { get }
var adID: String { get }
var isBannerOnScreen: Bool { get }
}
// MARK: BannersCache
@objc (MWMBannersCache)
final class BannersCache: NSObject {
static let cache = BannersCache()
private override init() {}
private var cache: [String : Cacheable] = [:]
private var requests: Set<String> = []
typealias Completion = (Any, Bool) -> Void
private var completion: Completion?
func get(_ key: String, completion comp: @escaping Completion) {
completion = comp
func onBannerFinished(_ cacheable: Cacheable, isAsync: Bool) {
if let compl = completion {
compl(cacheable, isAsync)
cacheable.bannerIsOnScreen()
}
}
if let cached = cache[key] {
onBannerFinished(cached, isAsync: false)
completion = nil;
if !cached.isPossibleToReload || cached.isNeedToRetain {
return
}
}
if requests.contains(key) {
return
}
let banner = CacheableFacebookBanner(placementID: key)
banner.reload({ [weak self] cacheable in
guard let s = self else { return }
Statistics.logEvent(kStatPlacePageBannerShow,
withParameters: [kStatBanner : key, kStatProvider : kStatFacebook])
s.add(cacheable)
s.removeRequest(atKey: key)
onBannerFinished(cacheable, isAsync: true)
}, failure: { [weak self] event, errorDetails, error in
guard let s = self else { return }
Statistics.logEvent(event, withParameters: errorDetails)
Crashlytics.sharedInstance().recordError(error)
s.removeRequest(atKey: key)
})
addRequest(key)
}
func bannerIsOutOfScreen(_ bannerID: String) {
if let cached = cache[bannerID], cached.isBannerOnScreen {
cached.bannerIsOutOfScreen()
}
}
private func add(_ banner: Cacheable) {
cache[banner.adID] = banner
}
private func removeRequest(atKey key: String) {
requests.remove(key)
}
private func addRequest(_ key: String) {
requests.insert(key)
}
}

View file

@ -1,3 +1,5 @@
#import "SwiftBridge.h"
#include "map/place_page_info.hpp"
#include "std/vector.hpp"
@ -97,7 +99,6 @@ using BannerIsReady = void (^)();
@class MWMGalleryItemModel;
@class FBNativeAd;
/// ViewModel for place page.
@interface MWMPlacePageData : NSObject
@ -136,7 +137,7 @@ using BannerIsReady = void (^)();
- (NSArray<MWMGalleryItemModel *> *)photos;
// Banner
- (FBNativeAd *)nativeAd;
- (id<MWMBanner>)nativeAd;
// API
- (NSString *)apiURL;

View file

@ -1,5 +1,6 @@
#import "MWMPlacePageData.h"
#import "AppInfo.h"
#import "MWMBannerHelpers.h"
#import "MWMNetworkPolicy.h"
#import "MWMSettings.h"
#import "Statistics.h"
@ -26,7 +27,7 @@ using namespace place_page;
@interface MWMPlacePageData ()
@property(copy, nonatomic) NSString * cachedMinPrice;
@property(nonatomic) FBNativeAd * nativeAd;
@property(nonatomic) id<MWMBanner> nativeAd;
@property(copy, nonatomic) NSArray<MWMGalleryItemModel *> * photos;
@end
@ -104,17 +105,18 @@ using namespace place_page;
if (network_policy::CanUseNetwork() && ![MWMSettings adForbidden] && m_info.HasBanner())
{
__weak auto wSelf = self;
// Dummy should be changed by IOS developer
[[MWMBannersCache cache] get:@(m_info.GetBanners()[0].m_bannerId.c_str()) completion:^(FBNativeAd * ad, BOOL isAsync) {
__strong auto self = wSelf;
if (!self)
return;
self.nativeAd = ad;
self->m_previewRows.push_back(PreviewRows::Banner);
if (isAsync)
self.bannerIsReadyCallback();
}];
[[MWMBannersCache cache]
getWithCoreBanners:banner_helpers::MatchPriorityBanners(m_info.GetBanners())
completion:^(id<MWMBanner> ad, BOOL isAsync) {
__strong auto self = wSelf;
if (!self)
return;
self.nativeAd = ad;
self->m_previewRows.push_back(PreviewRows::Banner);
if (isAsync)
self.bannerIsReadyCallback();
}];
}
}
@ -302,11 +304,8 @@ using namespace place_page;
- (void)dealloc
{
if (m_info.HasBanner())
{
// Dummy should be changed by IOS developer
[[MWMBannersCache cache] bannerIsOutOfScreen:@(m_info.GetBanners()[0].m_bannerId.c_str())];
}
if (self.nativeAd)
[[MWMBannersCache cache] bannerIsOutOfScreenWithCoreBanner:self.nativeAd];
}
#pragma mark - Getters

View file

@ -1,5 +1,6 @@
#import "MWMiPadPlacePageLayoutImpl.h"
#import "MWMPlacePageLayout.h"
#import "SwiftBridge.h"
namespace
{
@ -9,7 +10,7 @@ CGFloat const kTopOffset = 36;
CGFloat const kBottomOffset = 60;
} // namespace
@interface MWMiPadPlacePageLayoutImpl ()
@interface MWMiPadPlacePageLayoutImpl ()<UITableViewDelegate>
@property(nonatomic) CGFloat topBound;
@property(nonatomic) CGFloat leftBound;
@ -32,6 +33,7 @@ CGFloat const kBottomOffset = 60;
{
_ownerView = ownerView;
self.placePageView = placePageView;
placePageView.tableView.delegate = self;
_delegate = delegate;
[self addShadow];
}
@ -182,6 +184,15 @@ CGFloat const kBottomOffset = 60;
- (CGFloat)topBound { return _topBound + kTopOffset; }
- (CGFloat)leftBound { return _leftBound + kLeftOffset; }
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
auto cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[MWMAdBanner class]])
[static_cast<MWMAdBanner *>(cell) highlightButton];
}
#pragma mark - Properties
- (void)setPlacePageView:(MWMPPView *)placePageView

View file

@ -1,6 +1,7 @@
#import "MWMPlacePageLayout.h"
#import "MWMiPhonePlacePageLayoutImpl.h"
#import "MWMPPPreviewLayoutHelper.h"
#import "MWMPlacePageLayout.h"
#import "SwiftBridge.h"
namespace
{
@ -267,6 +268,12 @@ CGFloat const kMinOffset = 1;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
auto cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[MWMAdBanner class]])
{
[static_cast<MWMAdBanner *>(cell) highlightButton];
return;
}
if (indexPath.section != 0)
return;

View file

@ -124,7 +124,7 @@ namespace
array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTitle class],
[_MWMPPPSubtitle class], [_MWMPPPSchedule class],
[_MWMPPPBooking class], [_MWMPPPAddress class],
[_MWMPPPSpace class], [MWMFBAdsBanner class]}};
[_MWMPPPSpace class], [MWMAdBanner class]}};
} // namespace
@interface MWMPPPreviewLayoutHelper ()
@ -145,7 +145,7 @@ array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTi
@property(nonatomic) BOOL lastCellIsBanner;
@property(nonatomic) NSUInteger distanceRow;
@property(weak, nonatomic) MWMFBAdsBanner * cachedBannerCell;
@property(weak, nonatomic) MWMAdBanner * cachedBannerCell;
@end
@ -234,7 +234,7 @@ array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTi
case PreviewRows::Space:
return c;
case PreviewRows::Banner:
auto bannerCell = static_cast<MWMFBAdsBanner *>(c);
auto bannerCell = static_cast<MWMAdBanner *>(c);
[bannerCell configWithAd:data.nativeAd];
self.cachedBannerCell = bannerCell;
return bannerCell;
@ -314,8 +314,8 @@ array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTi
return height;
auto constexpr gapBannerHeight = 4.0;
CGFloat const excessHeight = self.cachedBannerCell.state == MWMFBAdsBannerStateDetailed
? [MWMFBAdsBanner detailedBannerExcessHeight]
CGFloat const excessHeight = self.cachedBannerCell.state == MWMAdBannerStateDetailed
? [MWMAdBanner detailedBannerExcessHeight]
: 0;
return height + gapBannerHeight - excessHeight;
@ -327,7 +327,7 @@ array<Class, 8> const kPreviewCells = {{[_MWMPPPTitle class], [_MWMPPPExternalTi
return;
[self.tableView update:^{
self.cachedBannerCell.state = isOpen ? MWMFBAdsBannerStateDetailed : MWMFBAdsBannerStateCompact;
self.cachedBannerCell.state = isOpen ? MWMAdBannerStateDetailed : MWMAdBannerStateCompact;
}];
}