mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-01-18 22:49:10 +00:00
Merge branch 'describe-purchase-extent'
This commit is contained in:
commit
6a52cb313f
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="fEC-GT-W4O">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="fEC-GT-W4O">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@ -27,29 +27,36 @@
|
||||
<scene sceneID="93l-dg-vRI">
|
||||
<objects>
|
||||
<tableViewController id="bQc-2A-qWz" customClass="PurchaseViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="5WE-4Q-uDQ">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="5WE-4Q-uDQ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="PurchaseTableViewCell" id="0XE-hK-4Ro" customClass="PurchaseTableViewCell" customModule="Passepartout" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="28" width="414" height="105"/>
|
||||
<rect key="frame" x="0.0" y="55.5" width="414" height="99"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0XE-hK-4Ro" id="Fe6-eH-sBT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="105"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="99"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dit-R5-2h7">
|
||||
<rect key="frame" x="20" y="20" width="374" height="65"/>
|
||||
<rect key="frame" x="20" y="20" width="374" height="59"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hf0-aN-JRs">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="24.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="34.5" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Price" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="892-go-vOV">
|
||||
<rect key="frame" x="334" y="0.0" width="40" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Description" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gB1-nL-LEc">
|
||||
<rect key="frame" x="0.0" y="44.5" width="374" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<rect key="frame" x="0.0" y="41" width="374" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
@ -58,10 +65,12 @@
|
||||
<constraint firstAttribute="trailing" secondItem="gB1-nL-LEc" secondAttribute="trailing" id="062-HW-sKW"/>
|
||||
<constraint firstItem="gB1-nL-LEc" firstAttribute="leading" secondItem="Dit-R5-2h7" secondAttribute="leading" id="3je-C8-e0v"/>
|
||||
<constraint firstItem="Hf0-aN-JRs" firstAttribute="leading" secondItem="Dit-R5-2h7" secondAttribute="leading" id="7cX-Z8-Z9p"/>
|
||||
<constraint firstAttribute="trailing" secondItem="892-go-vOV" secondAttribute="trailing" id="Dt7-md-WxN"/>
|
||||
<constraint firstItem="Hf0-aN-JRs" firstAttribute="top" secondItem="Dit-R5-2h7" secondAttribute="top" id="FOS-1V-gEv"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Hf0-aN-JRs" secondAttribute="trailing" id="MQl-hH-lvW"/>
|
||||
<constraint firstItem="892-go-vOV" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Hf0-aN-JRs" secondAttribute="trailing" constant="20" id="P3K-6q-k6r"/>
|
||||
<constraint firstItem="gB1-nL-LEc" firstAttribute="top" secondItem="Hf0-aN-JRs" secondAttribute="bottom" constant="20" id="dKT-d6-56g"/>
|
||||
<constraint firstAttribute="bottom" secondItem="gB1-nL-LEc" secondAttribute="bottom" id="h1s-nk-2kw"/>
|
||||
<constraint firstItem="892-go-vOV" firstAttribute="top" secondItem="Dit-R5-2h7" secondAttribute="top" id="tzq-5O-Ntg"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
@ -74,6 +83,7 @@
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="labelDescription" destination="gB1-nL-LEc" id="zIn-g5-Rl0"/>
|
||||
<outlet property="labelPrice" destination="892-go-vOV" id="9Kf-XF-zUy"/>
|
||||
<outlet property="labelTitle" destination="Hf0-aN-JRs" id="E65-5C-zZR"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
|
@ -97,6 +97,18 @@ enum Product: String {
|
||||
// MARK: All
|
||||
|
||||
static let all: [Product] = allDonations + allFeatures + allProviders
|
||||
|
||||
var isDonation: Bool {
|
||||
return Product.allDonations.contains(self)
|
||||
}
|
||||
|
||||
var isFeature: Bool {
|
||||
return Product.allFeatures.contains(self)
|
||||
}
|
||||
|
||||
var isProvider: Bool {
|
||||
return Product.allProviders.contains(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Infrastructure.Name {
|
||||
|
@ -80,6 +80,21 @@ class ProductManager: NSObject {
|
||||
return inApp.product(withIdentifier: identifier)
|
||||
}
|
||||
|
||||
func featureProducts(includingFullVersion: Bool) -> [SKProduct] {
|
||||
return inApp.products.filter {
|
||||
guard let p = Product(rawValue: $0.productIdentifier) else {
|
||||
return false
|
||||
}
|
||||
guard includingFullVersion || p != .fullVersion else {
|
||||
return false
|
||||
}
|
||||
guard p.isFeature else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func purchase(_ product: SKProduct, completionHandler: @escaping (InAppPurchaseResult, Error?) -> Void) {
|
||||
inApp.purchase(product: product) {
|
||||
if $0 == .success {
|
||||
|
@ -82,6 +82,12 @@ internal enum L10n {
|
||||
/// Purchase
|
||||
internal static let title = L10n.tr("App", "purchase.title")
|
||||
internal enum Cells {
|
||||
internal enum FullVersion {
|
||||
/// \n- All providers (including those being added in the future)\n%@
|
||||
internal static func extraDescription(_ p1: String) -> String {
|
||||
return L10n.tr("App", "purchase.cells.full_version.extra_description", p1)
|
||||
}
|
||||
}
|
||||
internal enum Restore {
|
||||
/// If you bought this app or feature in the past, you can restore your purchases and this screen won't show again.
|
||||
internal static let description = L10n.tr("App", "purchase.cells.restore.description")
|
||||
@ -89,6 +95,12 @@ internal enum L10n {
|
||||
internal static let title = L10n.tr("App", "purchase.cells.restore.title")
|
||||
}
|
||||
}
|
||||
internal enum Sections {
|
||||
internal enum Products {
|
||||
/// Every product is a one-time purchase.
|
||||
internal static let footer = L10n.tr("App", "purchase.sections.products.footer")
|
||||
}
|
||||
}
|
||||
}
|
||||
internal enum Service {
|
||||
internal enum Alerts {
|
||||
|
@ -61,5 +61,7 @@
|
||||
"shortcuts.edit.cells.add_shortcut.caption" = "Add shortcut";
|
||||
|
||||
"purchase.title" = "Purchase";
|
||||
"purchase.sections.products.footer" = "Every product is a one-time purchase.";
|
||||
"purchase.cells.full_version.extra_description" = "- All providers (including those being added in the future)\n%@";
|
||||
"purchase.cells.restore.title" = "Restore purchases";
|
||||
"purchase.cells.restore.description" = "If you bought this app or feature in the past, you can restore your purchases and this screen won't show again.";
|
||||
|
@ -29,27 +29,28 @@ import StoreKit
|
||||
class PurchaseTableViewCell: UITableViewCell {
|
||||
@IBOutlet private weak var labelTitle: UILabel?
|
||||
|
||||
@IBOutlet private weak var labelPrice: UILabel?
|
||||
|
||||
@IBOutlet private weak var labelDescription: UILabel?
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
labelTitle?.applyAccent(.current)
|
||||
labelPrice?.applyAccent(.current)
|
||||
}
|
||||
|
||||
func fill(product: SKProduct) {
|
||||
var title = product.localizedTitle
|
||||
if let price = product.localizedPrice {
|
||||
title += " @ \(price)"
|
||||
}
|
||||
func fill(product: SKProduct, customDescription: String? = nil) {
|
||||
fill(
|
||||
title: title,
|
||||
description: "\(product.localizedDescription)."
|
||||
title: product.localizedTitle,
|
||||
description: customDescription ?? "\(product.localizedDescription)."
|
||||
)
|
||||
labelPrice?.text = product.localizedPrice
|
||||
}
|
||||
|
||||
func fill(title: String, description: String) {
|
||||
labelTitle?.text = title
|
||||
labelDescription?.text = description
|
||||
labelPrice?.text = nil
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ class PurchaseViewController: UITableViewController, StrongTableHost {
|
||||
private var skFeature: SKProduct?
|
||||
|
||||
private var skFullVersion: SKProduct?
|
||||
|
||||
private var fullVersionExtra: String?
|
||||
|
||||
// MARK: StrongTableHost
|
||||
|
||||
@ -46,19 +48,26 @@ class PurchaseViewController: UITableViewController, StrongTableHost {
|
||||
func reloadModel() {
|
||||
model.clear()
|
||||
model.add(.products)
|
||||
|
||||
model.setFooter(L10n.App.Purchase.Sections.Products.footer, forSection: .products)
|
||||
|
||||
var rows: [RowType] = []
|
||||
let pm = ProductManager.shared
|
||||
if let skFeature = pm.product(withIdentifier: feature) {
|
||||
self.skFeature = skFeature
|
||||
rows.append(.feature)
|
||||
}
|
||||
if let skFullVersion = pm.product(withIdentifier: .fullVersion) {
|
||||
self.skFullVersion = skFullVersion
|
||||
rows.append(.fullVersion)
|
||||
}
|
||||
if let skFeature = pm.product(withIdentifier: feature) {
|
||||
self.skFeature = skFeature
|
||||
rows.append(.feature)
|
||||
}
|
||||
rows.append(.restore)
|
||||
model.set(rows, forSection: .products)
|
||||
|
||||
let featureBulletsList: [String] = ProductManager.shared.featureProducts(includingFullVersion: false).map {
|
||||
return "- \($0.localizedTitle)"
|
||||
}.sortedCaseInsensitive()
|
||||
let featureBullets = featureBulletsList.joined(separator: "\n")
|
||||
fullVersionExtra = L10n.App.Purchase.Cells.FullVersion.extraDescription(featureBullets)
|
||||
}
|
||||
|
||||
// MARK: UIViewController
|
||||
@ -156,6 +165,14 @@ extension PurchaseViewController {
|
||||
case restore
|
||||
}
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return model.numberOfSections
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
return model.footer(forSection: section)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
guard !isLoading else {
|
||||
return 0
|
||||
@ -176,7 +193,7 @@ extension PurchaseViewController {
|
||||
guard let product = skFullVersion else {
|
||||
fatalError("Loaded full version cell, yet no corresponding product?")
|
||||
}
|
||||
cell.fill(product: product)
|
||||
cell.fill(product: product, customDescription: fullVersionExtra)
|
||||
|
||||
case .restore:
|
||||
cell.fill(
|
||||
|
Loading…
Reference in New Issue
Block a user