Commit f1cc460a by Dmitry Stepanets

- Added missing UI for subscriptions

- Changed subscription verify logic
parent 8980fc87
...@@ -164,6 +164,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -164,6 +164,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidBecomeActive(_ application: UIApplication) { func applicationDidBecomeActive(_ application: UIApplication) {
LocationManager.shared.updateEverythingIfNeeded() LocationManager.shared.updateEverythingIfNeeded()
storeManager.verifySubscriptions()
if #available(iOS 14, *) { if #available(iOS 14, *) {
WidgetManager.shared.refreshAnalytics() WidgetManager.shared.refreshAnalytics()
......
...@@ -173,7 +173,7 @@ public class StoreManager { ...@@ -173,7 +173,7 @@ public class StoreManager {
public func purchase(product: SKProduct, completion: @escaping (Bool) -> ()) { public func purchase(product: SKProduct, completion: @escaping (Bool) -> ()) {
let log = self.log let log = self.log
log.info("Purchase \(product.productIdentifier) start (SK).") log.info("Purchase \(product.productIdentifier) start (SK).")
SwiftyStoreKit.purchaseProduct(product) { result in SwiftyStoreKit.purchaseProduct(product, atomically: true) { result in
switch result { switch result {
case .success(let product): case .success(let product):
if product.needsFinishTransaction { if product.needsFinishTransaction {
...@@ -196,6 +196,7 @@ public class StoreManager { ...@@ -196,6 +196,7 @@ public class StoreManager {
#else #else
service = .production service = .production
#endif #endif
let appleValidator = AppleReceiptValidator(service: service, sharedSecret: StoreManager.sharedSecret) let appleValidator = AppleReceiptValidator(service: service, sharedSecret: StoreManager.sharedSecret)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result { switch result {
...@@ -211,6 +212,7 @@ public class StoreManager { ...@@ -211,6 +212,7 @@ public class StoreManager {
} }
case .expired(let expiryDate, let items): case .expired(let expiryDate, let items):
log.debug("Subscription expired since \(expiryDate)\n\(items)\n") log.debug("Subscription expired since \(expiryDate)\n\(items)\n")
self.hasSubscription = false
self.everHadSubscription = true self.everHadSubscription = true
case .notPurchased: case .notPurchased:
log.debug("The user has never purchased a subscription.") log.debug("The user has never purchased a subscription.")
...@@ -219,6 +221,9 @@ public class StoreManager { ...@@ -219,6 +221,9 @@ public class StoreManager {
} }
case .error(let error): case .error(let error):
log.error("Receipt verification failed: \(error)") log.error("Receipt verification failed: \(error)")
self.hasSubscription = false
self.everHadSubscription = false
self.subscriptionExpirationDate = nil
} }
} }
} }
......
{
"images" : [
{
"filename" : "menu_crown.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
...@@ -193,10 +193,13 @@ ...@@ -193,10 +193,13 @@
//Menu //Menu
"menu.goPremium" = "Go Premium"; "menu.goPremium" = "Go Premium";
"menu.upgradeTo" = "Upgrade to";
"menu.premiumMembership" = "Premium\nMembership";
"menu.premium.desc" = "Subcribe to 1Weather premium for a unique experience."; "menu.premium.desc" = "Subcribe to 1Weather premium for a unique experience.";
"menu.tv" = "1Weather TV"; "menu.tv" = "1Weather TV";
"menu.radar" = "Radar"; "menu.radar" = "Radar";
"menu.buyNow" = "Buy now"; "menu.buyNow" = "Buy now";
"menu.upgradeNow" = "Upgrade now";
"menu.settings" = "Settings"; "menu.settings" = "Settings";
"menu.subscriptionOverview" = "Premium"; "menu.subscriptionOverview" = "Premium";
"menu.about" = "About us"; "menu.about" = "About us";
......
...@@ -37,9 +37,7 @@ public enum MenuRow { ...@@ -37,9 +37,7 @@ public enum MenuRow {
case .deviceId: case .deviceId:
return UIImage(named: "menu_device_id") return UIImage(named: "menu_device_id")
case .subscriptionOverview: case .subscriptionOverview:
return nil return UIImage(named: "menu_crown")
#warning("Not implemented!")
//TODO: Implement!
} }
} }
...@@ -108,23 +106,7 @@ private struct SectionItem { ...@@ -108,23 +106,7 @@ private struct SectionItem {
class MenuCellFactory<T>: CellFactory { class MenuCellFactory<T>: CellFactory {
//Private //Private
private let menuViewModel:MenuViewModel private let menuViewModel:MenuViewModel
private let sections: [SectionItem] = { private var sections = [SectionItem]()
let infoSectionItem: SectionItem
if StoreManager.shared.hasSubscription {
infoSectionItem = SectionItem(type: .info,
rows: [.settings, .subscriptionOverview])
}
else {
infoSectionItem = SectionItem(type: .info,
rows: [.settings])
}
let settingsSectionItem = SectionItem(type: .settings,
rows: [.about, .ad, .help, .faq, .privacy, .deviceId])
return [infoSectionItem, settingsSectionItem]
}()
//Public //Public
public var kSectionHeight:CGFloat { public var kSectionHeight:CGFloat {
...@@ -139,6 +121,24 @@ class MenuCellFactory<T>: CellFactory { ...@@ -139,6 +121,24 @@ class MenuCellFactory<T>: CellFactory {
init(viewModel: MenuViewModel) { init(viewModel: MenuViewModel) {
self.menuViewModel = viewModel self.menuViewModel = viewModel
reload()
}
public func reload() {
let infoSectionItem: SectionItem
if StoreManager.shared.hasSubscription {
infoSectionItem = SectionItem(type: .info,
rows: [.settings, .subscriptionOverview])
}
else {
infoSectionItem = SectionItem(type: .info,
rows: [.settings])
}
let settingsSectionItem = SectionItem(type: .settings,
rows: [.about, .ad, .help, .faq, .privacy, .deviceId])
self.sections = [infoSectionItem, settingsSectionItem]
} }
public func numberOfRows(inSection section:Int) -> Int { public func numberOfRows(inSection section:Int) -> Int {
......
...@@ -12,7 +12,7 @@ class MenuHeaderView: UIView { ...@@ -12,7 +12,7 @@ class MenuHeaderView: UIView {
private let premiumContainer = UIView() private let premiumContainer = UIView()
private let premiumHeadingLabel = UILabel() private let premiumHeadingLabel = UILabel()
private let premiumDescriptionLabel = UILabel() private let premiumDescriptionLabel = UILabel()
private let buyButton = UIButton() private let buyButton = SelfSizingButton()
private let premiumImageView = UIImageView() private let premiumImageView = UIImageView()
public var onTapBuy: (() -> ())? public var onTapBuy: (() -> ())?
...@@ -64,36 +64,55 @@ private extension MenuHeaderView { ...@@ -64,36 +64,55 @@ private extension MenuHeaderView {
premiumContainer.addSubview(premiumImageView) premiumContainer.addSubview(premiumImageView)
premiumHeadingLabel.textColor = .white premiumHeadingLabel.textColor = .white
premiumHeadingLabel.font = AppFont.SFPro.bold(size: 23)
premiumHeadingLabel.text = "menu.goPremium".localized()
premiumHeadingLabel.setContentHuggingPriority(.fittingSizeLevel, for: .vertical) premiumHeadingLabel.setContentHuggingPriority(.fittingSizeLevel, for: .vertical)
premiumContainer.addSubview(premiumHeadingLabel) premiumContainer.addSubview(premiumHeadingLabel)
let descParagpraphStyle = NSMutableParagraphStyle()
descParagpraphStyle.minimumLineHeight = 20
let descriptionAttrString = NSAttributedString(string: "menu.premium.desc".localized(),
attributes: [.foregroundColor : UIColor.white,
.paragraphStyle : descParagpraphStyle,
.font : AppFont.SFPro.regular(size: 14)])
premiumDescriptionLabel.lineBreakMode = .byWordWrapping premiumDescriptionLabel.lineBreakMode = .byWordWrapping
premiumDescriptionLabel.numberOfLines = 0 premiumDescriptionLabel.numberOfLines = 0
premiumDescriptionLabel.attributedText = descriptionAttrString
premiumDescriptionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) premiumDescriptionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
premiumContainer.addSubview(premiumDescriptionLabel) premiumContainer.addSubview(premiumDescriptionLabel)
buyButton.backgroundColor = .white buyButton.backgroundColor = .white
buyButton.setTitle("menu.buyNow".localized(), for: .normal) buyButton.titleEdgeInsets = .init(top: 0, left: 10, bottom: 0, right: 10)
buyButton.setTitleColor(ThemeManager.currentTheme.graphTintColor, for: .normal) buyButton.setTitleColor(ThemeManager.currentTheme.graphTintColor, for: .normal)
buyButton.titleLabel?.font = AppFont.SFPro.semibold(size: 15) buyButton.titleLabel?.font = AppFont.SFPro.semibold(size: 15)
buyButton.layer.cornerRadius = 4 buyButton.layer.cornerRadius = 4
buyButton.addTarget(self, action: #selector(handleBuyButton), for: .touchUpInside) buyButton.addTarget(self, action: #selector(handleBuyButton), for: .touchUpInside)
premiumContainer.addSubview(buyButton) premiumContainer.addSubview(buyButton)
if StoreManager.shared.removeAdsPurchased {
premiumHeadingLabel.font = AppFont.SFPro.regular(size: 16)
premiumHeadingLabel.text = "menu.upgradeTo".localized()
let descParagpraphStyle = NSMutableParagraphStyle()
descParagpraphStyle.minimumLineHeight = 20
let descriptionAttrString = NSAttributedString(string: "menu.premiumMembership".localized(),
attributes: [.foregroundColor : UIColor.white,
.paragraphStyle : descParagpraphStyle,
.font : AppFont.SFPro.bold(size: 24)])
premiumDescriptionLabel.attributedText = descriptionAttrString
buyButton.setTitle("menu.upgradeNow".localized(), for: .normal)
}
else {
premiumHeadingLabel.font = AppFont.SFPro.bold(size: 23)
premiumHeadingLabel.text = "menu.goPremium".localized()
let descParagpraphStyle = NSMutableParagraphStyle()
descParagpraphStyle.minimumLineHeight = 20
let descriptionAttrString = NSAttributedString(string: "menu.premium.desc".localized(),
attributes: [.foregroundColor : UIColor.white,
.paragraphStyle : descParagpraphStyle,
.font : AppFont.SFPro.regular(size: 14)])
premiumDescriptionLabel.attributedText = descriptionAttrString
buyButton.setTitle("menu.buyNow".localized(), for: .normal)
}
//Constraints //Constraints
premiumContainer.snp.makeConstraints { (make) in premiumContainer.snp.makeConstraints { (make) in
make.top.equalTo(30) make.top.equalTo(30)
make.left.right.equalToSuperview().inset(18).priority(999) make.left.right.equalToSuperview().inset(18).priority(999)
make.height.equalTo(180)
make.bottom.equalToSuperview().inset(30) make.bottom.equalToSuperview().inset(30)
} }
...@@ -115,7 +134,6 @@ private extension MenuHeaderView { ...@@ -115,7 +134,6 @@ private extension MenuHeaderView {
} }
buyButton.snp.makeConstraints { (make) in buyButton.snp.makeConstraints { (make) in
make.width.equalTo(100)
make.height.equalTo(35) make.height.equalTo(35)
make.top.equalTo(premiumDescriptionLabel.snp.bottom).offset(18).priority(999) make.top.equalTo(premiumDescriptionLabel.snp.bottom).offset(18).priority(999)
make.left.equalToSuperview().inset(18) make.left.equalToSuperview().inset(18)
......
...@@ -52,12 +52,20 @@ class MenuViewController: UIViewController { ...@@ -52,12 +52,20 @@ class MenuViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
StoreManager.shared.add(observer: self)
prepareController() prepareController()
prepareTableViewHeader() prepareTableViewHeader()
prepareTableView() prepareTableView()
updateUI() updateUI()
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
menuCellFactory.reload()
tableView.reloadData()
}
override func viewDidLayoutSubviews() { override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
tableView.layoutTableHeaderView() tableView.layoutTableHeaderView()
...@@ -155,6 +163,17 @@ extension MenuViewController: UITableViewDelegate { ...@@ -155,6 +163,17 @@ extension MenuViewController: UITableViewDelegate {
} }
} }
//MARK:- StoreManager Observer
extension MenuViewController: StoreManagerObserver {
func storeManagerUpdatedStatus(_ storeManager: StoreManager) {
onMain {
self.menuCellFactory.reload()
self.tableView.reloadData()
}
}
}
//MARK:- MenuViewModel Delegate
extension MenuViewController: MenuViewModelDelegate { extension MenuViewController: MenuViewModelDelegate {
func viewModelDidChange<P: ViewModelProtocol>(model:P) { func viewModelDidChange<P: ViewModelProtocol>(model:P) {
onMain { onMain {
......
...@@ -31,6 +31,9 @@ class SubscriptionOverviewViewController: UIViewController { ...@@ -31,6 +31,9 @@ class SubscriptionOverviewViewController: UIViewController {
prepareViewController() prepareViewController()
prepareFooter() prepareFooter()
prepareScrollView() prepareScrollView()
//Verify new subscription
StoreManager.shared.verifySubscriptions()
} }
} }
...@@ -54,7 +57,7 @@ extension SubscriptionOverviewViewController { ...@@ -54,7 +57,7 @@ extension SubscriptionOverviewViewController {
scrollViewContent.addSubview(topHeaderView) scrollViewContent.addSubview(topHeaderView)
topHeaderView.snp.makeConstraints { make in topHeaderView.snp.makeConstraints { make in
make.top.equalToSuperview() make.top.equalToSuperview()
make.left.right.equalToSuperview().inset(24) make.left.right.equalToSuperview()
} }
scrollViewContent.addSubview(descriptionView) scrollViewContent.addSubview(descriptionView)
......
...@@ -134,7 +134,9 @@ extension SubscriptionStoreViewController: SubscriptionPurchaseButtonDelegate { ...@@ -134,7 +134,9 @@ extension SubscriptionStoreViewController: SubscriptionPurchaseButtonDelegate {
extension SubscriptionStoreViewController: SubscriptionViewModelDelegate { extension SubscriptionStoreViewController: SubscriptionViewModelDelegate {
func viewModel(_ vm: SubscriptionViewModel, finishedSubscriptionPurchaseWithResult result: Bool) { func viewModel(_ vm: SubscriptionViewModel, finishedSubscriptionPurchaseWithResult result: Bool) {
if result { if result {
coordinator.openOverview() self.dismiss(animated: true) {
self.coordinator.openOverview()
}
} }
} }
} }
...@@ -119,6 +119,7 @@ class SubscriptionDescriptionView: UIView { ...@@ -119,6 +119,7 @@ class SubscriptionDescriptionView: UIView {
let label = UILabel() let label = UILabel()
view.addSubview(label) view.addSubview(label)
label.textColor = .black
label.font = AppFont.SFPro.semibold(size: 10) label.font = AppFont.SFPro.semibold(size: 10)
label.text = "subscription.description.items.adFree.forever".localized() label.text = "subscription.description.items.adFree.forever".localized()
...@@ -154,6 +155,7 @@ class SubscriptionDescriptionView: UIView { ...@@ -154,6 +155,7 @@ class SubscriptionDescriptionView: UIView {
let label = UILabel() let label = UILabel()
view.addSubview(label) view.addSubview(label)
label.textColor = .black
label.font = AppFont.SFPro.semibold(size: 10) label.font = AppFont.SFPro.semibold(size: 10)
label.text = "subscription.description.items.comingSoon".localized() label.text = "subscription.description.items.comingSoon".localized()
......
...@@ -90,7 +90,7 @@ private extension SubscriptionProDescriptionView { ...@@ -90,7 +90,7 @@ private extension SubscriptionProDescriptionView {
discountMarkerView.backgroundColor = UIColor(hex: 0xffc933) discountMarkerView.backgroundColor = UIColor(hex: 0xffc933)
proUsersContainer.addSubview(discountMarkerView) proUsersContainer.addSubview(discountMarkerView)
discountLabel.textColor = ThemeManager.currentTheme.primaryTextColor discountLabel.textColor = .black
discountLabel.font = AppFont.SFPro.bold(size: 14) discountLabel.font = AppFont.SFPro.bold(size: 14)
discountLabel.text = "subscription.description.discount".localizedFormat("30%") discountLabel.text = "subscription.description.discount".localizedFormat("30%")
discountMarkerView.addSubview(discountLabel) discountMarkerView.addSubview(discountLabel)
...@@ -278,7 +278,7 @@ private extension SubscriptionProDescriptionView { ...@@ -278,7 +278,7 @@ private extension SubscriptionProDescriptionView {
let label = UILabel() let label = UILabel()
label.text = text label.text = text
label.font = AppFont.SFPro.semibold(size: 10) label.font = AppFont.SFPro.semibold(size: 10)
label.textColor = .black label.textColor = ThemeManager.currentTheme.primaryTextColor
label.adjustsFontSizeToFitWidth = true label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2 label.minimumScaleFactor = 0.2
......
...@@ -22,7 +22,8 @@ class SubscriptionViewModel: ViewModelProtocol { ...@@ -22,7 +22,8 @@ class SubscriptionViewModel: ViewModelProtocol {
} }
public var isProUser: Bool { public var isProUser: Bool {
storeManager.removeAdsPurchased return true
// storeManager.removeAdsPurchased
} }
public func purchase(subscription: SKProduct) { public func purchase(subscription: SKProduct) {
......
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