Commit 40069501 by Dmitry Stepanets

[IOS-288]: Added subscription pop up view

parent 4f586371
......@@ -180,9 +180,6 @@
CDB0D4CA2670CAD00081C773 /* ShortsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB0D4C92670CAD00081C773 /* ShortsCollectionViewCell.swift */; };
CDB0D4CC2670D12F0081C773 /* TodayShortsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB0D4CB2670D12F0081C773 /* TodayShortsCell.swift */; };
CDB0D4CE2670DABF0081C773 /* UIImage+AverageColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB0D4CD2670DABF0081C773 /* UIImage+AverageColor.swift */; };
CDC2E23F27184C4F002B6826 /* SubscriptionPopUpCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC2E23E27184C4F002B6826 /* SubscriptionPopUpCoordinator.swift */; };
CDC2E242271854D0002B6826 /* StorePresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC2E241271854D0002B6826 /* StorePresentationAnimator.swift */; };
CDC2E244271854EA002B6826 /* StoreDismissAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC2E243271854EA002B6826 /* StoreDismissAnimator.swift */; };
CDC3F858269460E600AAE3BF /* PromotionMediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC3F857269460E600AAE3BF /* PromotionMediumWidgetView.swift */; };
CDC6124F25E7964700188DA7 /* TodayDayTimesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC6124E25E7964700188DA7 /* TodayDayTimesCell.swift */; };
CDC6125325E79C8F00188DA7 /* DayTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC6125225E79C8F00188DA7 /* DayTimeView.swift */; };
......@@ -195,6 +192,7 @@
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 */; };
CDD4C43A271971AC0025481A /* SubscriptionPopUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD4C439271971AC0025481A /* SubscriptionPopUpViewController.swift */; };
CDD75F0D25DE68B10099ACDB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDD75F0F25DE68B10099ACDB /* Localizable.strings */; };
CDDCD50726809F6D00E089AD /* ShortsSwipeHelperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCD50626809F6D00E089AD /* ShortsSwipeHelperView.swift */; };
CDDCD5092680C18B00E089AD /* ShortsUnreadNudgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCD5082680C18B00E089AD /* ShortsUnreadNudgeView.swift */; };
......@@ -544,9 +542,6 @@
CDB0D4C92670CAD00081C773 /* ShortsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortsCollectionViewCell.swift; sourceTree = "<group>"; };
CDB0D4CB2670D12F0081C773 /* TodayShortsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayShortsCell.swift; sourceTree = "<group>"; };
CDB0D4CD2670DABF0081C773 /* UIImage+AverageColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+AverageColor.swift"; sourceTree = "<group>"; };
CDC2E23E27184C4F002B6826 /* SubscriptionPopUpCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionPopUpCoordinator.swift; sourceTree = "<group>"; };
CDC2E241271854D0002B6826 /* StorePresentationAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePresentationAnimator.swift; sourceTree = "<group>"; };
CDC2E243271854EA002B6826 /* StoreDismissAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDismissAnimator.swift; sourceTree = "<group>"; };
CDC3F857269460E600AAE3BF /* PromotionMediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PromotionMediumWidgetView.swift; sourceTree = "<group>"; };
CDC6124E25E7964700188DA7 /* TodayDayTimesCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayDayTimesCell.swift; sourceTree = "<group>"; };
CDC6125225E79C8F00188DA7 /* DayTimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayTimeView.swift; sourceTree = "<group>"; };
......@@ -559,6 +554,7 @@
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>"; };
CDD4C439271971AC0025481A /* SubscriptionPopUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionPopUpViewController.swift; sourceTree = "<group>"; };
CDD75F0E25DE68B10099ACDB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
CDDCD50626809F6D00E089AD /* ShortsSwipeHelperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortsSwipeHelperView.swift; sourceTree = "<group>"; };
CDDCD5082680C18B00E089AD /* ShortsUnreadNudgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortsUnreadNudgeView.swift; sourceTree = "<group>"; };
......@@ -865,7 +861,6 @@
CD8579692671FA8100CC4CDA /* ShortsCoordinator.swift */,
CE6E410726EBA7C0009829AE /* SubscriptionCoordinator.swift */,
CED4D66A26ED6A5E00ECF479 /* SubscriptionOverviewCoordinator.swift */,
CDC2E23E27184C4F002B6826 /* SubscriptionPopUpCoordinator.swift */,
);
path = Coordinators;
sourceTree = "<group>";
......@@ -1334,15 +1329,6 @@
path = SharedCells;
sourceTree = "<group>";
};
CDC2E240271854AE002B6826 /* Animators */ = {
isa = PBXGroup;
children = (
CDC2E241271854D0002B6826 /* StorePresentationAnimator.swift */,
CDC2E243271854EA002B6826 /* StoreDismissAnimator.swift */,
);
path = Animators;
sourceTree = "<group>";
};
CDC6124D25E7960D00188DA7 /* TodayDayTimesCell */ = {
isa = PBXGroup;
children = (
......@@ -1577,10 +1563,10 @@
CE6E410126EBA386009829AE /* Subscriptions */ = {
isa = PBXGroup;
children = (
CDC2E240271854AE002B6826 /* Animators */,
CE6E410426EBA3B4009829AE /* Views */,
CE6E410226EBA3B0009829AE /* SubscriptionStoreViewController.swift */,
CE6E410526EBA3EB009829AE /* SubscriptionOverviewViewController.swift */,
CDD4C439271971AC0025481A /* SubscriptionPopUpViewController.swift */,
);
path = Subscriptions;
sourceTree = "<group>";
......@@ -2274,7 +2260,6 @@
CD8B60B626381E0F0055CB3F /* AdsUserDefaultsWrapper.swift in Sources */,
CD9B6B1425DBCDE2001D9B80 /* GraphView.swift in Sources */,
CD866A6F260F67F200E96A5C /* SettingsDetailsViewModel.swift in Sources */,
CDC2E242271854D0002B6826 /* StorePresentationAnimator.swift in Sources */,
CD71709025FA317700A63C27 /* ForecastTimePeriodView.swift in Sources */,
CE13B812262480B3007CBD4D /* NativeAdItem.swift in Sources */,
CE6E410826EBA7C0009829AE /* SubscriptionCoordinator.swift in Sources */,
......@@ -2292,6 +2277,7 @@
CDC6125725E7AB1A00188DA7 /* TodayAirQualityCell.swift in Sources */,
CD8B60AE263819400055CB3F /* NWSAlertViewController.swift in Sources */,
CE6E410326EBA3B0009829AE /* SubscriptionStoreViewController.swift in Sources */,
CDD4C43A271971AC0025481A /* SubscriptionPopUpViewController.swift in Sources */,
CD593BCF2608A50900C93428 /* ForecastHourlyCell.swift in Sources */,
CDB0D4CC2670D12F0081C773 /* TodayShortsCell.swift in Sources */,
CD1DDD332602305200AC62B2 /* ForecastInfoCell.swift in Sources */,
......@@ -2318,7 +2304,6 @@
CE578FE725FB415F00E8B85D /* LocationsViewModel.swift in Sources */,
CD82300A25D6B2AF00A05501 /* AppTabBarController.swift in Sources */,
CE3A9CE326E64F2800E2CB4B /* StoreManager.swift in Sources */,
CDC2E23F27184C4F002B6826 /* SubscriptionPopUpCoordinator.swift in Sources */,
CD85797126721D9800CC4CDA /* UIViewController+Alert.swift in Sources */,
CDC6126225E8DAB800188DA7 /* MoonPhaseCell.swift in Sources */,
CD37D3D6260C93B3002669D6 /* MenuCellFactory.swift in Sources */,
......@@ -2404,7 +2389,6 @@
CD86246C25E6826A0097F3FB /* InnerShadowLayer.swift in Sources */,
CD85797F267221C500CC4CDA /* CACornerMask+All.swift in Sources */,
CE578FE525FB415F00E8B85D /* CityCell.swift in Sources */,
CDC2E244271854EA002B6826 /* StoreDismissAnimator.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -35,7 +35,8 @@ class SubscriptionCoordinator: NSObject, Coordinator {
}
public func startPopUp() {
activeViewController = SubscriptionPopUpViewController(viewModel: self.viewModel)
self.parentViewController.present(activeViewController!, animated: true)
}
private func openOverview() {
......
//
// SubscriptionPopUpCoordinator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 14.10.2021.
//
import Foundation
import UIKit
class SubscriptionPopUpCoordinator: Coordinator {
private let parentViewController: UIViewController
public var childCoordinators = [Coordinator]()
public var parentCoordinator: Coordinator?
public init(parentViewController: UIViewController, storeManager: StoreManager = StoreManager.shared) {
self.parentViewController = parentViewController
}
public func start() {
}
func viewControllerDidEnd(controller: UIViewController) {
parentCoordinator?.childDidFinish(child: self)
}
}
......@@ -15,7 +15,7 @@ protocol TodayCoordinatorDelegate: AnyObject {
class TodayCoordinator: Coordinator {
// MARK: - Private
private let navigationController = ColoredNavigationController(nibName: nil, bundle: nil)
private var tabBarController:UITabBarController?
private var tabBarController: UITabBarController?
var todayViewController: TodayViewController?
// MARK: - Public
......@@ -23,7 +23,7 @@ class TodayCoordinator: Coordinator {
public var childCoordinators = [Coordinator]()
public var parentCoordinator: Coordinator?
public init(tabBarController:UITabBarController) {
public init(tabBarController: UITabBarController) {
self.tabBarController = tabBarController
}
......@@ -65,6 +65,17 @@ class TodayCoordinator: Coordinator {
onboardingCoordinator.start()
}
public func openSubscriptionStorePopUp() {
guard let parentController = self.tabBarController else {
return
}
let subscriptionCoordinator = SubscriptionCoordinator(parentViewController: parentController)
subscriptionCoordinator.parentCoordinator = self
childCoordinators.append(subscriptionCoordinator)
subscriptionCoordinator.startPopUp()
}
public func viewControllerDidEnd(controller: UIViewController) {
parentCoordinator?.childDidFinish(child: self)
}
......
......@@ -36,7 +36,7 @@ public class PushNotificationsManager: NSObject, PushNotificationsManagerProtoco
// TODO: forced re-register on timeout
public func registerForRemoteNotifications() {
public func registerForRemoteNotifications(completion: (() -> Void)? = nil) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { [weak self]
(granted, error) in
guard let self = self else { return }
......@@ -49,6 +49,7 @@ public class PushNotificationsManager: NSObject, PushNotificationsManagerProtoco
onMain {
MoEngage.sharedInstance().registerForRemoteNotification(withCategories: nil, withUserNotificationCenterDelegate: self)
completion?()
}
}
}
......
//
// StoreDismissAnimator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 14.10.2021.
//
import Foundation
//
// StorePresentationAnimator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 14.10.2021.
//
import UIKit
class StorePresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let toViewController = transitionContext.viewController(forKey: .to) else {
return
}
let container = transitionContext.containerView
let heightDiff = container.bounds.height * 0.3 //30% from container height
let widthDiff = container.bounds.width * 0.124 //12.4% from container width
let targetHeight = container.bounds.height - heightDiff
let targetWidth = container.bounds.width - widthDiff
toViewController.view.frame = .init(x: (container.bounds.width - targetWidth) / 2,
y: container.bounds.height,
width: targetWidth,
height: targetHeight)
container.addSubview(toViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
toViewController.view.frame.origin.y = (container.bounds.height - targetHeight) / 2
} completion: { finished in
transitionContext.completeTransition(finished)
}
}
}
//
// SubscriptionPopUpViewController.swift
// 1Weather
//
// Created by Dmitry Stepanets on 15.10.2021.
//
import UIKit
import OneWeatherCore
class SubscriptionPopUpViewController: UIViewController {
private let storeViewController: SubscriptionStoreViewController
init(viewModel: SubscriptionViewModel) {
self.storeViewController = SubscriptionStoreViewController(viewModel: viewModel)
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .overCurrentContext
modalTransitionStyle = .crossDissolve
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
prepareControler()
prepareStoreController()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
storeViewController.view.snp.updateConstraints { update in
let diffHeight = view.bounds.height - storeViewController.view.bounds.height
let offset = storeViewController.view.bounds.height + diffHeight / 2
update.top.equalTo(view.snp.bottom).offset(-offset)
}
UIView.animate(withDuration: 0.2) {
self.view.layoutIfNeeded()
}
Settings.shared.initialSubscriptionShowed = true
}
}
private extension SubscriptionPopUpViewController {
func prepareControler() {
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
}
func prepareStoreController() {
storeViewController.view.clipsToBounds = true
storeViewController.view.layer.cornerRadius = 12
view.addSubview(storeViewController.view)
addChild(storeViewController)
storeViewController.didMove(toParent: self)
//Constraints
storeViewController.view.snp.makeConstraints { make in
make.width.equalToSuperview().multipliedBy(0.87)
make.height.equalToSuperview().multipliedBy(0.9)
make.centerX.equalToSuperview()
make.top.equalTo(view.snp.bottom)
}
}
}
......@@ -27,20 +27,22 @@ public class SubscriptionStoreViewController: UIViewController {
init(viewModel: SubscriptionViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
}
@available(*, unavailable)
required init?(coder: NSCoder) { return nil }
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.scrollView.contentSize = self.scrollViewContent.bounds.size
}
public override func viewDidLoad() {
super.viewDidLoad()
prepareViewController()
prepareScrollView()
rebuildUI()
}
}
//MARK: - UI Setup
......@@ -158,14 +160,3 @@ extension SubscriptionStoreViewController: SubscriptionPurchaseButtonDelegate {
viewModel.purchase(subscription: product)
}
}
//MARK: Transitioning Delegate
extension SubscriptionStoreViewController: UIViewControllerTransitioningDelegate {
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return StorePresentationAnimator()
}
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
}
......@@ -175,6 +175,10 @@ extension TodayViewController: TodayViewModelDelegate {
coordinator.openOnboarding()
}
func showSubscriptionPopup(viewModel: TodayViewModel) {
coordinator.openSubscriptionStorePopUp()
}
func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
cityButton.configure(with: viewModel.location)
cityButton.isHidden = false
......
......@@ -14,6 +14,7 @@ import AppTrackingTransparency
protocol TodayViewModelDelegate: ViewModelDelegate {
func showOnboarding(viewModel: TodayViewModel)
func showPrivacyNotice(viewModel: TodayViewModel)
func showSubscriptionPopup(viewModel: TodayViewModel)
}
class TodayViewModel: ViewModelProtocol {
......@@ -96,7 +97,12 @@ class TodayViewModel: ViewModelProtocol {
private func onboardingFlowCompleted() {
self.initializeAllAdsIfNeeded()
PushNotificationsManager.shared.registerForRemoteNotifications()
PushNotificationsManager.shared.registerForRemoteNotifications(completion: { [weak self] in
guard let self = self else { return }
if !Settings.shared.initialSubscriptionShowed && CCPAHelper.shared.isNewUser {
self.delegate?.showSubscriptionPopup(viewModel: self)
}
})
analytics(log: .ANALYTICS_VIEW_TODAY)
}
......
......@@ -101,6 +101,9 @@ public class Settings {
@UserDefaultsBasicValue(key: "shorts_showed_swipeUp_count", userDefaults: UserDefaults.appDefaults)
public var shortsSwipeUpNudgeShowedCount = 0
@UserDefaultsBasicValue(key: "initial_subscription_showed", userDefaults: UserDefaults.appDefaults)
public var initialSubscriptionShowed = false
#warning("Not implemented!")
//TODO: implement store in UserDefaults and configure via UI in debug builds.
public var adLogging: Bool = true
......
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