Skip to content

Commit

Permalink
Added optional closures to store and subscription views; Updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
russell-archer committed Sep 18, 2024
1 parent 1943efc commit c8abc70
Show file tree
Hide file tree
Showing 24 changed files with 276 additions and 75 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Samples/Images/plant-services.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ struct ContentView: View {
// Products that have been purchased will be grayed-out.
// Tapping on the product's image shows details for the product.
NavigationLink("List all products") {
SKHelperStoreView() { productId in
// Add more content to a product's description by placing it in this closure
}
SKHelperStoreView()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ struct ContentView: View {
// Tapping on the product's image shows details for the product.
NavigationLink("List all products") {
SKHelperStoreView() { productId in
// Add more content to a product's description by placing it in this closure
Group {
Image(productId)
.resizable()
.scaledToFit()
Image(productId + ".info").resizable().scaledToFit()
Text("Here is some text about why you might want to buy this product.")
}
.padding()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ struct ContentView: View {
// Tapping on the product's image shows details for the product.
NavigationLink("List all products") {
SKHelperStoreView() { productId in
// Add more content to a product's description by placing it in this closure
Group {
Image(productId)
.resizable()
.scaledToFit()
Image(productId + ".info").resizable().scaledToFit()
Text("Here is some text about why you might want to buy this product.")
}
.padding()
Expand All @@ -30,8 +27,8 @@ struct ContentView: View {

// SKHelperSubscriptionStoreView() lists all subscription products for this app.
// Trials, upgrades and downgrades are handled automatically.
NavigationLink("Lists all subscription") {
SKHelperSubscriptionStoreView()
NavigationLink("List all subscriptions") {
SKHelperSubscriptionStoreView(subscriptionGroupName: "vip")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ struct ContentView: View {
// Tapping on the product's image shows details for the product.
NavigationLink("List all products") {
SKHelperStoreView() { productId in
// Add more content to a product's description by placing it in this closure
Group {
Image(productId)
.resizable()
.scaledToFit()
Image(productId + ".info").resizable().scaledToFit()
Text("Here is some text about why you might want to buy this product.")
}
.padding()
Expand All @@ -30,15 +27,27 @@ struct ContentView: View {

// SKHelperSubscriptionStoreView() lists all subscription products for this app.
// Trials, upgrades and downgrades are handled automatically.
NavigationLink("Lists all subscription") {
SKHelperSubscriptionStoreView()
}

// SKHelperPurchasesView() lists all products that have been purchased,
// including subscriptions. Details of the purchase or subscription are shown when
// the "Manage Purchase" button is tapped.
NavigationLink("List all purchases") {
SKHelperPurchasesView()
NavigationLink("List all subscriptions") {
SKHelperSubscriptionStoreView(
subscriptionGroupName: "vip",
subscriptionHeader: {
VStack {
Image("plant-services").resizable().scaledToFit()
Text("Services to make your plants happy!").font(.headline)
}
},
subscriptionControl: { productId in
VStack {
Image(productId).resizable().scaledToFit()
Text("We'll visit \(productId == "com.rarcher.subscription.vip.gold" ? "weekly" : "monthly") to water your plants.").font(.caption2)
}
},
subscriptionDetails: { productId in
VStack {
Image(productId + ".info").resizable().scaledToFit()
Text("Here is some text about why you might want to buy this product.")
}
})
}
}
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@ContentAndMedia {
In this section we'll add the code required to display all products and support user purchases.

@Image(source: "quickstart11.png", alt: "SKHelperDemoApp.swift.")
@Image(source: "quickstart14.png", alt: "Display products.")
}

@Steps {
Expand Down Expand Up @@ -74,9 +74,9 @@
}

@Step {
If your build and run the app you'll see how the changes have affected the display of product details.
If you build and run the app you'll see how the changes have affected the display of product details.

@Image(source: "quickstart16.png", alt: "Show product details with addtional custom information.")
@Image(source: "quickstart16.png", alt: "Show product details with additional custom information.")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,64 @@
@ContentAndMedia {
In this section we'll add code to support the display, promotion, purchase and management of subscriptions.

@Image(source: "quickstart11.png", alt: "SKHelperDemoApp.swift.")
@Image(source: "quickstart17.png", alt: "Display subscriptions.")
}

@Steps {
@Step {
TODO.
If you look at the **Products.storekit** file you'll see that our two demo subscriptions for the "gold" and "silver" services
are collected into a subscription group named **"vip"**.

@Image(source: "quickstart18.png", alt: "The VIP subscription group.")
}

@Step {
Add the following code to **ContentView.swift** to enable our demo to show all the subscriptions in the "vip" group.

@Code(name: "ContentView.swift", file: "quickstart-contentview3.swift", previousFile: "quickstart-contentview2.swift", reset: false) {}

Notice how we use the subscription group name to refer to all subscriptions in the "vip" group.
}

@Step {
Build and run the app and select the **List all subscriptions** option. You should see the "gold" and "silver"
subscription list, along with options to subscribe.

@Image(source: "quickstart19.png", alt: "The VIP subscription group.")
}

@Step {
We can customize the look of **SKHelperSubscriptionStoreView** by specifying three optional closures.
}

@Step {
**Header**. Content displayed at the top of the subscription list that is common to all subscriptions in the group.

@Image(source: "quickstart21.png", alt: "Header customization.")
}

@Step {
**Control**. Content displayed in-line with each subscription in the subscription list.

@Image(source: "quickstart22.png", alt: "Control customization.")
}

@Step {
**Details**. Content displayed in the product details sheet.

@Image(source: "quickstart23.png", alt: "Details customization.")
}

@Step {
Add the following code to **ContentView.swift** to customize the appearance of **SKHelperSubscriptionStoreView**.

@Code(name: "ContentView.swift", file: "quickstart-contentview4.swift", reset: false) {}
}

@Step {
Build and run the app. You can now see how the customizations have changed the look of the subscription list.

@Image(source: "quickstart20.png", alt: "The customized VIP subscription group.")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
@Chapter(name: "Display all products") {
Add code to display all products and support user purchases.

@Image(source: "quickstart11.png", alt: "Display all products.")
@Image(source: "quickstart14.png", alt: "Display all products.")
@TutorialReference(tutorial: "doc:display-products")
}

@Chapter(name: "Display subscriptions") {
Add code to support the display, promotion, purchase and management of subscriptions.

@Image(source: "quickstart11.png", alt: "Display subscriptions.")
@Image(source: "quickstart17.png", alt: "Display subscriptions.")
@TutorialReference(tutorial: "doc:display-subscriptions")
}

Expand Down
20 changes: 17 additions & 3 deletions Sources/SKHelper/Views/SKHelperProductView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import StoreKit
@available(iOS 17.0, macOS 14.6, *)
public struct SKHelperProductView<Content: View>: View {

/// A closure that is passed a `ProductId` and returns a `View` providing product details.
public typealias ProductDetailsClosure = (ProductId) -> Content

/// The `SKHelper` object.
Expand All @@ -27,9 +28,9 @@ public struct SKHelperProductView<Content: View>: View {
@Binding var showProductInfoSheet: Bool

/// A closure which is called to display product details.
private var productDetails: ProductDetailsClosure
private var productDetails: ProductDetailsClosure?

/// Creates an `SKHelperProductView` which displays product information using a StoreKit `ProductView`.
/// Creates an `SKHelperProductView` which displays custom product information using a StoreKit `ProductView`.
///
/// - Parameters:
/// - selectedProductId: The `ProductId` of the product for which you want to display details.
Expand All @@ -41,12 +42,25 @@ public struct SKHelperProductView<Content: View>: View {
self._showProductInfoSheet = showProductInfoSheet
self.productDetails = productDetails
}

/// Creates an `SKHelperProductView` which displays default product information using a StoreKit `ProductView`.
///
/// - Parameters:
/// - selectedProductId: The `ProductId` of the product for which you want to display details.
/// - showProductInfoSheet: Used to togggle the display of the product information sheet
///
public init(selectedProductId: Binding<ProductId>, showProductInfoSheet: Binding<Bool>) where Content == EmptyView {
self._selectedProductId = selectedProductId
self._showProductInfoSheet = showProductInfoSheet
self.productDetails = nil
}

/// Creates the body of the view.
///
public var body: some View {
SKHelperSheetBarView(showSheet: $showProductInfoSheet, title: product?.displayName ?? "Product Info")
ScrollView {
productDetails(selectedProductId)
productDetails?(selectedProductId)

ProductView(id: selectedProductId) {
Image(selectedProductId)
Expand Down
30 changes: 13 additions & 17 deletions Sources/SKHelper/Views/SKHelperStoreView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import StoreKit
@available(iOS 17.0, macOS 14.6, *)
public struct SKHelperStoreView<Content: View>: View {

/// A closure that is passed a `ProductId` and returns a `View` providing product details.
public typealias ProductDetailsClosure = (ProductId) -> Content

/// The `SKHelper` object.
Expand All @@ -24,14 +25,14 @@ public struct SKHelperStoreView<Content: View>: View {
@State private var productSelected = false

/// A closure which is called to display product details.
private var productDetails: ProductDetailsClosure
private var productDetails: ProductDetailsClosure?

/// Creates an `SKHelperStoreView`. When you instantiate this view provide a closure that may be called to display product information. This information will be displayed when the
/// user taps on the product's image.
/// Creates an `SKHelperStoreView`. When you instantiate this view provide a closure that may be called to display product information.
/// This information will be displayed when the user taps on the product's image.
///
/// The `ProductId` of the product to display information for is provided to the closure.
///
/// ## Example 1 ##
/// ## Example ##
///
/// ```
/// SKHelperStoreView() { productId in
Expand All @@ -45,17 +46,14 @@ public struct SKHelperStoreView<Content: View>: View {
/// .padding()
/// }
/// ```
///
/// Note that you can also provide an empty closure if you do not wish to provide custom content.
///
/// ## Example 2 ##
///
/// ```
/// SKHelperStoreView() { _ in }
/// ```
public init(@ViewBuilder productDetails: @escaping ProductDetailsClosure) {
self.productDetails = productDetails
}

/// Creates an `SKHelperStoreView`. Default product information will be displayed when the user taps on the product's image.
public init() where Content == EmptyView {
self.productDetails = nil
}

/// Creates the body of the view.
public var body: some View {
Expand All @@ -81,7 +79,8 @@ public struct SKHelperStoreView<Content: View>: View {
#endif
.storeButton(.hidden, for: .cancellation) // Hides the close "X" at the top-right of the view
.sheet(isPresented: $productSelected) {
SKHelperProductView(selectedProductId: $selectedProductId, showProductInfoSheet: $productSelected, productDetails: productDetails)
if let productDetails { SKHelperProductView(selectedProductId: $selectedProductId, showProductInfoSheet: $productSelected, productDetails: productDetails) }
else { SKHelperProductView(selectedProductId: $selectedProductId, showProductInfoSheet: $productSelected) }
}
} else {

Expand All @@ -96,8 +95,5 @@ public struct SKHelperStoreView<Content: View>: View {
}

#Preview {
SKHelperStoreView() { selectedProductId in
Text("Product details for \(selectedProductId)")
}
.environment(SKHelper())
SKHelperStoreView().environment(SKHelper())
}
Loading

0 comments on commit c8abc70

Please sign in to comment.