diff --git a/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.h b/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.h index 4ebd675327..2e30b2667a 100644 --- a/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.h +++ b/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.h @@ -17,7 +17,9 @@ typedef void (^ValidateReceiptCallback)(NSString * _Nonnull serverId, MWMValidat + (MWMPurchaseManager * _Nonnull)sharedManager; - (void)validateReceipt:(NSString * _Nonnull)serverId + refreshReceipt:(BOOL)refresh callback:(ValidateReceiptCallback _Nonnull)callback; - (void)setAdsDisabled:(BOOL)disabled; +- (void)refreshReceipt; @end diff --git a/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.mm b/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.mm index 929cd7d68d..b3f746e12b 100644 --- a/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.mm +++ b/iphone/Maps/Core/Subscriptions/MWMPurchaseManager.mm @@ -1,16 +1,15 @@ #import "MWMPurchaseManager.h" #include "Framework.h" -#include "Private.h" +#include "private.h" #import @interface MWMPurchaseManager() -@property (nonatomic) BOOL didRefreshReceipt; -@property (nonatomic, copy) ValidateReceiptCallback callback; -@property (nonatomic) SKReceiptRefreshRequest *receiptRequest; -@property (nonatomic, copy) NSString * serverId; +@property(nonatomic, copy) ValidateReceiptCallback callback; +@property(nonatomic) SKReceiptRefreshRequest *receiptRequest; +@property(nonatomic, copy) NSString * serverId; @end @@ -48,24 +47,28 @@ self.receiptRequest = [[SKReceiptRefreshRequest alloc] init]; self.receiptRequest.delegate = self; [self.receiptRequest start]; - self.didRefreshReceipt = YES; } -- (void)validateReceipt:(NSString *)serverId callback:(ValidateReceiptCallback)callback +- (void)validateReceipt:(NSString *)serverId + refreshReceipt:(BOOL)refresh + callback:(ValidateReceiptCallback)callback { self.callback = callback; self.serverId = serverId; - [self validateReceipt]; + [self validateReceipt:refresh]; } -- (void)validateReceipt +- (void)validateReceipt:(BOOL)refresh { NSURL * receiptUrl = [NSBundle mainBundle].appStoreReceiptURL; NSData * receiptData = [NSData dataWithContentsOfURL:receiptUrl]; if (!receiptData) { - [self noReceipt]; + if (refresh) + [self refreshReceipt]; + else + [self noReceipt]; return; } @@ -130,7 +133,7 @@ - (void)requestDidFinish:(SKRequest *)request { - [self validateReceipt]; + [self validateReceipt:NO]; } - (void)request:(SKRequest *)request didFailWithError:(NSError *)error diff --git a/iphone/Maps/Core/Subscriptions/SubscriptionManager.swift b/iphone/Maps/Core/Subscriptions/SubscriptionManager.swift index fe729ed189..19dc7774d9 100644 --- a/iphone/Maps/Core/Subscriptions/SubscriptionManager.swift +++ b/iphone/Maps/Core/Subscriptions/SubscriptionManager.swift @@ -8,6 +8,7 @@ class SubscriptionManager: NSObject { typealias SuscriptionsCompletion = ([ISubscription]?, Error?) -> Void + typealias RestorationCompletion = (MWMValidationResult) -> Void @objc static var shared: SubscriptionManager = { return SubscriptionManager() }() @@ -18,6 +19,7 @@ class SubscriptionManager: NSObject { private var products: [String: SKProduct]? private var pendingSubscription: ISubscription? private var listeners = NSHashTable.weakObjects() + private var restorationCallback: RestorationCompletion? override private init() { super.init() @@ -54,10 +56,22 @@ class SubscriptionManager: NSObject { } @objc func validate() { + validate(false) + } + + @objc func restore(_ callback: @escaping RestorationCompletion) { + restorationCallback = callback + validate(true) + } + + private func validate(_ refreshReceipt: Bool) { MWMPurchaseManager.shared() - .validateReceipt(MWMPurchaseManager.adsRemovalServerId()) { (serverId, validationResult) in + .validateReceipt(MWMPurchaseManager.adsRemovalServerId(), + refreshReceipt: refreshReceipt) { (serverId, validationResult) in if validationResult == .error { Statistics.logEvent(kStatInappValidationError, withParameters: [kStatErrorCode : 2]) + self.restorationCallback?(.error) + self.restorationCallback = nil return } else { if validationResult == .valid { @@ -71,6 +85,8 @@ class SubscriptionManager: NSObject { self.paymentQueue.transactions .filter { $0.transactionState == .purchased || $0.transactionState == .restored } .forEach { self.paymentQueue.finishTransaction($0) } + self.restorationCallback?(validationResult) + self.restorationCallback = nil } } } @@ -114,7 +130,7 @@ extension SubscriptionManager: SKPaymentTransactionObserver { .forEach { processPurchased($0) } transactions.filter { $0.transactionState == .restored } .forEach { processRestored($0) } - validate() + validate(false) } transactions.filter { $0.transactionState == .deferred } diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 982799f128..e753233a15 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -354,6 +354,7 @@ 472E3F472146BCD30020E412 /* SubscriptionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472E3F462146BCD30020E412 /* SubscriptionManager.swift */; }; 472E3F4A2146C4CD0020E412 /* MWMPurchaseManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 472E3F492146C4CD0020E412 /* MWMPurchaseManager.mm */; }; 472E3F4C2147D5700020E412 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472E3F4B2147D5700020E412 /* Subscription.swift */; }; + 473CBF9B2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */; }; 474AC76C2139E4F2002F9BF9 /* RemoveAdsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */; }; 474AC76D2139E4F2002F9BF9 /* RemoveAdsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */; }; 474C9F5A213FF75800369009 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474C9F59213FF75800369009 /* StoreKit.framework */; }; @@ -1339,6 +1340,7 @@ 472E3F482146C4CD0020E412 /* MWMPurchaseManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMPurchaseManager.h; sourceTree = ""; }; 472E3F492146C4CD0020E412 /* MWMPurchaseManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPurchaseManager.mm; sourceTree = ""; }; 472E3F4B2147D5700020E412 /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = ""; }; + 473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSelectableProgressCell.swift; sourceTree = ""; }; 474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsViewController.swift; sourceTree = ""; }; 474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RemoveAdsViewController.xib; sourceTree = ""; }; 474C9F59213FF75800369009 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; @@ -4122,6 +4124,7 @@ F6E2FD381E097BA00083EBEC /* SettingsTableViewLinkCell.swift */, F6E2FD391E097BA00083EBEC /* SettingsTableViewSelectableCell.swift */, F6E2FD3A1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift */, + 473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */, ); path = Cells; sourceTree = ""; @@ -4753,6 +4756,7 @@ 47E3C7292111E614008B3B27 /* FadeInAnimatedTransitioning.swift in Sources */, 34AB667D1FC5AA330078E451 /* MWMRoutePreview.mm in Sources */, B33D21AC20DA515800BAD749 /* MWMCategoryInfoCell.mm in Sources */, + 473CBF9B2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift in Sources */, 47E3C72D2111E6A2008B3B27 /* FadeTransitioning.swift in Sources */, 34845DAF1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift in Sources */, 474C9F632141896800369009 /* MWMEye.mm in Sources */, diff --git a/iphone/Maps/UI/Settings/Cells/SettingsTableViewSelectableProgressCell.swift b/iphone/Maps/UI/Settings/Cells/SettingsTableViewSelectableProgressCell.swift new file mode 100644 index 0000000000..be9fc23558 --- /dev/null +++ b/iphone/Maps/UI/Settings/Cells/SettingsTableViewSelectableProgressCell.swift @@ -0,0 +1,18 @@ +@objc +final class SettingsTableViewSelectableProgressCell: MWMTableViewCell { + @IBOutlet private weak var title: UILabel! + @IBOutlet weak var progress: UIActivityIndicatorView! + + @objc func config(title: String) { + backgroundColor = UIColor.white() + progress.activityIndicatorViewStyle = UIColor.isNightMode() ? .white : .gray + + self.title.text = title + styleTitle() + } + + fileprivate func styleTitle() { + title.textColor = UIColor.blackPrimaryText() + title.font = UIFont.regular17() + } +} diff --git a/iphone/Maps/UI/Settings/MWMSettingsViewController.mm b/iphone/Maps/UI/Settings/MWMSettingsViewController.mm index 5dd571f791..59a380df40 100644 --- a/iphone/Maps/UI/Settings/MWMSettingsViewController.mm +++ b/iphone/Maps/UI/Settings/MWMSettingsViewController.mm @@ -36,6 +36,9 @@ extern NSString * const kAlohalyticsTapEventKey; @property(weak, nonatomic) IBOutlet SettingsTableViewLinkCell * helpCell; @property(weak, nonatomic) IBOutlet SettingsTableViewLinkCell * aboutCell; +@property(weak, nonatomic) IBOutlet SettingsTableViewSelectableProgressCell *restoreSubscriptionCell; + +@property(nonatomic) BOOL restoringSubscription; @end @@ -186,6 +189,7 @@ extern NSString * const kAlohalyticsTapEventKey; { [self.helpCell configWithTitle:L(@"help") info:nil]; [self.aboutCell configWithTitle:L(@"about_menu_title") info:nil]; + [self.restoreSubscriptionCell configWithTitle:L(@"restore_subscription")]; } #pragma mark - SettingsTableViewSwitchCellDelegate @@ -281,7 +285,7 @@ extern NSString * const kAlohalyticsTapEventKey; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - auto cell = static_cast([tableView cellForRowAtIndexPath:indexPath]); + auto cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell == self.profileCell) { [Statistics logEvent:kStatSettingsOpenSection withParameters:@{kStatName : kStatAuthorization}]; @@ -328,6 +332,42 @@ extern NSString * const kAlohalyticsTapEventKey; [Statistics logEvent:kStatSettingsOpenSection withParameters:@{kStatName : kStatAbout}]; [self performSegueWithIdentifier:@"SettingsToAbout" sender:nil]; } + else if (cell == self.restoreSubscriptionCell) + { + self.restoreSubscriptionCell.selected = false; + [self.restoreSubscriptionCell.progress startAnimating]; + self.restoringSubscription = YES; + __weak auto s = self; + [[SubscriptionManager shared] restore:^(MWMValidationResult result) { + __strong auto self = s; + self.restoringSubscription = NO; + [self.restoreSubscriptionCell.progress stopAnimating]; + NSString *alertText; + switch (result) + { + case MWMValidationResultValid: + alertText = L(@"restore_success_alert"); + break; + case MWMValidationResultNotValid: + alertText = L(@"restore_no_subscription_alert"); + break; + case MWMValidationResultError: + alertText = L(@"restore_error_alert"); + break; + } + [MWMAlertViewController.activeAlertController presentInfoAlert:L(@"restore_subscription") + text:alertText]; + }]; + } +} + +- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + auto cell = [tableView cellForRowAtIndexPath:indexPath]; + if (cell == self.restoreSubscriptionCell) + return self.restoringSubscription ? nil : indexPath; + + return indexPath; } #pragma mark - UITableViewDataSource diff --git a/iphone/Maps/UI/Storyboard/Settings.storyboard b/iphone/Maps/UI/Storyboard/Settings.storyboard index ca1c7d900f..ef90f81360 100644 --- a/iphone/Maps/UI/Storyboard/Settings.storyboard +++ b/iphone/Maps/UI/Storyboard/Settings.storyboard @@ -1,12 +1,11 @@ - + - - + @@ -30,13 +29,13 @@ - + @@ -179,7 +178,7 @@ - + @@ -213,7 +212,7 @@ - + @@ -240,13 +239,13 @@ - + @@ -385,7 +384,7 @@ - + @@ -419,7 +418,7 @@ - + @@ -453,7 +452,7 @@ - + @@ -480,17 +479,17 @@ - + - + @@ -560,7 +559,7 @@ - + @@ -583,17 +582,17 @@ - +