Commit 280006fc by Demid Merzlyakov

IOS-155: Subscriptions control via config.

parent 580f1c88
......@@ -1364,6 +1364,14 @@
path = Firebase;
sourceTree = "<group>";
};
CE3A9CE426E64F9300E2CB4B /* Configuration */ = {
isa = PBXGroup;
children = (
CD6C22E926677BDF00D75659 /* ConfigManager.swift */,
);
path = Configuration;
sourceTree = "<group>";
};
CE578FE025FB415E00E8B85D /* Locations */ = {
isa = PBXGroup;
children = (
......@@ -1438,7 +1446,7 @@
isa = PBXGroup;
children = (
CD6C22ED26677DBC00D75659 /* PushNotificationsManager.swift */,
CD6C22E926677BDF00D75659 /* ConfigManager.swift */,
CE3A9CE426E64F9300E2CB4B /* Configuration */,
87C171F325FF7A4000DA3464 /* PopularCitiesManager.swift */,
CD427D29266F86C600B4350A /* ShortsManager.swift */,
);
......
......@@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ios_subscription_config</key>
<string>{
&quot;subscriptions_enabled&quot;: false,
&quot;monthly&quot;: {
&quot;product_id&quot;: &quot;&quot;
},
&quot;yearly&quot;: {
&quot;product_id&quot;: &quot;&quot;
},
&quot;monthly_discounted&quot;: {
&quot;product_id&quot;: &quot;&quot;
},
&quot;yearly_discounted&quot;: {
&quot;product_id&quot;: &quot;&quot;
}
}</string>
<key>search_screen_popular_cities</key>
<string>[{&quot;lat&quot;:&quot;40.7127&quot;,&quot;lon&quot;:&quot;-74.006&quot;,&quot;city&quot;:&quot;New York&quot;,&quot;state&quot;:&quot;New York&quot;,&quot;stateCode&quot;:&quot;NY&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:1},{&quot;lat&quot;:&quot;41.8756&quot;,&quot;lon&quot;:&quot;-87.6244&quot;,&quot;city&quot;:&quot;Chicago&quot;,&quot;state&quot;:&quot;Illinois&quot;,&quot;stateCode&quot;:&quot;IL&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:2},{&quot;lat&quot;:&quot;29.7589&quot;,&quot;lon&quot;:&quot;-95.3677&quot;,&quot;city&quot;:&quot;Houston&quot;,&quot;state&quot;:&quot;Texas&quot;,&quot;stateCode&quot;:&quot;TX&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:3},{&quot;lat&quot;:&quot;34.0537&quot;,&quot;lon&quot;:&quot;-118.243&quot;,&quot;city&quot;:&quot;Los Angeles&quot;,&quot;state&quot;:&quot;California&quot;,&quot;stateCode&quot;:&quot;CA&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:4},{&quot;lat&quot;:&quot;29.4246&quot;,&quot;lon&quot;:&quot;-98.4951&quot;,&quot;city&quot;:&quot;San Antonio&quot;,&quot;state&quot;:&quot;Texas&quot;,&quot;stateCode&quot;:&quot;TX&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:5},{&quot;lat&quot;:&quot;39.7683&quot;,&quot;lon&quot;:&quot;-86.1584&quot;,&quot;city&quot;:&quot;Indianapolis&quot;,&quot;state&quot;:&quot;Indiana&quot;,&quot;stateCode&quot;:&quot;IN&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:6},{&quot;lat&quot;:&quot;39.9527&quot;,&quot;lon&quot;:&quot;-75.1635&quot;,&quot;city&quot;:&quot;Philadelphia&quot;,&quot;state&quot;:&quot;Pennsylvania&quot;,&quot;stateCode&quot;:&quot;PA&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:7},{&quot;lat&quot;:&quot;36.1673&quot;,&quot;lon&quot;:&quot;-115.149&quot;,&quot;city&quot;:&quot;Las Vegas&quot;,&quot;state&quot;:&quot;Nevada&quot;,&quot;stateCode&quot;:&quot;NV&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:8},{&quot;lat&quot;:&quot;39.9623&quot;,&quot;lon&quot;:&quot;-83.0007&quot;,&quot;city&quot;:&quot;Columbus&quot;,&quot;state&quot;:&quot;Ohio&quot;,&quot;stateCode&quot;:&quot;OH&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:9},{&quot;lat&quot;:&quot;30.3322&quot;,&quot;lon&quot;:&quot;-81.6557&quot;,&quot;city&quot;:&quot;Jacksonville&quot;,&quot;state&quot;:&quot;Florida&quot;,&quot;stateCode&quot;:&quot;FL&quot;,&quot;country&quot;:&quot;United States of America&quot;,&quot;countryCode&quot;:&quot;US&quot;,&quot;order&quot;:10}]</string>
<key>ios_nws_alerts_via_moengage_enabled</key>
......
......@@ -22,6 +22,7 @@ public class ConfigManager {
private static let ccpaUpdateIntervalConfigKey = "ccpa_update_interval_ios"
private static let shortsLeftBelowCountKey = "shorts_left_below_nudge_every_x_cards"
private static let shortsSwipeUpNudgeCountKey = "shorts_swipe_up_nudge_on_x_cards"
private static let subscriptionConfigKey = "ios_subscription_config"
private let delegates = MulticastDelegate<ConfigManagerDelegate>()
......@@ -100,11 +101,10 @@ public class ConfigManager {
private func parseConfigFromFirebase(source: String) {
log.info("Got config from \(source)")
var configErrors = [Error]()
let decoder = JSONDecoder()
var adConfig = AdConfig()
do {
let decoder = JSONDecoder()
let adConfigData = remoteConfig.configValue(forKey: ConfigManager.adConfigKey).dataValue
adConfig = try decoder.decode(AdConfig.self, from: adConfigData)
}
......@@ -142,13 +142,25 @@ public class ConfigManager {
let featureAvailability = parseFeatureAvailability()
var subscriptionsConfig = SubscriptionsListConfig()
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let subscriptionConfigData = remoteConfig.configValue(forKey: ConfigManager.subscriptionConfigKey).dataValue
subscriptionsConfig = try decoder.decode(SubscriptionsListConfig.self, from: subscriptionConfigData)
}
catch (let error) {
configErrors.append(error)
}
DispatchQueue.main.async {
self.config = AppConfig(popularCities: popularCities,
adConfig: adConfig,
ccpaUpdateInterval:ccpaUpdateInterval,
shortsLeftBelowCountKey: shortsLeftBelowCount,
shortsSwipeUpNudgeCountKey: shortsSwipeNudgeCount,
explicitFeatureAvailability: featureAvailability
explicitFeatureAvailability: featureAvailability,
subscriptionConfig: subscriptionsConfig
)
self.notifyAboutConfigUpdate()
DispatchQueue.global().async {
......@@ -182,7 +194,7 @@ fileprivate extension AppFeature {
return "shorts_swipe_down_nudge_enabled"
case .onboarding:
return "ios_show_onboarding"
case .ads, .airQualityIndex, .minutelyForecast, .shorts:
case .ads, .airQualityIndex, .minutelyForecast, .shorts, case .subscription, .subscriptionForPro:
return nil
// don't use 'default', so that we didn't add new features here in the future.
}
......
......@@ -77,6 +77,8 @@
CDFE459426566D7B0021A29F /* HealthSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFE459326566D7B0021A29F /* HealthSource.swift */; };
CDFE459626566D860021A29F /* FIPSSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFE459526566D860021A29F /* FIPSSource.swift */; };
CE3A112726CD3CDE00D925C7 /* UserDefaults+OneWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3A112626CD3CDE00D925C7 /* UserDefaults+OneWeather.swift */; };
CE3D393826E7A65600E7E738 /* SubscriptionsListConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3D393726E7A65600E7E738 /* SubscriptionsListConfig.swift */; };
CE3D393A26E7A66200E7E738 /* SubscriptionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3D393926E7A66200E7E738 /* SubscriptionConfig.swift */; };
CE72A75426D5121D00F13CF7 /* FeatureAvailabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A75326D5121D00F13CF7 /* FeatureAvailabilityManager.swift */; };
CE72A75726D5127400F13CF7 /* AppFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A75626D5127400F13CF7 /* AppFeature.swift */; };
CE72A75926D516BF00F13CF7 /* FeatureAvailabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE72A75826D516BF00F13CF7 /* FeatureAvailabilityChecker.swift */; };
......@@ -188,6 +190,8 @@
CDFE459326566D7B0021A29F /* HealthSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthSource.swift; sourceTree = "<group>"; };
CDFE459526566D860021A29F /* FIPSSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIPSSource.swift; sourceTree = "<group>"; };
CE3A112626CD3CDE00D925C7 /* UserDefaults+OneWeather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+OneWeather.swift"; sourceTree = "<group>"; };
CE3D393726E7A65600E7E738 /* SubscriptionsListConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsListConfig.swift; sourceTree = "<group>"; };
CE3D393926E7A66200E7E738 /* SubscriptionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionConfig.swift; sourceTree = "<group>"; };
CE72A75326D5121D00F13CF7 /* FeatureAvailabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureAvailabilityManager.swift; sourceTree = "<group>"; };
CE72A75626D5127400F13CF7 /* AppFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFeature.swift; sourceTree = "<group>"; };
CE72A75826D516BF00F13CF7 /* FeatureAvailabilityChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureAvailabilityChecker.swift; sourceTree = "<group>"; };
......@@ -484,6 +488,15 @@
path = Sources;
sourceTree = "<group>";
};
CE3D393426E7A63400E7E738 /* Subscriptions */ = {
isa = PBXGroup;
children = (
CE3D393726E7A65600E7E738 /* SubscriptionsListConfig.swift */,
CE3D393926E7A66200E7E738 /* SubscriptionConfig.swift */,
);
path = Subscriptions;
sourceTree = "<group>";
};
CE72A75526D5122500F13CF7 /* FeatureAvailability */ = {
isa = PBXGroup;
children = (
......@@ -510,6 +523,7 @@
CE72A75D26D627D100F13CF7 /* Config */ = {
isa = PBXGroup;
children = (
CE3D393426E7A63400E7E738 /* Subscriptions */,
CE72A76226D6284300F13CF7 /* Ads */,
CE72A75E26D627E300F13CF7 /* AppConfig.swift */,
);
......@@ -699,6 +713,7 @@
files = (
CD3302A126C2A589007BBB12 /* WidgetManager.swift in Sources */,
CD3302A026C2A527007BBB12 /* SmartTextMacro.swift in Sources */,
CE3D393826E7A65600E7E738 /* SubscriptionsListConfig.swift in Sources */,
CD3883972657AFE00070FD6F /* Settings.swift in Sources */,
CE72A75426D5121D00F13CF7 /* FeatureAvailabilityManager.swift in Sources */,
CEFE85242694C5D1003C67D3 /* ApproachingPrecipitationSmartText.swift in Sources */,
......@@ -712,6 +727,7 @@
CD2D55D626553384007B70F4 /* UserDefaultsValue.swift in Sources */,
CD550FBA265531A100257FB5 /* RadarLayer.swift in Sources */,
CD550FBB265531A100257FB5 /* RadarLayerType.swift in Sources */,
CE3D393A26E7A66200E7E738 /* SubscriptionConfig.swift in Sources */,
CDBC243F2656740E00F9F4E2 /* AppData.swift in Sources */,
CD550FBC265531A100257FB5 /* WeatherLayerType.swift in Sources */,
CD550FBD265531A100257FB5 /* SevereLayerType.swift in Sources */,
......
......@@ -16,4 +16,8 @@ public enum AppFeature: String, Codable, CaseIterable {
case minutelyForecast
case shorts
case shortsLastNudge
/// Any kind of subscription
case subscription
/// Discounted subscription for people who previously purchased an in-app to remove ads
case subscriptionForPro
}
......@@ -14,13 +14,15 @@ public struct AppConfig: Codable {
public let shortsLeftBelowCount: Int
public let shortsSwipeUpNudgeCount: Int
private let explicitFeatureAvailability: [AppFeature: Bool]
private let subscriptionsConfig: SubscriptionsListConfig
public init(popularCities: [GeoNamesPlace]?,
adConfig: AdConfig,
ccpaUpdateInterval: TimeInterval?,
shortsLeftBelowCountKey: Int,
shortsSwipeUpNudgeCountKey: Int,
explicitFeatureAvailability: [AppFeature: Bool]
explicitFeatureAvailability: [AppFeature: Bool],
subscriptionsConfig: SubscriptionsListConfig
) {
self.popularCities = popularCities
self.adConfig = adConfig
......@@ -28,12 +30,16 @@ public struct AppConfig: Codable {
self.shortsLeftBelowCount = shortsLeftBelowCountKey
self.shortsSwipeUpNudgeCount = shortsSwipeUpNudgeCountKey
self.explicitFeatureAvailability = explicitFeatureAvailability
self.subscriptionsConfig = subscriptionsConfig
}
public func isEnabled(feature: AppFeature) -> Bool {
if feature == .ads {
return adConfig.adsEnabled
}
if feature == .subscription || feature == .subscriptionForPro {
return subscriptionsConfig.subscriptionsEnabled
}
return explicitFeatureAvailability[feature] ?? true
}
}
//
// SubscriptionConfig.swift
// OneWeatherCore
//
// Created by Demid Merzlyakov on 07.09.2021.
//
import Foundation
public struct SubscriptionConfig {
public let productId: String
}
extension SubscriptionConfig: Codable {}
//
// SubscriptionsListConfig.swift
// OneWeatherCore
//
// Created by Demid Merzlyakov on 07.09.2021.
//
import Foundation
public struct SubscriptionsListConfig {
public let subscriptionsEnabled: Bool
public let monthly: SubscriptionConfig
public let yearly: SubscriptionConfig
public let monthlyDiscounted: SubscriptionConfig
public let yearlyDiscounted: SubscriptionConfig
public init(subscriptionsEnabled: Bool, monthly: SubscriptionConfig, yearly: SubscriptionConfig, monthlyDiscounted: SubscriptionConfig, yearlyDiscounted: SubscriptionConfig) {
self.subscriptionsEnabled = subscriptionsEnabled
self.monthly = monthly
self.yearly = yearly
self.monthlyDiscounted = monthlyDiscounted
self.yearlyDiscounted = yearlyDiscounted
}
public init() {
self.subscriptionsEnabled = false
self.monthly = SubscriptionConfig(productId: "")
self.yearly = SubscriptionConfig(productId: "")
self.monthlyDiscounted = SubscriptionConfig(productId: "")
self.yearlyDiscounted = SubscriptionConfig(productId: "")
}
}
extension SubscriptionsListConfig: Codable {}
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