[iOS] add restore subscription to settings

This commit is contained in:
Aleksey Belouosv 2018-10-03 15:35:21 +03:00 committed by Daria Volvenkova
parent 9e8e1a328f
commit 7c536943e0
7 changed files with 169 additions and 51 deletions

View file

@ -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

View file

@ -1,16 +1,15 @@
#import "MWMPurchaseManager.h"
#include "Framework.h"
#include "Private.h"
#include "private.h"
#import <StoreKit/StoreKit.h>
@interface MWMPurchaseManager() <SKRequestDelegate>
@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

View file

@ -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<SubscriptionManagerListener>.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 }

View file

@ -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 = "<group>"; };
472E3F492146C4CD0020E412 /* MWMPurchaseManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMPurchaseManager.mm; sourceTree = "<group>"; };
472E3F4B2147D5700020E412 /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = "<group>"; };
473CBF9A2164DD470059BD54 /* SettingsTableViewSelectableProgressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSelectableProgressCell.swift; sourceTree = "<group>"; };
474AC76A2139E4F2002F9BF9 /* RemoveAdsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAdsViewController.swift; sourceTree = "<group>"; };
474AC76B2139E4F2002F9BF9 /* RemoveAdsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RemoveAdsViewController.xib; sourceTree = "<group>"; };
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 = "<group>";
@ -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 */,

View file

@ -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()
}
}

View file

@ -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<SettingsTableViewLinkCell *>([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

View file

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -30,13 +29,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Профиль" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8jb-wX-P4h">
<rect key="frame" x="16" y="12" width="73" height="19"/>
<rect key="frame" x="16" y="12" width="73" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="igortomko" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gix-nv-IcA">
<rect key="frame" x="263" y="12" width="78" height="19"/>
<rect key="frame" x="263" y="12" width="78" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -69,13 +68,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Единицы измерения" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RB1-Nr-K3T">
<rect key="frame" x="16" y="12" width="225" height="19"/>
<rect key="frame" x="16" y="12" width="225" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="Километры " textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZzK-qL-wC4">
<rect key="frame" x="245" y="12" width="96" height="19"/>
<rect key="frame" x="245" y="12" width="96" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -111,7 +110,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="taQ-3Z-nh3">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -145,7 +144,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aMo-Df-9LS">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -179,7 +178,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f8R-Di-osU">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -213,7 +212,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" horizontalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gal-zH-fgo">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -240,13 +239,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Мобильный интернет" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wjW-GA-wVI">
<rect key="frame" x="16" y="12" width="254" height="19"/>
<rect key="frame" x="16" y="12" width="254" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="Никогда" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d32-tz-eSW">
<rect key="frame" x="274" y="12" width="67" height="19"/>
<rect key="frame" x="274" y="12" width="67" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -275,13 +274,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Недавно пройденый путь" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3ew-eh-kVT">
<rect key="frame" x="16" y="12" width="248" height="19"/>
<rect key="frame" x="16" y="12" width="248" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="12 часов " textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E18-yq-nve">
<rect key="frame" x="268" y="12" width="73" height="19"/>
<rect key="frame" x="268" y="12" width="73" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -317,7 +316,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bAw-rB-tR1">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -351,7 +350,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tuY-xc-X6P">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -385,7 +384,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hRC-jd-ViV">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -419,7 +418,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fDF-O1-urS">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -453,7 +452,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Y8g-7o-Lbp">
<rect key="frame" x="310" y="6" width="51" height="31"/>
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -480,17 +479,17 @@
<rect key="frame" x="0.0" y="746.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="QNt-XC-xma" id="fBV-aJ-Mo8">
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ночной режим" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q7P-cj-3tZ">
<rect key="frame" x="16" y="12" width="205" height="19"/>
<rect key="frame" x="16" y="12" width="205" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="Автоматически" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g5c-Yk-svX">
<rect key="frame" x="225" y="12" width="124" height="19"/>
<rect key="frame" x="225" y="12" width="124" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -526,7 +525,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="m0S-BP-FrU">
<rect key="frame" x="310" y="6" width="51" height="31"/>
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -560,7 +559,7 @@
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ipg-f4-K5Q">
<rect key="frame" x="310" y="6" width="51" height="31"/>
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>
@ -583,17 +582,17 @@
<rect key="frame" x="0.0" y="878.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="nED-2n-gN6" id="2oQ-0g-poj">
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Голосовые инструкции" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2v2-mU-aWi">
<rect key="frame" x="16" y="12" width="241" height="19"/>
<rect key="frame" x="16" y="12" width="241" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="Nederlands" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DQG-mX-mR7">
<rect key="frame" x="261" y="12" width="88" height="19"/>
<rect key="frame" x="261" y="12" width="88" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -622,17 +621,17 @@
<rect key="frame" x="0.0" y="970.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JTZ-K9-RVv" id="mHA-wn-hse">
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Справочный центр" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7ty-Jh-0Rp">
<rect key="frame" x="16" y="12" width="329" height="19"/>
<rect key="frame" x="16" y="12" width="329" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vlu-iM-vCC">
<rect key="frame" x="349" y="12" width="0.0" height="19"/>
<rect key="frame" x="349" y="12" width="0.0" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -657,11 +656,11 @@
<rect key="frame" x="0.0" y="1014.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Kv3-pO-jV5" id="8mJ-wm-9uJ">
<rect key="frame" x="0.0" y="0.0" width="349" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="О приложении" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cS1-Lw-pFx">
<rect key="frame" x="16" y="12" width="329" height="19"/>
<rect key="frame" x="16" y="12" width="329" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -672,7 +671,7 @@
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FxV-a4-ylD">
<rect key="frame" x="349" y="12" width="0.0" height="19"/>
<rect key="frame" x="349" y="12" width="0.0" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -693,6 +692,41 @@
<outlet property="title" destination="cS1-Lw-pFx" id="Ca5-KM-OSc"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="SettingsTableViewSelectableCell" id="2pB-bw-TE4" customClass="SettingsTableViewSelectableProgressCell" customModule="maps_me" customModuleProvider="target">
<rect key="frame" x="0.0" y="1058.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2pB-bw-TE4" id="Mjg-FQ-BbL">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Восстановить покупки" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wLQ-ju-cRP">
<rect key="frame" x="16" y="11" width="315" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular17"/>
</userDefinedRuntimeAttributes>
</label>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="lK6-Ad-YkO">
<rect key="frame" x="339" y="12" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<constraints>
<constraint firstItem="wLQ-ju-cRP" firstAttribute="top" secondItem="Mjg-FQ-BbL" secondAttribute="topMargin" constant="3" id="7nA-4k-p6R"/>
<constraint firstAttribute="bottomMargin" secondItem="wLQ-ju-cRP" secondAttribute="bottom" constant="3.5" id="F0Z-fl-5hO"/>
<constraint firstItem="lK6-Ad-YkO" firstAttribute="centerY" secondItem="Mjg-FQ-BbL" secondAttribute="centerY" id="Rum-Fd-UDx"/>
<constraint firstAttribute="trailing" secondItem="lK6-Ad-YkO" secondAttribute="trailing" constant="16" id="fpT-Pq-H6k"/>
<constraint firstItem="wLQ-ju-cRP" firstAttribute="leading" secondItem="Mjg-FQ-BbL" secondAttribute="leading" constant="16" id="jYa-dS-A6o"/>
<constraint firstItem="lK6-Ad-YkO" firstAttribute="leading" secondItem="wLQ-ju-cRP" secondAttribute="trailing" constant="8" id="yq0-bv-4vX"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="progress" destination="lK6-Ad-YkO" id="dgQ-6i-VYz"/>
<outlet property="title" destination="wLQ-ju-cRP" id="clm-e9-wMY"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
@ -717,6 +751,7 @@
<outlet property="perspectiveViewCell" destination="X5R-fv-yd7" id="hCe-Sv-pxD"/>
<outlet property="profileCell" destination="yh8-cr-14c" id="nzT-Um-BHL"/>
<outlet property="recentTrackCell" destination="VyW-Wh-2QX" id="zXx-a3-FBg"/>
<outlet property="restoreSubscriptionCell" destination="2pB-bw-TE4" id="wqz-cu-DZJ"/>
<outlet property="showOffersCell" destination="F1Y-qu-HAo" id="poJ-lN-MJ2"/>
<outlet property="statisticsCell" destination="NOt-bc-7ls" id="OeS-uK-O2Q"/>
<outlet property="transliterationCell" destination="f8Z-Jk-JIR" id="4X8-tt-Wf3"/>
@ -1114,13 +1149,13 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Other" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="arm-Sx-diY">
<rect key="frame" x="16" y="12" width="321" height="20"/>
<rect key="frame" x="16" y="12" width="321" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="300" verticalHuggingPriority="251" horizontalCompressionResistancePriority="700" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8HI-p3-Ef4">
<rect key="frame" x="341" y="12" width="0.0" height="20"/>
<rect key="frame" x="341" y="12" width="0.0" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -1548,7 +1583,7 @@
</userDefinedRuntimeAttributes>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8gZ-CB-BtW">
<rect key="frame" x="302" y="6" width="51" height="31"/>
<rect key="frame" x="302" y="6.5" width="51" height="31"/>
<inset key="insetFor6xAndEarlier" minX="3" minY="-2" maxX="-3" maxY="2"/>
<color key="onTintColor" red="0.1176470588" green="0.58823529409999997" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</switch>