Commit fe6329ff by Demid Merzlyakov

IOS-155: move from a legacy isAppPro() to StoreManager to check in-app.

Use shared (group) UserDefaults to store in-app status. Use new UserDefaults key to save in-app info.
Convert existing isAppPro code to storeManager / featureAvailability controlled code.
parent 3e305001
...@@ -21,7 +21,15 @@ public class StoreManager { ...@@ -21,7 +21,15 @@ public class StoreManager {
// MARK: - Get known status // MARK: - Get known status
@UserDefaultsValue("com.inmobi.oneweather.WeatherKey", defaultValue: false, userDefaults: UserDefaults.appDefaults) @UserDefaultsValue("com.inmobi.oneweather.WeatherKey", defaultValue: false, userDefaults: UserDefaults.appDefaults)
public var removeAdsPurchased: Bool public var removeAdsPurchased: Bool {
didSet {
if removeAdsPurchased {
subscribers.invoke { subscriber in
subscriber.storeManagerUpdatedStatus(self)
}
}
}
}
public var hasSubscription: Bool { public var hasSubscription: Bool {
#warning("Not implemented!") #warning("Not implemented!")
......
...@@ -28,7 +28,8 @@ private enum ForecastCellType { ...@@ -28,7 +28,8 @@ private enum ForecastCellType {
private struct HourlySection { private struct HourlySection {
let rows: [ForecastCellType] = { let rows: [ForecastCellType] = {
let showAds = !isAppPro() && AdConfigManager.shared.adConfig.adsEnabled // TODO: use dependency injection instead of a singleton
let showAds = FeatureAvailabilityManager.shared.isAvailable(feature: .ads)
//TODO: dependency injection //TODO: dependency injection
if FeatureAvailabilityManager.shared.isAvailable(feature: .ads) { if FeatureAvailabilityManager.shared.isAvailable(feature: .ads) {
return [.day, .forecastHourly, .adBanner, .precipitation, .wind, .adMREC] return [.day, .forecastHourly, .adBanner, .precipitation, .wind, .adMREC]
...@@ -57,7 +58,7 @@ class ForecastCellFactory: CellFactory { ...@@ -57,7 +58,7 @@ class ForecastCellFactory: CellFactory {
private let dailySection = DailySection() private let dailySection = DailySection()
private let hourlySection = HourlySection() private let hourlySection = HourlySection()
private var cellsToUpdate: Set<ForecastCellType> = [.forecastDaily, .forecastHourly, .forecastDailyInfo, .precipitation, .wind] private var cellsToUpdate: Set<ForecastCellType> = [.forecastDaily, .forecastHourly, .forecastDailyInfo, .precipitation, .wind]
private let forecastViewModel:ForecastViewModel private let forecastViewModel: ForecastViewModel
private var adViewCache = [TimePeriod: [IndexPath: AdView]]() private var adViewCache = [TimePeriod: [IndexPath: AdView]]()
//Public //Public
......
...@@ -157,7 +157,7 @@ extension MenuViewController: UITableViewDelegate { ...@@ -157,7 +157,7 @@ extension MenuViewController: UITableViewDelegate {
extension MenuViewController: MenuViewModelDelegate { extension MenuViewController: MenuViewModelDelegate {
func viewModelDidChange<P: ViewModelProtocol>(model:P) { func viewModelDidChange<P: ViewModelProtocol>(model:P) {
onMain { onMain {
if isAppPro() { if self.viewModel.storeManager.hasSubscription || !self.viewModel.featureAvailabilityManager.isAvailable(feature: .subscription) {
self.tableView.tableHeaderView = nil self.tableView.tableHeaderView = nil
} }
self.tableView.reloadData() self.tableView.reloadData()
......
...@@ -22,8 +22,15 @@ class MenuViewModel: NSObject, ViewModelProtocol { ...@@ -22,8 +22,15 @@ class MenuViewModel: NSObject, ViewModelProtocol {
private var proVersionPurchaseInProgress = false private var proVersionPurchaseInProgress = false
private let log = Logger(componentName: "MenuViewModel") private let log = Logger(componentName: "MenuViewModel")
private var upgradeAlert: UIAlertController? private var upgradeAlert: UIAlertController?
public let storeManager: StoreManager
public weak var delegate: MenuViewModelDelegate? public weak var delegate: MenuViewModelDelegate?
public init(storeManager: StoreManager = StoreManager.shared) {
self.storeManager = storeManager
super.init()
self.storeManager.add(subscriber: self)
}
public func showAlert(_ title: String?, message: String?) -> Void { public func showAlert(_ title: String?, message: String?) -> Void {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
...@@ -96,29 +103,11 @@ class MenuViewModel: NSObject, ViewModelProtocol { ...@@ -96,29 +103,11 @@ class MenuViewModel: NSObject, ViewModelProtocol {
self.delegate?.viewControllerForPresentation().present(alert, animated: true) self.delegate?.viewControllerForPresentation().present(alert, animated: true)
} }
private let kOLAppMetricsCountKey: String = "count" private let kOLAppMetricsCountKey: String = "count"
private let kOLAppMetricsDateKey: String = "date" private let kOLAppMetricsDateKey: String = "date"
private func logEventToUserDefaults(forKey eventKey: String) {
let userDefaults = UserDefaults.standard
var updatedCount: Int = 1
var metricsLog = userDefaults.dictionary(forKey: kOLAppMetricsKey) ?? [String : Any]()
if let countEvent = metricsLog[eventKey] as? [String : Any], let count = countEvent[kOLAppMetricsCountKey] as? Int {
updatedCount = count + 1
}
let updateEvent = [kOLAppMetricsCountKey: updatedCount, kOLAppMetricsDateKey: Date()] as [String : Any]
metricsLog[eventKey] = updateEvent
userDefaults.set(metricsLog, forKey: kOLAppMetricsKey)
}
private func updateToProCompleted() { private func updateToProCompleted() {
logEventToUserDefaults(forKey: kEventInAppPurchasedCompleted) storeManager.removeAdsPurchased = true
NotificationCenter.default.post(name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil)
analytics(log: .ANALYTICS_GO_PRO) analytics(log: .ANALYTICS_GO_PRO)
delegate?.viewModelDidChange(model: self) delegate?.viewModelDidChange(model: self)
} }
...@@ -126,7 +115,7 @@ class MenuViewModel: NSObject, ViewModelProtocol { ...@@ -126,7 +115,7 @@ class MenuViewModel: NSObject, ViewModelProtocol {
// MARK: - Help section // MARK: - Help section
extension MenuViewModel { extension MenuViewModel {
private var featureAvailabilityManager: FeatureAvailabilityManager { public var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared FeatureAvailabilityManager.shared
} }
...@@ -175,7 +164,7 @@ extension MenuViewModel { ...@@ -175,7 +164,7 @@ extension MenuViewModel {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")! let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")!
let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")! let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")!
let systemVersion = UIDevice.current.systemVersion let systemVersion = UIDevice.current.systemVersion
let isPro = isAppPro() ? "Yes" : "No" let isPro = storeManager.removeAdsPurchased ? "Yes" : "No"
let installedDate = "Unknown" let installedDate = "Unknown"
let deviceInfo = "Version: \(version)-\(build)\nDevice: \(deviceName)\nOS: \(systemVersion)\nPro: \(isPro) \nInstalled: \(installedDate) \(deviceToken)" let deviceInfo = "Version: \(version)-\(build)\nDevice: \(deviceName)\nOS: \(systemVersion)\nPro: \(isPro) \nInstalled: \(installedDate) \(deviceToken)"
...@@ -292,3 +281,11 @@ extension MenuViewModel: OLInAppStoreManagerUIDelegate { ...@@ -292,3 +281,11 @@ extension MenuViewModel: OLInAppStoreManagerUIDelegate {
return delegate.viewControllerForPresentation() return delegate.viewControllerForPresentation()
} }
} }
extension MenuViewModel: StoreManagerSubscriber {
func storeManagerUpdatedStatus(_ storeManager: StoreManager) {
onMain {
self.delegate?.viewModelDidChange(model: self)
}
}
}
...@@ -13,18 +13,25 @@ class NWSAlertViewModel: ViewModelProtocol { ...@@ -13,18 +13,25 @@ class NWSAlertViewModel: ViewModelProtocol {
public private(set) var alert: NWSAlert public private(set) var alert: NWSAlert
private let alertsManager: NWSAlertsManager private let alertsManager: NWSAlertsManager
public var cellFactory: NWSAlertCellFactory public var cellFactory: NWSAlertCellFactory
private let featureAvailabilityManager: FeatureAvailabilityManager
private let storeManager: StoreManager
deinit { deinit {
alertsManager.delegates.remove(delegate: self) alertsManager.delegates.remove(delegate: self)
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
} }
public init(alert: NWSAlert, alertsManager: NWSAlertsManager = LocationManager.shared.nwsAlertsManager) { public init(alert: NWSAlert,
alertsManager: NWSAlertsManager = LocationManager.shared.nwsAlertsManager,
featureAvailabilityManager: FeatureAvailabilityManager = FeatureAvailabilityManager.shared,
storeManager: StoreManager = StoreManager.shared) {
self.alert = alert self.alert = alert
self.alertsManager = alertsManager self.alertsManager = alertsManager
cellFactory = NWSAlertCellFactory(alert: alert) cellFactory = NWSAlertCellFactory(alert: alert)
self.featureAvailabilityManager = featureAvailabilityManager
self.storeManager = storeManager
alertsManager.delegates.add(delegate: self) alertsManager.delegates.add(delegate: self)
NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil) self.storeManager.add(subscriber: self)
cellFactory.delegate = self cellFactory.delegate = self
} }
...@@ -57,3 +64,9 @@ extension NWSAlertViewModel: CellFactoryDelegate { ...@@ -57,3 +64,9 @@ extension NWSAlertViewModel: CellFactoryDelegate {
} }
} }
extension NWSAlertViewModel: StoreManagerSubscriber {
func storeManagerUpdatedStatus(_ storeManager: StoreManager) {
handlePremiumStateChange()
}
}
...@@ -23,6 +23,7 @@ class TodayViewModel: ViewModelProtocol { ...@@ -23,6 +23,7 @@ class TodayViewModel: ViewModelProtocol {
//Private //Private
private let locationManager: LocationManager private let locationManager: LocationManager
private let configManager: ConfigManager private let configManager: ConfigManager
private let storeManager: StoreManager
private let kAnalyticsThresholdSec = 2.5 private let kAnalyticsThresholdSec = 2.5
private let log = Logger(componentName: "TodayViewModel") private let log = Logger(componentName: "TodayViewModel")
private var ccpaHelper = CCPAHelper.shared private var ccpaHelper = CCPAHelper.shared
...@@ -51,15 +52,16 @@ class TodayViewModel: ViewModelProtocol { ...@@ -51,15 +52,16 @@ class TodayViewModel: ViewModelProtocol {
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
} }
public init(locationManager: LocationManager = LocationManager.shared, configManager: ConfigManager = ConfigManager.shared, shortsManager: ShortsManager = ShortsManager.shared) { public init(locationManager: LocationManager = LocationManager.shared, configManager: ConfigManager = ConfigManager.shared, shortsManager: ShortsManager = ShortsManager.shared, storeManager: StoreManager = StoreManager.shared) {
self.locationManager = locationManager self.locationManager = locationManager
self.configManager = configManager self.configManager = configManager
self.shortsManager = shortsManager self.shortsManager = shortsManager
self.storeManager = storeManager
self.storeManager.add(subscriber: self)
self.shortsManager.multicastDelegate.add(delegate: self) self.shortsManager.multicastDelegate.add(delegate: self)
self.location = locationManager.selectedLocation self.location = locationManager.selectedLocation
locationManager.add(delegate: self) locationManager.add(delegate: self)
Settings.shared.delegate.add(delegate: self) Settings.shared.delegate.add(delegate: self)
NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil)
} }
//MARK: Private //MARK: Private
...@@ -77,7 +79,7 @@ class TodayViewModel: ViewModelProtocol { ...@@ -77,7 +79,7 @@ class TodayViewModel: ViewModelProtocol {
guard !adManager.initialized else { return } guard !adManager.initialized else { return }
self.ccpaHelper.updateCCPAStatus(reason: "initialization") self.ccpaHelper.updateCCPAStatus(reason: "initialization")
if !isAppPro() { if self.featureAvailabilityManager.isAvailable(feature: .ads) {
// In Debug mode we allow the user to change the environment // In Debug mode we allow the user to change the environment
//TODO AdStack: add MoPub App Key //TODO AdStack: add MoPub App Key
...@@ -195,6 +197,12 @@ extension TodayViewModel: LocationManagerDelegate { ...@@ -195,6 +197,12 @@ extension TodayViewModel: LocationManagerDelegate {
} }
} }
extension TodayViewModel: StoreManagerSubscriber {
func storeManagerUpdatedStatus(_ storeManager: StoreManager) {
handlePremiumStateChange()
}
}
//MARK:- Settings Delegate //MARK:- Settings Delegate
extension TodayViewModel: SettingsDelegate { extension TodayViewModel: SettingsDelegate {
func settingsDidChange() { func settingsDidChange() {
......
...@@ -9,11 +9,9 @@ import Foundation ...@@ -9,11 +9,9 @@ import Foundation
public let kMoEngageAppId = "11PSBEC6K93IYU1AC8WIYADY" public let kMoEngageAppId = "11PSBEC6K93IYU1AC8WIYADY"
public let kEventInAppPurchasedCompleted = "EventInAppPurchasedCompleted"
public let a9AppKey = "2e440b094f7c44b4bae7044b764c61ac" public let a9AppKey = "2e440b094f7c44b4bae7044b764c61ac"
public let kAdMoPubInitializationAdUnitId = "05bff78d4a4245bd98ff6b595c134889" public let kAdMoPubInitializationAdUnitId = "05bff78d4a4245bd98ff6b595c134889"
public let kFlurryPartnerId = "2HJTQGPKT6VHXYRHFQTD" public let kFlurryPartnerId = "2HJTQGPKT6VHXYRHFQTD"
public let kOLAppMetricsKey: String = "OLAppMetricsKey"
public let WDT_APP_ID = "e3b73414" public let WDT_APP_ID = "e3b73414"
public let WDT_APP_KEY = "25e8d6b72de3bcd528f7769b073cc335" public let WDT_APP_KEY = "25e8d6b72de3bcd528f7769b073cc335"
......
...@@ -21,14 +21,6 @@ let BLANK = "--" ...@@ -21,14 +21,6 @@ let BLANK = "--"
let UP_ARROW = "\u{2191}" let UP_ARROW = "\u{2191}"
let DOWN_ARROW = "\u{2193}" let DOWN_ARROW = "\u{2193}"
// isPro
public func isAppPro() -> Bool {
if let metricsLog = UserDefaults.standard.dictionary(forKey: kOLAppMetricsKey) {
return metricsLog[kEventInAppPurchasedCompleted] != nil
}
return false
}
func windUnits() -> WindUnits { func windUnits() -> WindUnits {
return .mps return .mps
} }
......
...@@ -20,6 +20,33 @@ extension UserDefaults { ...@@ -20,6 +20,33 @@ extension UserDefaults {
return UserDefaults.standard return UserDefaults.standard
} }
private static func migrateInAppPurchaseMarker() {
// User Defaults - Old
let userDefaults = UserDefaults.standard
// App Groups Default - New
let groupDefaults = UserDefaults.appDefaults
let legacyAppMetricsKey = "OLAppMetricsKey"
let legacyInAppPurchaseEventKey = "EventInAppPurchasedCompleted"
let newInAppPurchaseMarkerKey = "com.inmobi.oneweather.WeatherKey" // we want something inconspicuous just so that it wasn't that obvious if anybody has a look at UserDefaults
var hasInAppPurchase = false
for userDefaults in [groupDefaults, userDefaults] {
if let appMetrics = userDefaults.dictionary(forKey: legacyAppMetricsKey) {
if appMetrics[legacyInAppPurchaseEventKey] != nil {
hasInAppPurchase = true
break
}
}
}
if hasInAppPurchase {
groupDefaults.set(true, forKey: newInAppPurchaseMarkerKey)
}
}
public static func migrateUserDefaultsToAppGroupsIfNeeded() { public static func migrateUserDefaultsToAppGroupsIfNeeded() {
// User Defaults - Old // User Defaults - Old
let userDefaults = UserDefaults.standard let userDefaults = UserDefaults.standard
...@@ -41,5 +68,8 @@ extension UserDefaults { ...@@ -41,5 +68,8 @@ extension UserDefaults {
} else { } else {
log.info("No need to migrate defaults") log.info("No need to migrate defaults")
} }
// Migrate in app purchase marker separately, because it was added later.
migrateInAppPurchaseMarker()
} }
} }
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