Commit fda52da8 by Demid Merzlyakov

IOS-73: hide adviews when there are no ads.

parent dc0d546b
...@@ -10,13 +10,22 @@ import Foundation ...@@ -10,13 +10,22 @@ import Foundation
import GoogleMobileAds import GoogleMobileAds
import UIKit import UIKit
@objc
public protocol AdViewDelegate: AnyObject { public protocol AdViewDelegate: AnyObject {
func succeeded(adView: AdView) func succeeded(adView: AdView, hadAdBefore: Bool)
func failed(adView: AdView) func failed(adView: AdView, hadAdBefore: Bool)
func closeButtonTapped(adView: AdView) func closeButtonTapped(adView: AdView)
/// Return the view controller, that will present the interstitial. /// Return the view controller, that will present the interstitial.
func adTopViewController() -> UIViewController func adTopViewController() -> UIViewController?
}
// MARK: - Default methods implementation
extension AdViewDelegate {
func closeButtonTapped(adView: AdView) {
// do nothing
}
func adTopViewController() -> UIViewController? {
return nil
}
} }
@objcMembers @objcMembers
...@@ -324,22 +333,25 @@ extension AdView { ...@@ -324,22 +333,25 @@ extension AdView {
extension AdView: NativeBannerContainerViewDelegate { extension AdView: NativeBannerContainerViewDelegate {
func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView) { func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView) {
log.info("ad request succeeded") log.info("ad request succeeded")
let hadAdBefore = adReady
adReady = true adReady = true
analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams) analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams)
self.delegate?.succeeded(adView: self) self.delegate?.succeeded(adView: self, hadAdBefore: hadAdBefore)
} }
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) { func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
log.info("ad request succeeded") log.info("ad request succeeded")
let hadAdBefore = adReady
adReady = true adReady = true
analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams) analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams)
self.delegate?.succeeded(adView: self) self.delegate?.succeeded(adView: self, hadAdBefore: hadAdBefore)
} }
public func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) { public func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
log.error("ad request failed") log.error("ad request failed")
let hadAdBefore = adReady
adReady = false adReady = false
self.delegate?.failed(adView: self) self.delegate?.failed(adView: self, hadAdBefore: hadAdBefore)
} }
} }
......
...@@ -7,7 +7,19 @@ ...@@ -7,7 +7,19 @@
import UIKit import UIKit
extension CellFactoryProtocol { public protocol CellFactory {
var numberOfSections:Int { get }
func numberOfRows(inSection section:Int) -> Int
func registerCells(on tableView:UITableView)
func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell
}
public protocol CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory)
}
// MARK: - Default methods implementation
extension CellFactory {
func dequeueReusableCell<T: ReusableCellProtocol>(type:T.Type, tableView:UITableView, indexPath: IndexPath) -> T { func dequeueReusableCell<T: ReusableCellProtocol>(type:T.Type, tableView:UITableView, indexPath: IndexPath) -> T {
let cell = tableView.dequeueReusableCell(withIdentifier: T.kIdentifier, for: indexPath) as! T let cell = tableView.dequeueReusableCell(withIdentifier: T.kIdentifier, for: indexPath) as! T
return cell return cell
...@@ -17,10 +29,3 @@ extension CellFactoryProtocol { ...@@ -17,10 +29,3 @@ extension CellFactoryProtocol {
tableView.register(type, forCellReuseIdentifier: T.kIdentifier) tableView.register(type, forCellReuseIdentifier: T.kIdentifier)
} }
} }
public protocol CellFactoryProtocol {
var numberOfSections:Int { get }
func numberOfRows(inSection section:Int) -> Int
func registerCells(on tableView:UITableView)
func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell
}
...@@ -64,10 +64,12 @@ class BannerAdCell: UITableViewCell, AdCell { ...@@ -64,10 +64,12 @@ class BannerAdCell: UITableViewCell, AdCell {
private extension BannerAdCell { private extension BannerAdCell {
func prepareCellStyle() { func prepareCellStyle() {
selectionStyle = .none selectionStyle = .none
clipsToBounds = true
} }
func prepareContainer() { func prepareContainer() {
container.layer.cornerRadius = 6 container.layer.cornerRadius = 6
container.clipsToBounds = true
contentView.addSubview(container) contentView.addSubview(container)
container.snp.makeConstraints { (make) in container.snp.makeConstraints { (make) in
......
...@@ -26,7 +26,7 @@ class MRECAdCell: UITableViewCell, AdCell { ...@@ -26,7 +26,7 @@ class MRECAdCell: UITableViewCell, AdCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
prepareCellStyle() prepareCell()
prepareContainer() prepareContainer()
prepareAd() prepareAd()
prepareGradient() prepareGradient()
...@@ -58,8 +58,9 @@ class MRECAdCell: UITableViewCell, AdCell { ...@@ -58,8 +58,9 @@ class MRECAdCell: UITableViewCell, AdCell {
//MARK:- Prepare //MARK:- Prepare
private extension MRECAdCell { private extension MRECAdCell {
func prepareCellStyle() { func prepareCell() {
selectionStyle = .none selectionStyle = .none
clipsToBounds = true
} }
func prepareContainer() { func prepareContainer() {
......
...@@ -30,6 +30,7 @@ class ForecastViewController: UIViewController { ...@@ -30,6 +30,7 @@ class ForecastViewController: UIViewController {
self.coordinator = coordinator self.coordinator = coordinator
self.forecastCellFactory = ForecastCellFactory(viewModel: viewModel) self.forecastCellFactory = ForecastCellFactory(viewModel: viewModel)
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
self.forecastCellFactory.delegate = self
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
...@@ -159,7 +160,6 @@ private extension ForecastViewController { ...@@ -159,7 +160,6 @@ private extension ForecastViewController {
tableView.separatorStyle = .none tableView.separatorStyle = .none
tableView.tableFooterView = UIView() tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
tableView.delegate = self tableView.delegate = self
tableView.dataSource = self tableView.dataSource = self
view.addSubview(tableView) view.addSubview(tableView)
...@@ -247,6 +247,10 @@ extension ForecastViewController: UITableViewDataSource { ...@@ -247,6 +247,10 @@ extension ForecastViewController: UITableViewDataSource {
return forecastCellFactory.cellFromTableView(tableView: tableView, return forecastCellFactory.cellFromTableView(tableView: tableView,
indexPath: indexPath) indexPath: indexPath)
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
forecastCellFactory.height(for: indexPath)
}
} }
//MARK:- ViewModel Delegate //MARK:- ViewModel Delegate
...@@ -278,3 +282,9 @@ extension ForecastViewController: DaysControlViewDelegate { ...@@ -278,3 +282,9 @@ extension ForecastViewController: DaysControlViewDelegate {
viewModel.offsetHolder.update(offset: offset) viewModel.offsetHolder.update(offset: offset)
} }
} }
extension ForecastViewController: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
self.tableView.reloadData()
}
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
import UIKit import UIKit
import OneWeatherCore import OneWeatherCore
class LocationCellFactory: CellFactoryProtocol { class LocationCellFactory: CellFactory {
//Private //Private
private let locationsViewModel:LocationsViewModel private let locationsViewModel:LocationsViewModel
......
...@@ -91,7 +91,7 @@ private struct SectionItem { ...@@ -91,7 +91,7 @@ private struct SectionItem {
let rows:[MenuRow] let rows:[MenuRow]
} }
class MenuCellFactory<T>: CellFactoryProtocol { class MenuCellFactory<T>: CellFactory {
//Private //Private
private let menuViewModel:MenuViewModel private let menuViewModel:MenuViewModel
private let sections:[SectionItem] = [SectionItem(type: .info, rows: [.settings]), private let sections:[SectionItem] = [SectionItem(type: .info, rows: [.settings]),
......
...@@ -72,8 +72,13 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection { ...@@ -72,8 +72,13 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection {
let rows: [NWSAlertCellType] = [.extendedInfoBlock] let rows: [NWSAlertCellType] = [.extendedInfoBlock]
} }
class NWSAlertCellFactory: CellFactoryProtocol { class NWSAlertCellFactory: CellFactory {
var alert: NWSAlert { fileprivate var sections: [NWSAlertTableViewSection]
private var adViewCache = [IndexPath: AdView]()
public var delegate: CellFactoryDelegate?
public var alert: NWSAlert {
didSet { didSet {
for i in 0..<sections.count { for i in 0..<sections.count {
sections[i].update(with: alert) sections[i].update(with: alert)
...@@ -81,19 +86,28 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -81,19 +86,28 @@ class NWSAlertCellFactory: CellFactoryProtocol {
} }
} }
init(alert: NWSAlert) { public init(alert: NWSAlert) {
self.alert = alert self.alert = alert
self.sections = [HeaderSection(alert: alert), ExtendedInfoSection(alert: alert)] self.sections = [HeaderSection(alert: alert), ExtendedInfoSection(alert: alert)]
} }
fileprivate var sections: [NWSAlertTableViewSection] public func height(for indexPath: IndexPath) -> CGFloat {
private var adViewCache = [IndexPath: AdView]() let cellType = cellType(at: indexPath)
switch cellType {
case .adBanner: fallthrough
case .adMREC:
let adView = adView(for: indexPath)
return adView.adReady ? UITableView.automaticDimension : 0
default:
return UITableView.automaticDimension
}
}
var numberOfSections: Int { public var numberOfSections: Int {
return sections.count return sections.count
} }
func numberOfRows(inSection section: Int) -> Int { public func numberOfRows(inSection section: Int) -> Int {
sections[section].numberOfRows sections[section].numberOfRows
} }
...@@ -102,6 +116,7 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -102,6 +116,7 @@ class NWSAlertCellFactory: CellFactoryProtocol {
return adView return adView
} }
let adView = adViewCache[indexPath] ?? AdView() let adView = adViewCache[indexPath] ?? AdView()
adView.delegate = self
adView.loggingAlias = "⚠️ Alert Banner" adView.loggingAlias = "⚠️ Alert Banner"
adView.set(placementName: placementNameNWSAlertBanner, adType: .banner) adView.set(placementName: placementNameNWSAlertBanner, adType: .banner)
adViewCache[indexPath] = adView adViewCache[indexPath] = adView
...@@ -116,9 +131,14 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -116,9 +131,14 @@ class NWSAlertCellFactory: CellFactoryProtocol {
registerCell(type: MRECAdCell.self, tableView: tableView) registerCell(type: MRECAdCell.self, tableView: tableView)
} }
func cellFromTableView(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell { private func cellType(at indexPath: IndexPath) -> NWSAlertCellType {
let section = sections[indexPath.section] let section = sections[indexPath.section]
let type = section.type(forRow: indexPath.row) let type = section.type(forRow: indexPath.row)
return type
}
public func cellFromTableView(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
let type = cellType(at: indexPath)
switch type { switch type {
case .header: case .header:
let alertCell = dequeueReusableCell(type: NWSAlertCell.self, tableView: tableView, indexPath: indexPath) let alertCell = dequeueReusableCell(type: NWSAlertCell.self, tableView: tableView, indexPath: indexPath)
...@@ -165,3 +185,22 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -165,3 +185,22 @@ class NWSAlertCellFactory: CellFactoryProtocol {
} }
} }
} }
// MARK: - AdViewDelegate
extension NWSAlertCellFactory: AdViewDelegate {
func succeeded(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
func failed(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
}
...@@ -109,7 +109,7 @@ extension NWSAlertViewController: UITableViewDelegate, UITableViewDataSource { ...@@ -109,7 +109,7 @@ extension NWSAlertViewController: UITableViewDelegate, UITableViewDataSource {
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
UITableView.automaticDimension return viewModel.cellFactory.height(for: indexPath)
} }
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
......
...@@ -18,7 +18,7 @@ private struct LayerSection { ...@@ -18,7 +18,7 @@ private struct LayerSection {
let rowsCount:Int let rowsCount:Int
} }
class RadarLayersCellFactory: CellFactoryProtocol { class RadarLayersCellFactory: CellFactory {
//Private //Private
private let radarViewModel:RadarViewModel private let radarViewModel:RadarViewModel
private let sections:[LayerSection] private let sections:[LayerSection]
......
...@@ -84,7 +84,7 @@ private struct SettingsDataSource { ...@@ -84,7 +84,7 @@ private struct SettingsDataSource {
let rows:[SettingsRow] let rows:[SettingsRow]
} }
class SettingsCellFactory: CellFactoryProtocol { class SettingsCellFactory: CellFactory {
//Private //Private
private let viewModel: SettingsViewModel private let viewModel: SettingsViewModel
private let sections: [SettingsDataSource] = { private let sections: [SettingsDataSource] = {
......
...@@ -9,7 +9,7 @@ import UIKit ...@@ -9,7 +9,7 @@ import UIKit
import Localize_Swift import Localize_Swift
import OneWeatherCore import OneWeatherCore
class SettingsDetailsCellFactory: CellFactoryProtocol { class SettingsDetailsCellFactory: CellFactory {
//Private //Private
private let viewModel:SettingsDetailsViewModel private let viewModel:SettingsDetailsViewModel
......
...@@ -50,7 +50,7 @@ private struct TodaySection { ...@@ -50,7 +50,7 @@ private struct TodaySection {
} }
} }
class TodayCellFactory: CellFactoryProtocol { class TodayCellFactory: CellFactory {
//Private //Private
private var cellsToUpdate:CellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime] private var cellsToUpdate:CellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
private let todayViewModel:TodayViewModel private let todayViewModel:TodayViewModel
...@@ -62,6 +62,7 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -62,6 +62,7 @@ class TodayCellFactory: CellFactoryProtocol {
private var adViewCache = [IndexPath: AdView]() private var adViewCache = [IndexPath: AdView]()
//Public //Public
public var delegate: CellFactoryDelegate?
init(viewModel: TodayViewModel) { init(viewModel: TodayViewModel) {
self.todayViewModel = viewModel self.todayViewModel = viewModel
} }
...@@ -93,6 +94,7 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -93,6 +94,7 @@ class TodayCellFactory: CellFactoryProtocol {
return adView return adView
} }
let adView = AdView() let adView = AdView()
adView.delegate = self
adView.loggingAlias = "📍 Today Banner" adView.loggingAlias = "📍 Today Banner"
var adType = AdType.banner var adType = AdType.banner
if cellType(at: indexPath) == .adMREC { if cellType(at: indexPath) == .adMREC {
...@@ -172,6 +174,18 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -172,6 +174,18 @@ class TodayCellFactory: CellFactoryProtocol {
} }
} }
public func height(for indexPath: IndexPath) -> CGFloat {
let cellType = cellType(at: indexPath)
switch cellType {
case .adBanner: fallthrough
case .adMREC:
let adView = adView(for: indexPath)
return adView.adReady ? UITableView.automaticDimension : 0
default:
return UITableView.automaticDimension
}
}
public func setNeedsUpdate() { public func setNeedsUpdate() {
cellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime] cellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
setupHiddenRows() setupHiddenRows()
...@@ -223,3 +237,22 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -223,3 +237,22 @@ class TodayCellFactory: CellFactoryProtocol {
todaySection.hiddenRows = rowsToHide todaySection.hiddenRows = rowsToHide
} }
} }
// MARK: - AdViewDelegate
extension TodayCellFactory: AdViewDelegate {
func succeeded(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
func failed(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
}
...@@ -106,7 +106,6 @@ private extension TodayViewController { ...@@ -106,7 +106,6 @@ private extension TodayViewController {
tableView.separatorStyle = .none tableView.separatorStyle = .none
tableView.tableFooterView = UIView() tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
tableView.delegate = self tableView.delegate = self
tableView.dataSource = self tableView.dataSource = self
view.addSubview(tableView) view.addSubview(tableView)
...@@ -126,6 +125,10 @@ extension TodayViewController: UITableViewDataSource { ...@@ -126,6 +125,10 @@ extension TodayViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return viewModel.todayCellFactory.cellFromTableView(tableView: tableView, indexPath: indexPath) return viewModel.todayCellFactory.cellFromTableView(tableView: tableView, indexPath: indexPath)
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return viewModel.todayCellFactory.height(for: indexPath)
}
} }
//MARK:- UITableView Delegate //MARK:- UITableView Delegate
......
...@@ -25,6 +25,7 @@ class NWSAlertViewModel: ViewModelProtocol { ...@@ -25,6 +25,7 @@ class NWSAlertViewModel: ViewModelProtocol {
cellFactory = NWSAlertCellFactory(alert: alert) cellFactory = NWSAlertCellFactory(alert: alert)
alertsManager.delegates.add(delegate: self) alertsManager.delegates.add(delegate: self)
NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil)
cellFactory.delegate = self
} }
@objc @objc
...@@ -35,6 +36,7 @@ class NWSAlertViewModel: ViewModelProtocol { ...@@ -35,6 +36,7 @@ class NWSAlertViewModel: ViewModelProtocol {
} }
} }
//MARK: - NWSAlertsManagerDelegate
extension NWSAlertViewModel: NWSAlertsManagerDelegate { extension NWSAlertViewModel: NWSAlertsManagerDelegate {
func alertsListDidChange(in alertsManager: NWSAlertsManager) { func alertsListDidChange(in alertsManager: NWSAlertsManager) {
// do nothing // do nothing
...@@ -48,3 +50,10 @@ extension NWSAlertViewModel: NWSAlertsManagerDelegate { ...@@ -48,3 +50,10 @@ extension NWSAlertViewModel: NWSAlertsManagerDelegate {
} }
} }
} }
extension NWSAlertViewModel: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
delegate?.viewModelDidChange(model: self)
}
}
...@@ -23,7 +23,9 @@ class TodayViewModel: ViewModelProtocol { ...@@ -23,7 +23,9 @@ class TodayViewModel: ViewModelProtocol {
private(set) var location:Location? private(set) var location:Location?
public lazy var todayCellFactory:TodayCellFactory = { public lazy var todayCellFactory:TodayCellFactory = {
TodayCellFactory(viewModel: self) let factory = TodayCellFactory(viewModel: self)
factory.delegate = self
return factory
}() }()
deinit { deinit {
...@@ -129,3 +131,10 @@ extension TodayViewModel: SettingsDelegate { ...@@ -129,3 +131,10 @@ extension TodayViewModel: SettingsDelegate {
delegate?.viewModelDidChange(model: self) delegate?.viewModelDidChange(model: self)
} }
} }
// MARK: CellFactoryDelegate
extension TodayViewModel: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
delegate?.viewModelDidChange(model: self)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment