Commit 0d5742e2 by Demid Merzlyakov

IOS-176: feature availability control: move most part of the stuff to the new control.

parent f916bb10
...@@ -76,6 +76,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -76,6 +76,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
FirebaseApp.configure() FirebaseApp.configure()
ConfigManager.shared.updateConfig() ConfigManager.shared.updateConfig()
FeatureAvailabilityManager.shared = configureFeatureAvailabilityManager(with: LocationManager.shared, configManager: ConfigManager.shared)
//App UI //App UI
let appCoordinator = AppCoordinator(window: self.window!, launchOptions: launchOptions) let appCoordinator = AppCoordinator(window: self.window!, launchOptions: launchOptions)
appCoordinator.start() appCoordinator.start()
...@@ -179,6 +181,46 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -179,6 +181,46 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
} }
} }
} }
private func configureFeatureAvailabilityManager(with locationManager: LocationManager, configManager: ConfigManager) -> FeatureAvailabilityManager {
let usOnly = USOnlyFeatureAvailabilityChecker { [weak locationManager] in
return locationManager?.selectedLocation
}
let premium = PremiumInAppFeatureAvailabilityChecker()
let proSubscription = ProSubscriptionAvailabilityChecker()
let isPhone = DeviceTypeFeatureAvailabilityChecker(deviceType: .phone)
var availabilityCheckers = [AppFeature: FeatureAvailabilityChecker]()
for feature in AppFeature.allCases {
// To make sure all features are explicitly configured.
switch feature {
case .ads:
availabilityCheckers[feature] = !premium && !proSubscription
case .minutelyForecast:
availabilityCheckers[feature] = proSubscription
case .shorts:
availabilityCheckers[feature] = usOnly && isPhone
case .airQualityIndex:
break
case .attPrompt:
break // config only
case .nwsAlertsViaMoEngage:
break // config only
case .onboarding:
break // config only
case .shortsLastNudge:
break // config only
}
}
let manager = FeatureAvailabilityManager(configFetcher: { [weak configManager] in
configManager?.config
},
checkers: availabilityCheckers)
return manager
}
} }
extension AppDelegate: AppsFlyerLibDelegate { extension AppDelegate: AppsFlyerLibDelegate {
......
...@@ -26,6 +26,9 @@ class AppCoordinator: Coordinator { ...@@ -26,6 +26,9 @@ class AppCoordinator: Coordinator {
var parentCoordinator: Coordinator? var parentCoordinator: Coordinator?
var childCoordinators = [Coordinator]() var childCoordinators = [Coordinator]()
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
init(window:UIWindow, launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { init(window:UIWindow, launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
self.window = window self.window = window
...@@ -109,7 +112,7 @@ class AppCoordinator: Coordinator { ...@@ -109,7 +112,7 @@ class AppCoordinator: Coordinator {
DispatchQueue.main.async { DispatchQueue.main.async {
self.logAppLaunchEvents() self.logAppLaunchEvents()
if ConfigManager.shared.config.showOnboarding { if self.featureAvailabilityManager.isAvailable(feature: .onboarding) {
if Settings.shared.initialOnboardingShowed { if Settings.shared.initialOnboardingShowed {
self.finishInitialOnboarding() self.finishInitialOnboarding()
} }
...@@ -158,7 +161,7 @@ class AppCoordinator: Coordinator { ...@@ -158,7 +161,7 @@ class AppCoordinator: Coordinator {
firstOpenSource = .url firstOpenSource = .url
} }
let flow = ConfigManager.shared.config.showOnboarding ? "FTUX" : "default" let flow = featureAvailabilityManager.isAvailable(feature: .onboarding) ? "FTUX" : "default"
analytics(log: .ANALYTICS_FIRST_OPEN, analytics(log: .ANALYTICS_FIRST_OPEN,
params: [.ANALYTICS_KEY_FIRST_OPEN_SOURCE : firstOpenSource.rawValue, params: [.ANALYTICS_KEY_FIRST_OPEN_SOURCE : firstOpenSource.rawValue,
.ANALYTICS_KEY_FIRST_OPEN_FLOW : flow]) .ANALYTICS_KEY_FIRST_OPEN_FLOW : flow])
......
...@@ -20,12 +20,8 @@ public class ConfigManager { ...@@ -20,12 +20,8 @@ public class ConfigManager {
private static let adConfigKey = "ads_config_ios" private static let adConfigKey = "ads_config_ios"
private static let popularCitiesConfigKey = "search_screen_popular_cities" private static let popularCitiesConfigKey = "search_screen_popular_cities"
private static let ccpaUpdateIntervalConfigKey = "ccpa_update_interval_ios" private static let ccpaUpdateIntervalConfigKey = "ccpa_update_interval_ios"
private static let nwsAlertsViaMoEngageEnabledKey = "ios_nws_alerts_via_moengage_enabled"
private static let showAttPromptKey = "ios_show_att_prompt"
private static let shortsLeftBelowCountKey = "shorts_left_below_nudge_every_x_cards" private static let shortsLeftBelowCountKey = "shorts_left_below_nudge_every_x_cards"
private static let shortsLastNudgeEnabledKey = "shorts_swipe_down_nudge_enabled"
private static let shortsSwipeUpNudgeCountKey = "shorts_swipe_up_nudge_on_x_cards" private static let shortsSwipeUpNudgeCountKey = "shorts_swipe_up_nudge_on_x_cards"
private static let showOnboardingKey = "ios_show_onboarding"
private let delegates = MulticastDelegate<ConfigManagerDelegate>() private let delegates = MulticastDelegate<ConfigManagerDelegate>()
...@@ -44,12 +40,15 @@ public class ConfigManager { ...@@ -44,12 +40,15 @@ public class ConfigManager {
public var config: AppConfig = AppConfig(popularCities: nil, public var config: AppConfig = AppConfig(popularCities: nil,
adConfig: AdConfig(), adConfig: AdConfig(),
ccpaUpdateInterval: nil, ccpaUpdateInterval: nil,
nwsAlertsViaMoEngageEnabled: true,
showAttPrompt: false,
shortsLeftBelowCountKey: 0, shortsLeftBelowCountKey: 0,
shortsLastNudgeEnabledKey: false,
shortsSwipeUpNudgeCountKey: 0, shortsSwipeUpNudgeCountKey: 0,
showOnboarding: false) explicitFeatureAvailability: [
.nwsAlertsViaMoEngage: true,
.attPrompt: false,
.shortsLastNudge: false,
.onboarding: false
]
)
public func updateConfig() { public func updateConfig() {
log.info("update config") log.info("update config")
...@@ -87,11 +86,23 @@ public class ConfigManager { ...@@ -87,11 +86,23 @@ public class ConfigManager {
delegates.remove(delegate: delegate) delegates.remove(delegate: delegate)
} }
private func parseFeatureAvailability() -> [AppFeature: Bool] {
var featureAvailability = [AppFeature: Bool]()
for feature in AppFeature.allCases {
if let configName = feature.configVariableName {
let configValue = remoteConfig.configValue(forKey: configName)
featureAvailability[feature] = configValue.boolValue
}
}
return featureAvailability
}
private func parseConfigFromFirebase(source: String) { private func parseConfigFromFirebase(source: String) {
log.info("Got config from \(source)") log.info("Got config from \(source)")
var configErrors = [Error]() var configErrors = [Error]()
let decoder = JSONDecoder() let decoder = JSONDecoder()
var adConfig = AdConfig() var adConfig = AdConfig()
do { do {
let adConfigData = remoteConfig.configValue(forKey: ConfigManager.adConfigKey).dataValue let adConfigData = remoteConfig.configValue(forKey: ConfigManager.adConfigKey).dataValue
...@@ -123,34 +134,22 @@ public class ConfigManager { ...@@ -123,34 +134,22 @@ public class ConfigManager {
if ccpaUpdateIntervalConfigValue.source == RemoteConfigSource.remote { if ccpaUpdateIntervalConfigValue.source == RemoteConfigSource.remote {
ccpaUpdateInterval = ccpaUpdateIntervalConfigValue.numberValue.doubleValue ccpaUpdateInterval = ccpaUpdateIntervalConfigValue.numberValue.doubleValue
} }
let nwsAlertsViaMoEngageEnabledValue = remoteConfig.configValue(forKey: ConfigManager.nwsAlertsViaMoEngageEnabledKey)
let nwsAlertsViaMoEngageEnabled = nwsAlertsViaMoEngageEnabledValue.boolValue
let showAttPromptValue = remoteConfig.configValue(forKey: ConfigManager.showAttPromptKey)
let showAttPrompt = showAttPromptValue.boolValue
let shortsLeftBelowCountValue = remoteConfig.configValue(forKey: ConfigManager.shortsLeftBelowCountKey) let shortsLeftBelowCountValue = remoteConfig.configValue(forKey: ConfigManager.shortsLeftBelowCountKey)
let shortsLeftBelowCount = shortsLeftBelowCountValue.numberValue.intValue let shortsLeftBelowCount = shortsLeftBelowCountValue.numberValue.intValue
let shortsLastNudgeEnabledValue = remoteConfig.configValue(forKey: ConfigManager.shortsLastNudgeEnabledKey)
let shortsLastNudgeEnabled = shortsLastNudgeEnabledValue.boolValue
let shortsSwipeNudgeCountValue = remoteConfig.configValue(forKey: ConfigManager.shortsSwipeUpNudgeCountKey) let shortsSwipeNudgeCountValue = remoteConfig.configValue(forKey: ConfigManager.shortsSwipeUpNudgeCountKey)
let shortsSwipeNudgeCount = shortsSwipeNudgeCountValue.numberValue.intValue let shortsSwipeNudgeCount = shortsSwipeNudgeCountValue.numberValue.intValue
let showOnboardingValue = remoteConfig.configValue(forKey: ConfigManager.showOnboardingKey) let featureAvailability = parseFeatureAvailability()
let showOnboarding = showOnboardingValue.boolValue
DispatchQueue.main.async { DispatchQueue.main.async {
self.config = AppConfig(popularCities: popularCities, self.config = AppConfig(popularCities: popularCities,
adConfig: adConfig, adConfig: adConfig,
ccpaUpdateInterval:ccpaUpdateInterval, ccpaUpdateInterval:ccpaUpdateInterval,
nwsAlertsViaMoEngageEnabled: nwsAlertsViaMoEngageEnabled,
showAttPrompt: showAttPrompt,
shortsLeftBelowCountKey: shortsLeftBelowCount, shortsLeftBelowCountKey: shortsLeftBelowCount,
shortsLastNudgeEnabledKey: shortsLastNudgeEnabled,
shortsSwipeUpNudgeCountKey: shortsSwipeNudgeCount, shortsSwipeUpNudgeCountKey: shortsSwipeNudgeCount,
showOnboarding: showOnboarding) explicitFeatureAvailability: featureAvailability
)
self.notifyAboutConfigUpdate() self.notifyAboutConfigUpdate()
DispatchQueue.global().async { DispatchQueue.global().async {
let encoder = JSONEncoder() let encoder = JSONEncoder()
...@@ -171,3 +170,21 @@ public class ConfigManager { ...@@ -171,3 +170,21 @@ public class ConfigManager {
} }
} }
} }
fileprivate extension AppFeature {
var configVariableName: String? {
switch self {
case .nwsAlertsViaMoEngage:
return "ios_nws_alerts_via_moengage_enabled"
case .attPrompt:
return "ios_show_att_prompt"
case .shortsLastNudge:
return "shorts_swipe_down_nudge_enabled"
case .onboarding:
return "ios_show_onboarding"
case .ads, .airQualityIndex, .minutelyForecast, .shorts:
return nil
// don't use 'default', so that we didn't add new features here in the future.
}
}
}
...@@ -56,8 +56,12 @@ public class PushNotificationsManager: NSObject, PushNotificationsManagerProtoco ...@@ -56,8 +56,12 @@ public class PushNotificationsManager: NSObject, PushNotificationsManagerProtoco
internal var lastSetFIPSList: String? = "" internal var lastSetFIPSList: String? = ""
internal var lastSetFIPSCode: String? = "" internal var lastSetFIPSCode: String? = ""
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
private func updateNwsSubscriptions(with fipsList: String?, currentFipsCode: String?) { private func updateNwsSubscriptions(with fipsList: String?, currentFipsCode: String?) {
if configManager.config.nwsAlertsViaMoEngageEnabled { if featureAvailabilityManager.isAvailable(feature: .nwsAlertsViaMoEngage) {
if fipsList != lastSetFIPSList { if fipsList != lastSetFIPSList {
log.info("Set \(AnalyticsAttribute.fipsList.attributeName) to '\(fipsList ?? "")'") log.info("Set \(AnalyticsAttribute.fipsList.attributeName) to '\(fipsList ?? "")'")
lastSetFIPSList = fipsList lastSetFIPSList = fipsList
......
...@@ -20,8 +20,12 @@ class ShortsManager { ...@@ -20,8 +20,12 @@ class ShortsManager {
static let shared = ShortsManager() static let shared = ShortsManager()
let multicastDelegate = MulticastDelegate<ShortsManagerDelegate>() let multicastDelegate = MulticastDelegate<ShortsManagerDelegate>()
private(set) var shorts = [ShortsItem]() private(set) var shorts = [ShortsItem]()
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
var shortsAvailable: Bool { var shortsAvailable: Bool {
return LocationManager.shared.selectedLocation?.countryCode == "US" && UIDevice.current.userInterfaceIdiom == .phone return featureAvailabilityManager.isAvailable(feature: .shorts)
} }
//Private //Private
......
...@@ -50,6 +50,10 @@ class ShortsViewController: UIViewController { ...@@ -50,6 +50,10 @@ class ShortsViewController: UIViewController {
return scheduler return scheduler
}() }()
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
deinit { deinit {
coordinator.viewControllerDidEnd(controller: self) coordinator.viewControllerDidEnd(controller: self)
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
...@@ -150,7 +154,7 @@ class ShortsViewController: UIViewController { ...@@ -150,7 +154,7 @@ class ShortsViewController: UIViewController {
} }
//Show the swipe helper view if needed //Show the swipe helper view if needed
if ConfigManager.shared.config.shortsLastNudgeEnabled { if featureAvailabilityManager.isAvailable(feature: .shortsLastNudge) {
//Check for the last row //Check for the last row
if rowIndex == viewModel.shorts.count - 1 { if rowIndex == viewModel.shorts.count - 1 {
swipeHelperView.configure(forState: .downViewedAll) swipeHelperView.configure(forState: .downViewedAll)
......
...@@ -126,9 +126,13 @@ class MenuViewModel: NSObject, ViewModelProtocol { ...@@ -126,9 +126,13 @@ class MenuViewModel: NSObject, ViewModelProtocol {
// MARK: - Help section // MARK: - Help section
extension MenuViewModel { extension MenuViewModel {
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
private func helpRequestBodyString() -> String { private func helpRequestBodyString() -> String {
var str = String() var str = String()
str.append("Weather Alerts Enabled: \(ConfigManager.shared.config.nwsAlertsViaMoEngageEnabled)\n") str.append("Weather Alerts Enabled: \(featureAvailabilityManager.isAvailable(feature: .nwsAlertsViaMoEngage))\n")
let isRegistered = UIApplication.shared.isRegisteredForRemoteNotifications let isRegistered = UIApplication.shared.isRegisteredForRemoteNotifications
str.append("Push Enabled: \(isRegistered)\n") str.append("Push Enabled: \(isRegistered)\n")
......
...@@ -35,6 +35,10 @@ class TodayViewModel: ViewModelProtocol { ...@@ -35,6 +35,10 @@ class TodayViewModel: ViewModelProtocol {
shortsManager.shorts shortsManager.shorts
} }
private var featureAvailabilityManager: FeatureAvailabilityManager {
FeatureAvailabilityManager.shared
}
public lazy var todayCellFactory:TodayCellFactory = { public lazy var todayCellFactory:TodayCellFactory = {
let factory = TodayCellFactory(viewModel: self) let factory = TodayCellFactory(viewModel: self)
factory.delegate = self factory.delegate = self
...@@ -127,7 +131,7 @@ class TodayViewModel: ViewModelProtocol { ...@@ -127,7 +131,7 @@ class TodayViewModel: ViewModelProtocol {
// not calling onboardingFlowCompleted, because it will be called in the ATT prompt completion handler. // not calling onboardingFlowCompleted, because it will be called in the ATT prompt completion handler.
return return
} }
if self.configManager.config.showAttPrompt if self.featureAvailabilityManager.isAvailable(feature: .attPrompt)
&& !self.ccpaHelper.isNewUser && !self.ccpaHelper.isNewUser
&& ATTrackingManager.trackingAuthorizationStatus == .notDetermined { && ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
CE72A76A26D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */; }; CE72A76A26D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */; };
CE72A76C26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */; }; CE72A76C26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */; };
CE72A76E26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */; }; CE72A76E26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */; };
CE72A77026D6917300F13CF7 /* DeviceTypeFeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A76F26D6917300F13CF7 /* DeviceTypeFeatureAvailabilityChecker.swift */; };
CEFE851826948C15003C67D3 /* SmartTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851726948C15003C67D3 /* SmartTextProvider.swift */; }; CEFE851826948C15003C67D3 /* SmartTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851726948C15003C67D3 /* SmartTextProvider.swift */; };
CEFE851C2694986D003C67D3 /* SmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851B2694986D003C67D3 /* SmartText.swift */; }; CEFE851C2694986D003C67D3 /* SmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851B2694986D003C67D3 /* SmartText.swift */; };
CEFE85202694C4BC003C67D3 /* DefaultSmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851F2694C4BC003C67D3 /* DefaultSmartText.swift */; }; CEFE85202694C4BC003C67D3 /* DefaultSmartText.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFE851F2694C4BC003C67D3 /* DefaultSmartText.swift */; };
...@@ -198,6 +199,7 @@ ...@@ -198,6 +199,7 @@
CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = USOnlyFeatureAvailabilityChecker.swift; sourceTree = "<group>"; }; CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = USOnlyFeatureAvailabilityChecker.swift; sourceTree = "<group>"; };
CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumInAppFeatureAvailabilityChecker.swift; sourceTree = "<group>"; }; CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumInAppFeatureAvailabilityChecker.swift; sourceTree = "<group>"; };
CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProSubscriptionAvailabilityChecker.swift; sourceTree = "<group>"; }; CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProSubscriptionAvailabilityChecker.swift; sourceTree = "<group>"; };
CE72A76F26D6917300F13CF7 /* DeviceTypeFeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTypeFeatureAvailabilityChecker.swift; sourceTree = "<group>"; };
CEFE851726948C15003C67D3 /* SmartTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextProvider.swift; sourceTree = "<group>"; }; CEFE851726948C15003C67D3 /* SmartTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextProvider.swift; sourceTree = "<group>"; };
CEFE851B2694986D003C67D3 /* SmartText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartText.swift; sourceTree = "<group>"; }; CEFE851B2694986D003C67D3 /* SmartText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartText.swift; sourceTree = "<group>"; };
CEFE851D2694C477003C67D3 /* SmartTextMacro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextMacro.swift; sourceTree = "<group>"; }; CEFE851D2694C477003C67D3 /* SmartTextMacro.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextMacro.swift; sourceTree = "<group>"; };
...@@ -500,6 +502,7 @@ ...@@ -500,6 +502,7 @@
CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */, CE72A76926D676A000F13CF7 /* USOnlyFeatureAvailabilityChecker.swift */,
CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */, CE72A76B26D6782F00F13CF7 /* PremiumInAppFeatureAvailabilityChecker.swift */,
CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */, CE72A76D26D680DF00F13CF7 /* ProSubscriptionAvailabilityChecker.swift */,
CE72A76F26D6917300F13CF7 /* DeviceTypeFeatureAvailabilityChecker.swift */,
); );
path = FeatureAvailabilityCheckers; path = FeatureAvailabilityCheckers;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -763,6 +766,7 @@ ...@@ -763,6 +766,7 @@
CDFE459426566D7B0021A29F /* HealthSource.swift in Sources */, CDFE459426566D7B0021A29F /* HealthSource.swift in Sources */,
CD615F9A265526E700B717DB /* CurrentWeather.swift in Sources */, CD615F9A265526E700B717DB /* CurrentWeather.swift in Sources */,
CD615F9B265526E700B717DB /* DailyWeather.swift in Sources */, CD615F9B265526E700B717DB /* DailyWeather.swift in Sources */,
CE72A77026D6917300F13CF7 /* DeviceTypeFeatureAvailabilityChecker.swift in Sources */,
CD615F9C265526E700B717DB /* HourlyWeather.swift in Sources */, CD615F9C265526E700B717DB /* HourlyWeather.swift in Sources */,
CD615F9D265526E700B717DB /* DayTimeWeather.swift in Sources */, CD615F9D265526E700B717DB /* DayTimeWeather.swift in Sources */,
CD615F9E265526E700B717DB /* Health.swift in Sources */, CD615F9E265526E700B717DB /* Health.swift in Sources */,
......
//
// DeviceTypeFeatureAvailabilityChecker.swift
// OneWeatherCore
//
// Created by Demid Merzlyakov on 25.08.2021.
//
import UIKit
public struct DeviceTypeFeatureAvailabilityChecker: FeatureAvailabilityChecker {
let deviceType: UIUserInterfaceIdiom
public init(deviceType: UIUserInterfaceIdiom) {
self.deviceType = deviceType
}
public var isAvailable: Bool {
UIDevice.current.userInterfaceIdiom == deviceType
}
}
...@@ -11,9 +11,6 @@ public struct PremiumInAppFeatureAvailabilityChecker: FeatureAvailabilityChecker ...@@ -11,9 +11,6 @@ public struct PremiumInAppFeatureAvailabilityChecker: FeatureAvailabilityChecker
public init() {} public init() {}
public var isAvailable: Bool { public var isAvailable: Bool {
if let metricsLog = UserDefaults.standard.dictionary(forKey: kOLAppMetricsKey) { isAppPro()
return metricsLog[kEventInAppPurchasedCompleted] != nil
}
return false
} }
} }
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