diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..b4e94de --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,49 @@ +name: Deploy Documentation to GitHub Pages + +on: + push: + branches: ["main", "wip/xcframework"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: write + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Install Swift + uses: swift-actions/setup-swift@v2 + + - name: Build Documentation + run: | + swift package --allow-writing-to-directory ./docs \ + generate-documentation --target FreemiumKit \ + --disable-indexing \ + --transform-for-static-hosting \ + --hosting-base-path FreemiumKit \ + --output-path ./docs + + - name: Deploy to Pages + uses: JamesIves/github-pages-deploy-action@v4.6.0 + with: + branch: gh-pages + folder: docs diff --git a/Images/PaywallSample_AsyncProducts.png b/Images/PaywallSample_AsyncProducts.png deleted file mode 100644 index 28cc953..0000000 Binary files a/Images/PaywallSample_AsyncProducts.png and /dev/null differ diff --git a/Logo.png b/Logo.png deleted file mode 100644 index a0a4e09..0000000 Binary files a/Logo.png and /dev/null differ diff --git a/Sources/FreemiumKit/FreemiumKit.docc/FreemiumKit.md b/Sources/FreemiumKit/FreemiumKit.docc/FreemiumKit.md new file mode 100644 index 0000000..4f523d5 --- /dev/null +++ b/Sources/FreemiumKit/FreemiumKit.docc/FreemiumKit.md @@ -0,0 +1,137 @@ +# FreemiumKit + +Learn how to set up your app for our paywalls and live push notifications. + +@Metadata { + @PageImage(purpose: icon, source: "FreemiumKit") + @TitleHeading("Setup Guide") + @PageKind(article) +} + + +## Adding the SDK + +1. Open your app project in Xcode. + +1. In the "File" menu select "Add Package Dependencies…" + + // TODO: add screenshot + +1. Paste this to the top right text field and press "Add Package": + ``` + https://github.com/FlineDev/FreemiumKit.git + ``` + + // TODO: add screenshot + +1. Select your app target (if not already selected) and confirm by pressing "Add Package" + + // TODO: add screenshot + + +## Configuring the SDK + +1. Make sure your app's Asset Catalog contains the `Paywall.config` file from the "Setup" tab for your app in FreemiumKit. If it doesn't, drag & drop it to your Asset Catalog now. + +1. Add a call to `.environmentObject(FreemiumKit.shared)` to every scene in the app entry point. For example: + + ```swift + @main + struct MyApp: App { + var body: some Scene { + WindowGroup { + MainView() + } + .environmentObject(FreemiumKit.shared) + } + } + ``` + + +## Showing the Paywalls + +1. (Recommended) Lock your paid features for users who have not made a purchase yet by using one of the built-in views `PaidFeatureButton`/`PaidFeatureView`. For example: + + ```swift + // opens paywall if user has not purchased, else works like a normal (stylable) button + PaidFeatureButton("Export", systemImage: "square.and.arrow.up") { + // your export logic – no check for a paid tier needed, only called if already purchased + } + + // this one behaves exactly the same as the one above, but gives you more flexibility to change the unlocked/locked views + PaidFeatureView { + Button("Export", systemImage: "square.and.arrow.up") { + // your export logic – no check for a paid tier needed, only called if already purchased + } + } lockedView: { + Label("Export", systemImage: "lock") + } + ``` + + Note that both `PaidFeatureButton` and `PaidFeatureView` accept an `unlocksAtTier` parameter of type `Int` (default: `1`) and a `showPaywallOnPressIfLocked` parameter of type `Bool` (default: `true`). This leads to a default behavior of unlocking the feature only if tier 1 is purchased and showing a paywall on press if tier 1 is not yet purchased. If `showPaywallOnPressIfLocked` is set to `false`, the locked view will not have any automatic interaction, just rendering locked view state as-is without any added behavior. + + +1. (Optional) Alternatively, if you want to control the presentation of the paywall manually, you can add the `.paywall(isPresented:)` modifier to your custom views where needed. For example: + + ```swift + struct MyView: View { + @State var showPaywall: Bool = false + + var body: some View { + Button("Unlock Pro") { + self.showPaywall = true + } + .paywall(isPresent: self.$showPaywall) + } + } + ``` + + If you want to conditionally hide views based on paid state (like hiding the unlock button if a user has already purchased), you can add the `FreemiumKit` object as an `@EnvironmentObject` and call `.purchasedTier` on it like so: + + ```swift + struct MyView: View { + @EnvironmentObject var freemiumKit: FreemiumKit + @State var showPaywall: Bool = false + + var body: some View { + if self.freemiumKit.purchasedTier == nil { + Button("Unlock Pro") { + self.showPaywall = true + } + .paywall(isPresent: self.$showPaywall) + } + } + } + ``` + +1. (Optional) There's also a `PaidStatusView` which you can add to your app's settings to indicate to users what their current purchase state is. There are two styles: + + ```swift + PaidStatusView(style: .plain) + PaidStatusView(style: .decorative(icon: .laurel)) + ``` + + // TODO: add screenshot of both styles + + The `.decorative` style has multiple `icon` parameter options and also accepts optional `foregroundColor` and `backgroundColor` parameters if you need to adjust the defaults. Note that the `PaidStatusView` will automatically open a paywall on press if there's no purchase yet. Else, it's rendered as just a label without interaction. + + +## SwiftUI Previews + +For SwiftUI previews to work for views where you make use of the `.paywall` modifier, add a call to `.environmentObject(FreemiumKit.preview)` in your preview code like so: + +```swift +#Preview { + YourView() + .environmentObject(FreemiumKit.preview) +} +``` + +If you want to simulate a specific paid state in your previews, you can call the `withDebugOverrides(purchasedTier:)` function on `FreemiumKit.preview` and set your desired tier (set `1` for full access). The default `FreemiumKit.preview` shows in the "nothing purchased" state, showcasing how things will look from a Free user perspective. For example: + +```swift +#Preview("Full Access") { + YourView() + .environmentObject(FreemiumKit.preview.withDebugOverrides(purchasedTier: 1)) +} +``` diff --git a/Sources/FreemiumKit/FreemiumKit.docc/Resources/FreemiumKit.png b/Sources/FreemiumKit/FreemiumKit.docc/Resources/FreemiumKit.png new file mode 100644 index 0000000..573f6c4 Binary files /dev/null and b/Sources/FreemiumKit/FreemiumKit.docc/Resources/FreemiumKit.png differ diff --git a/Sources/FreemiumKit/FreemiumKit.docc/theme-settings.json b/Sources/FreemiumKit/FreemiumKit.docc/theme-settings.json new file mode 100644 index 0000000..d403127 --- /dev/null +++ b/Sources/FreemiumKit/FreemiumKit.docc/theme-settings.json @@ -0,0 +1,9 @@ +{ + "theme": { + "color": { + "header": "#021221", + "documentation-intro-fill": "radial-gradient(circle at top, var(--color-header) 30%, #000 100%)", + "documentation-intro-accent": "var(--color-header)" + } + } +}