Commit 397522dc by Dmitriy Stepanets

Merge branch 'feature/IOS-133-onboarding' into develop

# Conflicts:
#	1Weather-Icons.sketch
#	1Weather.xcodeproj/project.pbxproj
#	1Weather/Resources/en.lproj/Localizable.strings
parents 4d6f4b51 e6b9d9dd
No preview for this file type
......@@ -109,6 +109,7 @@
CD6761842625B6A10079D273 /* RadarLayersCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6761832625B6A10079D273 /* RadarLayersCellFactory.swift */; };
CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6761872625C3360079D273 /* RadarViewModel.swift */; };
CD678C6926B03F91001E0CB7 /* RadarWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD678C6826B03F91001E0CB7 /* RadarWidget.swift */; };
CD6B2C8426C55F4600473B2D /* OnboardingPageControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B2C8326C55F4600473B2D /* OnboardingPageControl.swift */; };
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */; };
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303D25726960004B34B3 /* ThemeProtocol.swift */; };
CD6B304325726AD1004B34B3 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B304225726AD1004B34B3 /* DefaultTheme.swift */; };
......@@ -184,6 +185,8 @@
CDC6126225E8DAB800188DA7 /* MoonPhaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC6126125E8DAB800188DA7 /* MoonPhaseCell.swift */; };
CDC6126625E9085600188DA7 /* GraphLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC6126525E9085600188DA7 /* GraphLine.swift */; };
CDC6126A25E90C8800188DA7 /* GraphLineSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC6126925E90C8800188DA7 /* GraphLineSettings.swift */; };
CDC62C4526C13B9200156643 /* OnboardingPageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC62C4426C13B9200156643 /* OnboardingPageController.swift */; };
CDC62C4726C13BE300156643 /* OnboardingContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC62C4626C13BE300156643 /* OnboardingContentController.swift */; };
CDD0F1E52572425200CF5017 /* SF-Pro.ttf in Resources */ = {isa = PBXBuildFile; fileRef = CDD0F1E42572425200CF5017 /* SF-Pro.ttf */; };
CDD0F1E82572429E00CF5017 /* AppFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD0F1E72572429E00CF5017 /* AppFont.swift */; };
CDD0F1EE25725BCF00CF5017 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD0F1ED25725BCF00CF5017 /* ThemeManager.swift */; };
......@@ -406,6 +409,7 @@
CD6761832625B6A10079D273 /* RadarLayersCellFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarLayersCellFactory.swift; sourceTree = "<group>"; };
CD6761872625C3360079D273 /* RadarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarViewModel.swift; sourceTree = "<group>"; };
CD678C6826B03F91001E0CB7 /* RadarWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarWidget.swift; sourceTree = "<group>"; };
CD6B2C8326C55F4600473B2D /* OnboardingPageControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPageControl.swift; sourceTree = "<group>"; };
CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSizingButton.swift; sourceTree = "<group>"; };
CD6B303D25726960004B34B3 /* ThemeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeProtocol.swift; sourceTree = "<group>"; };
CD6B304225726AD1004B34B3 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = "<group>"; };
......@@ -481,6 +485,8 @@
CDC6126125E8DAB800188DA7 /* MoonPhaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonPhaseCell.swift; sourceTree = "<group>"; };
CDC6126525E9085600188DA7 /* GraphLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphLine.swift; sourceTree = "<group>"; };
CDC6126925E90C8800188DA7 /* GraphLineSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphLineSettings.swift; sourceTree = "<group>"; };
CDC62C4426C13B9200156643 /* OnboardingPageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPageController.swift; sourceTree = "<group>"; };
CDC62C4626C13BE300156643 /* OnboardingContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingContentController.swift; sourceTree = "<group>"; };
CDD0F1E42572425200CF5017 /* SF-Pro.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Pro.ttf"; sourceTree = "<group>"; };
CDD0F1E72572429E00CF5017 /* AppFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFont.swift; sourceTree = "<group>"; };
CDD0F1ED25725BCF00CF5017 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
......@@ -1197,6 +1203,16 @@
path = MoonPhaseCell;
sourceTree = "<group>";
};
CDC62C4326C13AD100156643 /* InitialOnboarding */ = {
isa = PBXGroup;
children = (
CDC62C4426C13B9200156643 /* OnboardingPageController.swift */,
CDC62C4626C13BE300156643 /* OnboardingContentController.swift */,
CD6B2C8326C55F4600473B2D /* OnboardingPageControl.swift */,
);
path = InitialOnboarding;
sourceTree = "<group>";
};
CDD0F1DC2572400200CF5017 /* UI */ = {
isa = PBXGroup;
children = (
......@@ -1440,6 +1456,7 @@
CEC8FBAD263975170001A6BF /* Onboarding */ = {
isa = PBXGroup;
children = (
CDC62C4326C13AD100156643 /* InitialOnboarding */,
CEC8FBAE2639756A0001A6BF /* OnboardingViewController.swift */,
);
path = Onboarding;
......@@ -1838,6 +1855,7 @@
CD7BF15526203E6900A30DF5 /* RadarViewController.swift in Sources */,
CD82300325D69DE400A05501 /* TodayConditionsCell.swift in Sources */,
CD32CE08260C743B00235081 /* MenuViewModel.swift in Sources */,
CDC62C4526C13B9200156643 /* OnboardingPageController.swift in Sources */,
CD866A76260F77C500E96A5C /* SettingsDetailsCoordinator.swift in Sources */,
CE0457902632B3BC00B3C19A /* NotificationsViewModel.swift in Sources */,
CE13B81A262480B3007CBD4D /* AdManager.swift in Sources */,
......@@ -1936,6 +1954,8 @@
CD37D3FA260DF714002669D6 /* SettingsThemeCell.swift in Sources */,
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */,
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */,
CDC62C4726C13BE300156643 /* OnboardingContentController.swift in Sources */,
CD9B6B1125DBC723001D9B80 /* CubicCurveAlgorithm.swift in Sources */,
CD8B60B4263819790055CB3F /* NotificationsViewController.swift in Sources */,
CD67617026259D220079D273 /* RadarMapLayersController.swift in Sources */,
CEC8FBAF2639756A0001A6BF /* OnboardingViewController.swift in Sources */,
......@@ -1994,6 +2014,7 @@
CD37D3F6260DF5BA002669D6 /* SettingsViewModel.swift in Sources */,
CD17C5F625D15B4400EE884E /* TodayViewController.swift in Sources */,
CD86245E25E646350097F3FB /* SunUvView.swift in Sources */,
CD6B2C8426C55F4600473B2D /* OnboardingPageControl.swift in Sources */,
CD427D2A266F86C600B4350A /* ShortsManager.swift in Sources */,
CDF8F12D26208E7B00DB384A /* MapCurrentTimeView.swift in Sources */,
CEC7D8EE2639FE2700B8836D /* OLInAppStoreManager.swift in Sources */,
......
......@@ -82,6 +82,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
FirebaseApp.configure()
ConfigManager.shared.updateConfig()
//App UI
let appCoordinator = AppCoordinator(window: self.window!)
appCoordinator.start()
ThemeManager.setBaseTheme()
......
......@@ -98,11 +98,38 @@ class AppCoordinator: Coordinator {
public func finishAnimation() {
DispatchQueue.main.async {
if ConfigManager.shared.config.showOnboarding {
if Settings.shared.initialOnboardingShowed {
self.finishInitialOnboarding()
}
else {
let initialOnboarding = OnboardingPageController(coordinator: self)
self.window.rootViewController = initialOnboarding
UIView.transition(with: self.window,
duration: 0.3,
options: .transitionCrossDissolve,
animations: nil)
}
}
else {
self.finishInitialOnboarding()
}
}
}
public func finishInitialOnboarding() {
DispatchQueue.main.async {
Settings.shared.initialOnboardingShowed = true
self.window.rootViewController = self.tabBarController
//Search the TodayCoordinator
let todayCoordinator = (self.childCoordinators.first{$0 is TodayCoordinator} as? TodayCoordinator)
todayCoordinator?.showOnboardingOrPrivacyNoticeIfNeeded()
UIView.transition(with: self.window,
duration: 0.3,
options: .transitionCrossDissolve,
animations: nil,
completion: {_ in
//Search the TodayCoordinator
let todayCoordinator = (self.childCoordinators.first{ $0 is TodayCoordinator } as? TodayCoordinator)
todayCoordinator?.showOnboardingOrPrivacyNoticeIfNeeded()
})
}
}
......
......@@ -21,8 +21,18 @@ public struct AppConfig: Codable {
public let shortsLeftBelowCount: Int
public let shortsLastNudgeEnabled: Bool
public let shortsSwipeUpNudgeCount: Int
public let showOnboarding: Bool
public init(popularCities: [GeoNamesPlace]?, adConfig: AdConfig, ccpaUpdateInterval: TimeInterval?, nwsAlertsViaMoEngageEnabled: Bool, showAttPrompt: Bool, shortsLeftBelowCountKey: Int, shortsLastNudgeEnabledKey: Bool, shortsSwipeUpNudgeCountKey: Int) {
public init(popularCities: [GeoNamesPlace]?,
adConfig: AdConfig,
ccpaUpdateInterval: TimeInterval?,
nwsAlertsViaMoEngageEnabled: Bool,
showAttPrompt: Bool,
shortsLeftBelowCountKey: Int,
shortsLastNudgeEnabledKey: Bool,
shortsSwipeUpNudgeCountKey: Int,
showOnboarding: Bool
) {
self.popularCities = popularCities
self.adConfig = adConfig
self.ccpaUpdateInterval = ccpaUpdateInterval
......@@ -31,6 +41,7 @@ public struct AppConfig: Codable {
self.shortsLeftBelowCount = shortsLeftBelowCountKey
self.shortsLastNudgeEnabled = shortsLastNudgeEnabledKey
self.shortsSwipeUpNudgeCount = shortsSwipeUpNudgeCountKey
self.showOnboarding = showOnboarding
}
}
......@@ -47,6 +58,7 @@ public class ConfigManager {
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 showOnboardingKey = "ios_show_onboarding"
private let delegates = MulticastDelegate<ConfigManagerDelegate>()
......@@ -61,7 +73,7 @@ public class ConfigManager {
}()
public static let shared = ConfigManager()
public private(set) var isUpdating = false
public var config: AppConfig = AppConfig(popularCities: nil,
adConfig: AdConfig(),
ccpaUpdateInterval: nil,
......@@ -69,12 +81,19 @@ public class ConfigManager {
showAttPrompt: false,
shortsLeftBelowCountKey: 0,
shortsLastNudgeEnabledKey: false,
shortsSwipeUpNudgeCountKey: 0)
shortsSwipeUpNudgeCountKey: 0,
showOnboarding: false)
public func updateConfig() {
log.info("update config")
isUpdating = true
remoteConfig.fetchAndActivate { [weak self] (status, error) in
guard let self = self else { return }
defer {
self.isUpdating = false
}
switch status {
case .successFetchedFromRemote:
self.parseConfigFromFirebase(source: "remote")
......@@ -152,6 +171,9 @@ public class ConfigManager {
let shortsSwipeNudgeCountValue = remoteConfig.configValue(forKey: ConfigManager.shortsSwipeUpNudgeCountKey)
let shortsSwipeNudgeCount = shortsSwipeNudgeCountValue.numberValue.intValue
let showOnboardingValue = remoteConfig.configValue(forKey: ConfigManager.showOnboardingKey)
let showOnboarding = showOnboardingValue.boolValue
DispatchQueue.main.async {
self.config = AppConfig(popularCities: popularCities,
adConfig: adConfig,
......@@ -160,7 +182,8 @@ public class ConfigManager {
showAttPrompt: showAttPrompt,
shortsLeftBelowCountKey: shortsLeftBelowCount,
shortsLastNudgeEnabledKey: shortsLastNudgeEnabled,
shortsSwipeUpNudgeCountKey: shortsSwipeNudgeCount)
shortsSwipeUpNudgeCountKey: shortsSwipeNudgeCount,
showOnboarding: showOnboarding)
self.notifyAboutConfigUpdate()
DispatchQueue.global().async {
let encoder = JSONEncoder()
......
{
"images" : [
{
"filename" : "onboarding-alerts.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
{
"images" : [
{
"filename" : "onboarding-close.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
{
"images" : [
{
"filename" : "onboarding-forecast.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
{
"images" : [
{
"filename" : "onboarding-next.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
{
"images" : [
{
"filename" : "onboarding-radar.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
......@@ -300,3 +300,14 @@
"widget.radar.title" = "Radar";
"widget.radar.description" = "";
"widget.lastUpdatedTemplate" = "Last updated #LAST_UPDATED ago.";
"ads.placeholder" = "Advertisement";
//Onboarding
"onboarding.skip" = "Skip";
"onboarding.done" = "Done";
"onboarding.forecast.title" = "Extended forecast";
"onboarding.forecast.subtitle" = "<Description>";
"onboarding.alerts.title" = "Weather alerts";
"onboarding.alerts.subtitle" = "<Description>";
"onboarding.radar.title" = "Live doppler radar";
"onboarding.radar.subtitle" = "<Description>";
//
// OnboardingContentController.swift
// 1Weather
//
// Created by Dmitry Stepanets on 09.08.2021.
//
import UIKit
class OnboardingContentController: UIViewController {
//Private
private let mainImageView = UIImageView()
private let titleLabel = UILabel()
private let subtitleLabel = UILabel()
init(type: OnboardingControllerType) {
super.init(nibName: nil, bundle: nil)
mainImageView.image = type.image
titleLabel.text = type.title
subtitleLabel.text = type.subtitle
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
prepareImageView()
prepareLables()
updateUI()
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
updateUI()
}
private func updateUI() {
view.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
subtitleLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
}
}
private extension OnboardingContentController {
func prepareImageView() {
mainImageView.contentMode = .scaleAspectFit
view.addSubview(mainImageView)
mainImageView.snp.makeConstraints { make in
make.bottom.equalToSuperview().multipliedBy(0.56)
make.centerX.equalToSuperview()
make.left.right.equalToSuperview().inset(30)
}
}
func prepareLables() {
titleLabel.font = AppFont.SFPro.semibold(size: 24)
titleLabel.textColor = ThemeManager.currentTheme.graphTintColor
view.addSubview(titleLabel)
subtitleLabel.font = AppFont.SFPro.regular(size: 14)
view.addSubview(subtitleLabel)
//Constraints
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().inset(30)
make.bottom.equalToSuperview().multipliedBy(0.7)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().inset(30)
make.top.equalTo(titleLabel.snp.bottom).offset(10)
}
}
}
//
// OnboardingPageControl.swift
// 1Weather
//
// Created by Dmitry Stepanets on 12.08.2021.
//
import UIKit
class OnboardingPageControl: UIView {
//Private
private let kSpacePerDot: CGFloat = 10
private let kDotSize: CGSize = .init(width: 9, height: 9)
private let kIndicatorSize: CGSize = .init(width: 23, height: 9)
private let kDotColor = UIColor(hex: 0xD0D0D0)
private let kIndicatorColor = ThemeManager.currentTheme.graphTintColor
private let totalPagesCount: Int
private var dots = [UIView]()
private lazy var dotColorComponents: (red: CGFloat, green: CGFloat, blue: CGFloat) = {
let components = kDotColor.cgColor.components
return (components?[0] ?? 0,
components?[1] ?? 0,
components?[2] ?? 0)
}()
private lazy var indicatorColorComponents: (red: CGFloat, green: CGFloat, blue: CGFloat) = {
let components = kIndicatorColor.cgColor.components
return (components?[0] ?? 0,
components?[1] ?? 0,
components?[2] ?? 0)
}()
init(totalPagesCount: Int) {
self.totalPagesCount = totalPagesCount
super.init(frame: .zero)
prepareView()
prepareDots()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func scroll(toPage nextPageIndex: Int, currentPageIndex: Int, screenTransitionProgress: CGFloat) {
guard screenTransitionProgress != 0 else { return }
var scrollProgress = max(0, screenTransitionProgress)
scrollProgress = min(screenTransitionProgress, 1)
let targetDot = dots[nextPageIndex]
let previousDot = dots[currentPageIndex]
//Width
let widthDelta = (kIndicatorSize.width - kDotSize.width) * scrollProgress
targetDot.snp.updateConstraints { update in
update.width.equalTo(kDotSize.width + widthDelta)
}
previousDot.snp.updateConstraints { update in
update.width.equalTo(kIndicatorSize.width - widthDelta)
}
//Color
//Blue to gray
let previousColorDelta: (red: CGFloat, green: CGFloat, blue: CGFloat) = (indicatorColorComponents.red - dotColorComponents.red,
indicatorColorComponents.green - dotColorComponents.green,
indicatorColorComponents.blue - dotColorComponents.blue)
previousDot.backgroundColor = UIColor(red: indicatorColorComponents.red - previousColorDelta.red * scrollProgress,
green: indicatorColorComponents.green - previousColorDelta.green * scrollProgress,
blue: indicatorColorComponents.blue - previousColorDelta.blue * scrollProgress,
alpha: 1)
//Gray to blue
let targetColorDelta: (red: CGFloat, green: CGFloat, blue: CGFloat) = (dotColorComponents.red - indicatorColorComponents.red,
dotColorComponents.green - indicatorColorComponents.green,
dotColorComponents.blue - indicatorColorComponents.blue)
targetDot.backgroundColor = UIColor(red: dotColorComponents.red - targetColorDelta.red * scrollProgress,
green: dotColorComponents.green - targetColorDelta.green * scrollProgress,
blue: dotColorComponents.blue - targetColorDelta.blue * scrollProgress,
alpha: 1)
}
}
//MARK:- Prepare
private extension OnboardingPageControl {
func prepareView() {
snp.makeConstraints { make in
make.height.equalTo(kDotSize.height)
}
}
func prepareDots() {
for index in 0..<totalPagesCount {
let dot = UIView()
dot.backgroundColor = index == 0 ? kIndicatorColor : kDotColor
dot.layer.cornerRadius = kDotSize.height / 2
addSubview(dot)
dots.append(dot)
dot.snp.makeConstraints { make in
make.size.equalTo(index == 0 ? kIndicatorSize : kDotSize)
make.centerY.equalToSuperview()
if index == 0 {
make.left.equalToSuperview()
}
else {
make.left.equalTo(dots[index - 1].snp.right).offset(kSpacePerDot)
}
if index == totalPagesCount - 1 {
make.right.equalToSuperview()
}
}
}
}
}
......@@ -11,11 +11,14 @@ import OneWeatherCore
import OneWeatherAnalytics
class SplashAnimationViewController: UIViewController {
private let kAttemptsCount = 3
private let appCoordinator:AppCoordinator
private let backgroundImageView = UIImageView()
private let animation = Animation.named("splash")
private let logger = Logger(componentName: "SplashAnimationController")
private var animationView:AnimationView?
private let playButton = UIButton()
private var currentAttempt = 0
init(appCoordinator:AppCoordinator) {
self.appCoordinator = appCoordinator
......@@ -59,12 +62,36 @@ class SplashAnimationViewController: UIViewController {
}
}
private func finish() {
//We need to wait, until ConfigManager finishes updating configuration
//But this is given 3 attempts with a duration of 1 second
if ConfigManager.shared.isUpdating {
if currentAttempt < kAttemptsCount {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.logger.log(level: .debug, message: "Waiting for finish config update \(self.currentAttempt)/\(self.kAttemptsCount)")
self.currentAttempt += 1
self.finish()
return
}
}
else {
self.logger.log(level: .debug, message: "Finish animation")
self.appCoordinator.finishAnimation()
}
}
else {
self.logger.log(level: .debug, message: "Finish animation")
self.appCoordinator.finishAnimation()
}
}
private func noCityAnimation() {
analytics(log: .ANALYTICS_FTUE_SPLASH_SEEN)
analytics(set: .splashFTUE, to: true)
self.animationView?.play(completion: {[weak self] _ in
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
self?.appCoordinator.finishAnimation()
self?.finish()
}
})
}
......@@ -76,7 +103,7 @@ class SplashAnimationViewController: UIViewController {
self.animationView?.alpha = 1
} completion: { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.appCoordinator.finishAnimation()
self.finish()
}
}
}
......
......@@ -121,6 +121,12 @@ public enum AnalyticsEvent: String {
case ANALYTICS_SHORTS_LIKE_BUTTON_CLICK = "LIKE_BUTTON_CLICK"
case ANALYTICS_SHORTS_EXIT_SHORTS_VIEW = "EXIT_SHORTS_VIEW"
case ANALYTICS_SHORTS_NUDGE_VIEW = "NUDGE_VIEW"
case ANALYTICS_ONBOARDING_FORECAST_SEEN = "ONBOARDING_FORECAST_SEEN"
case ANALYTICS_ONBOARDING_ALERT_SEEN = "ONBOARDING_ALERT_SEEN"
case ANALYTICS_ONBOARDING_RADAR_SEEN = "ONBOARDING_RADAR_SEEN"
case ANALYTICS_ONBOARDING_NEXT = "ONBOARDING_NEXT"
case ANALYTICS_ONBOARDING_SKIP = "ONBOARDING_SKIP"
case ANALYTICS_ONBOARDING_SWIPE = "ONBOARDING_SWIPE"
/// FTUE Funnel: User has saved his first city after installing the app.
case ANALYTICS_USER_QUALIFIED = "USER_QUALIFIED"
......
......@@ -98,6 +98,9 @@ public class Settings {
@UserDefaultsOptionalValue("widgetPromotionTriggerCount")
public var widgetPromotionTriggerCount: Int?
@UserDefaultsBasicValue(key: "initial_onboarding_showed")
public var initialOnboardingShowed = false
@UserDefaultsBasicValue(key: "shorts_showed_swipeUp_count")
public var shortsSwipeUpNudgeShowedCount = 0
......
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