changeset 11:039b26a99a48

implementing RevenueCat
author Dennis C. M. <dennis@denniscm.com>
date Sun, 09 Oct 2022 17:02:34 +0200
parents a793f33f05fb
children ce7ea84f67f5
files GeoQuiz.xcodeproj/project.pbxproj GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/Contents.json GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/GuessTheCapital.png GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/GuessTheCapitalDark.png GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/Contents.json GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/GuessTheCountry.png GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/GuessTheCountryDark.png GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/Contents.json GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/GuessThePopulation.png GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/GuessThePopulationDark.png GeoQuiz/Assets.xcassets/flag.imageset/Contents.json GeoQuiz/Assets.xcassets/flag.imageset/flag.png GeoQuiz/BuyPremiumModalView.swift GeoQuiz/Components/GameButtonHelper.swift GeoQuiz/ContentView.swift GeoQuiz/GeoQuizApp.swift GeoQuiz/GuessTheFlagView.swift
diffstat 17 files changed, 283 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/GeoQuiz.xcodeproj/project.pbxproj	Sat Oct 08 21:36:40 2022 +0200
+++ b/GeoQuiz.xcodeproj/project.pbxproj	Sun Oct 09 17:02:34 2022 +0200
@@ -10,6 +10,9 @@
 		95030CEA28D1BA4D001AA3A1 /* AnswerButtonHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95030CE928D1BA4D001AA3A1 /* AnswerButtonHelper.swift */; };
 		9509A8DE28E5A19A00CFCDBA /* countries.json in Resources */ = {isa = PBXBuildFile; fileRef = 9509A8DD28E5A19A00CFCDBA /* countries.json */; };
 		9509A8E228E5A3D700CFCDBA /* GuessThePopulationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */; };
+		950C535328F2FA3300179C78 /* BuyPremiumModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950C535228F2FA3300179C78 /* BuyPremiumModalView.swift */; };
+		950C535628F3172C00179C78 /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = 950C535528F3172C00179C78 /* RevenueCat */; };
+		950C535928F3178B00179C78 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 950C535828F3178B00179C78 /* StoreKit.framework */; };
 		951AFAEA28E5655C00A4A4BD /* cities.json in Resources */ = {isa = PBXBuildFile; fileRef = 951AFAE828E5655C00A4A4BD /* cities.json */; };
 		951AFAED28E5657500A4A4BD /* CityModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAEC28E5657500A4A4BD /* CityModel.swift */; };
 		951AFAEF28E565FE00A4A4BD /* CountryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAEE28E565FE00A4A4BD /* CountryModel.swift */; };
@@ -46,6 +49,8 @@
 		95030CE928D1BA4D001AA3A1 /* AnswerButtonHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnswerButtonHelper.swift; sourceTree = "<group>"; };
 		9509A8DD28E5A19A00CFCDBA /* countries.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = countries.json; sourceTree = "<group>"; };
 		9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessThePopulationView.swift; sourceTree = "<group>"; };
+		950C535228F2FA3300179C78 /* BuyPremiumModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuyPremiumModalView.swift; sourceTree = "<group>"; };
+		950C535828F3178B00179C78 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
 		951AFAE828E5655C00A4A4BD /* cities.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = cities.json; sourceTree = "<group>"; };
 		951AFAEC28E5657500A4A4BD /* CityModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityModel.swift; sourceTree = "<group>"; };
 		951AFAEE28E565FE00A4A4BD /* CountryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryModel.swift; sourceTree = "<group>"; };
@@ -85,6 +90,8 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				950C535628F3172C00179C78 /* RevenueCat in Frameworks */,
+				950C535928F3178B00179C78 /* StoreKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -107,6 +114,14 @@
 			path = Logic;
 			sourceTree = "<group>";
 		};
+		950C535728F3178B00179C78 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				950C535828F3178B00179C78 /* StoreKit.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 		9520ABBA28C86D0300A3D4D7 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
@@ -123,6 +138,7 @@
 			children = (
 				9539829128C51EDE00B70973 /* GeoQuiz */,
 				9539829028C51EDE00B70973 /* Products */,
+				950C535728F3178B00179C78 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -145,8 +161,9 @@
 				951B630128D1A87C004F9877 /* GuessTheCapitalView.swift */,
 				95AF322928DF293900023ACC /* GuessTheCountryView.swift */,
 				9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */,
+				950C535228F2FA3300179C78 /* BuyPremiumModalView.swift */,
+				952E41EC28DC658900198643 /* SettingsModalView.swift */,
 				9590359428E098FF00B24560 /* ProfileModalView.swift */,
-				952E41EC28DC658900198643 /* SettingsModalView.swift */,
 				959D414728C87EA600BAAC14 /* Components */,
 				95030CE728D1B60F001AA3A1 /* Logic */,
 				9520ABBA28C86D0300A3D4D7 /* Resources */,
@@ -196,6 +213,9 @@
 			dependencies = (
 			);
 			name = GeoQuiz;
+			packageProductDependencies = (
+				950C535528F3172C00179C78 /* RevenueCat */,
+			);
 			productName = GeoQuiz;
 			productReference = 9539828F28C51EDE00B70973 /* GeoQuiz.app */;
 			productType = "com.apple.product-type.application";
@@ -224,6 +244,9 @@
 				Base,
 			);
 			mainGroup = 9539828628C51EDE00B70973;
+			packageReferences = (
+				950C535428F3172C00179C78 /* XCRemoteSwiftPackageReference "purchases-ios" */,
+			);
 			productRefGroup = 9539829028C51EDE00B70973 /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
@@ -265,6 +288,7 @@
 				95C4315928C6500000212131 /* GameButtonHelper.swift in Sources */,
 				956273EA28CB2E98008DC094 /* FlagImageHelper.swift in Sources */,
 				951AFAED28E5657500A4A4BD /* CityModel.swift in Sources */,
+				950C535328F2FA3300179C78 /* BuyPremiumModalView.swift in Sources */,
 				951B630228D1A87C004F9877 /* GuessTheCapitalView.swift in Sources */,
 				9539829328C51EDE00B70973 /* GeoQuizApp.swift in Sources */,
 				95AF322A28DF293900023ACC /* GuessTheCountryView.swift in Sources */,
@@ -487,6 +511,25 @@
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+		950C535428F3172C00179C78 /* XCRemoteSwiftPackageReference "purchases-ios" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/RevenueCat/purchases-ios.git";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 4.0.0;
+			};
+		};
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+		950C535528F3172C00179C78 /* RevenueCat */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 950C535428F3172C00179C78 /* XCRemoteSwiftPackageReference "purchases-ios" */;
+			productName = RevenueCat;
+		};
+/* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = 9539828728C51EDE00B70973 /* Project object */;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/Contents.json	Sun Oct 09 17:02:34 2022 +0200
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "filename" : "GuessTheCapital.png",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "GuessTheCapitalDark.png",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
Binary file GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/GuessTheCapital.png has changed
Binary file GeoQuiz/Assets.xcassets/GuessTheCapital.imageset/GuessTheCapitalDark.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/Contents.json	Sun Oct 09 17:02:34 2022 +0200
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "filename" : "GuessTheCountry.png",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "GuessTheCountryDark.png",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
Binary file GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/GuessTheCountry.png has changed
Binary file GeoQuiz/Assets.xcassets/GuessTheCountry.imageset/GuessTheCountryDark.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/Contents.json	Sun Oct 09 17:02:34 2022 +0200
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "filename" : "GuessThePopulation.png",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "GuessThePopulationDark.png",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
Binary file GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/GuessThePopulation.png has changed
Binary file GeoQuiz/Assets.xcassets/GuessThePopulation.imageset/GuessThePopulationDark.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Assets.xcassets/flag.imageset/Contents.json	Sun Oct 09 17:02:34 2022 +0200
@@ -0,0 +1,12 @@
+{
+  "images" : [
+    {
+      "filename" : "flag.png",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
Binary file GeoQuiz/Assets.xcassets/flag.imageset/flag.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/BuyPremiumModalView.swift	Sun Oct 09 17:02:34 2022 +0200
@@ -0,0 +1,95 @@
+//
+//  BuyPremiumModalView.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 9/10/22.
+//
+
+import SwiftUI
+
+struct BuyPremiumModalView: View {
+    @Environment(\.dismiss) var dismiss
+    
+    var body: some View {
+        NavigationView {
+            ScrollView(showsIndicators: false) {
+                VStack(alignment: .center, spacing: 20) {
+                    VStack(spacing: 20) {
+                        Text("Unlock Premium 🤩")
+                            .font(.largeTitle.bold())
+                        
+                        Text("Unlock three more game modes to become a geography master and support the future development of GeoQuiz.")
+                            .foregroundColor(.secondary)
+                            .multilineTextAlignment(.center)
+                            .frame(maxWidth: 400)
+                    }
+                    .padding()
+                    
+                    ScrollView(.horizontal, showsIndicators: false) {
+                        HStack(spacing: 20) {
+                            Group {
+                                Image("GuessTheCapital")
+                                    .resizable()
+                                
+                                Image("GuessTheCountry")
+                                    .resizable()
+                                
+                                Image("GuessThePopulation")
+                                    .resizable()
+                            }
+                            .scaledToFit()
+                            .cornerRadius(25)
+                            .frame(height: 500)
+                        }
+                        .padding()
+                    }
+                    
+                    VStack(spacing: 10) {
+                        Text("A one-time payment.")
+                            .font(.title)
+                            .fontWeight(.semibold)
+                        
+                        Text("No subscriptions.")
+                            .font(.title2)
+                            .fontWeight(.semibold)
+                            .foregroundColor(.secondary)
+                        
+                        Button {
+                            // Buy
+                        } label: {
+                            Text("Buy for $2.99")
+                                .font(.headline)
+                                .padding()
+                        }
+                        .buttonStyle(.borderedProminent)
+                        .padding(.top)
+                    }
+                    .padding()
+                    
+                    VStack {
+                        Text("GeoQuiz is an indie game")
+                        Text("I appreciate your support ❤️")
+                    }
+                    .font(.callout)
+                    .foregroundColor(.secondary)
+                }
+            }
+            .navigationBarTitleDisplayMode(.inline)
+            .toolbar {
+                ToolbarItem(placement: .cancellationAction) {
+                    Button {
+                        dismiss()
+                    } label: {
+                        Label("Exit", systemImage: "multiply")
+                    }
+                }
+            }
+        }
+    }
+}
+
+struct BuyPremiumModalView_Previews: PreviewProvider {
+    static var previews: some View {
+        BuyPremiumModalView()
+    }
+}
--- a/GeoQuiz/Components/GameButtonHelper.swift	Sat Oct 08 21:36:40 2022 +0200
+++ b/GeoQuiz/Components/GameButtonHelper.swift	Sun Oct 09 17:02:34 2022 +0200
@@ -14,42 +14,43 @@
     let name: String
     
     var body: some View {
-        ZStack {
-            RoundedRectangle(cornerRadius: 20)
-                .fill(
-                    LinearGradient(
-                        gradient: gradient,
-                        startPoint: .trailing, endPoint: .leading
-                    )
+        RoundedRectangle(cornerRadius: 20)
+            .fill(
+                LinearGradient(
+                    gradient: gradient,
+                    startPoint: .trailing, endPoint: .leading
                 )
-                .frame(height: 180)
-            
-            VStack(alignment: .leading) {
-                HStack {
-                    Image(systemName: symbol)
-                        .font(.headline)
-                        .padding(5)
-                        .background(
-                            RoundedRectangle(cornerRadius: 5)
-                                .stroke(lineWidth: 1.5)
-                        )
-                    
-                    Spacer()
-                }
-                .padding(.bottom)
-                
-                VStack(alignment: .leading, spacing: 5) {
-                    Text(level)
-                        .font(.callout)
-                    
-                    Text(name)
-                        .font(.title.bold())
+            )
+            .frame(height: 180)
+            .frame(maxWidth: 700)
+            .overlay {
+                ZStack(alignment: .trailing) {
+                    VStack(alignment: .leading) {
+                        HStack {
+                            Image(systemName: symbol)
+                                .font(.headline)
+                                .padding(5)
+                                .background(
+                                    RoundedRectangle(cornerRadius: 5)
+                                        .stroke(lineWidth: 1.5)
+                                )
+                            
+                            Spacer()
+                        }
+                        .padding(.bottom)
+                        
+                        VStack(alignment: .leading, spacing: 5) {
+                            Text(level)
+                                .font(.callout)
+                            
+                            Text(name)
+                                .font(.title.bold())
+                        }
+                    }
+                    .foregroundColor(.white)
+                    .padding()
                 }
             }
-            .foregroundColor(.white)
-            .padding()
-        }
-        .frame(maxWidth: 700)
     }
 }
 
@@ -58,7 +59,7 @@
         GameButton(
             gradient: .main,
             level: "Level 1",
-            symbol: "checkmark",
+            symbol: "flag.fill",
             name: "Guess the flag"
         )
     }
--- a/GeoQuiz/ContentView.swift	Sat Oct 08 21:36:40 2022 +0200
+++ b/GeoQuiz/ContentView.swift	Sun Oct 09 17:02:34 2022 +0200
@@ -10,12 +10,12 @@
 struct ContentView: View {
     @State private var showingBuyPremiumModalView = false
     @State private var showingSettingsModalView = false
+    @State private var showingProfileModalView = false
     
     var body: some View {
         NavigationView {
             ScrollView(showsIndicators: false) {
-                VStack(alignment: .leading, spacing: 20) {
-                    
+                VStack(alignment: .leading, spacing: 30) {
                     Text("Select a game 🎮")
                         .font(.largeTitle.bold())
                         .padding(.bottom)
@@ -33,7 +33,7 @@
                             level: "Level 2", symbol: "building.2.fill", name: "Guess the capital"
                         )
                     }
-
+                    
                     NavigationLink(destination: GuessTheCountryView()) {
                         GameButton(
                             gradient: .tertiary,
@@ -67,15 +67,25 @@
                     } label: {
                         Label("Buy premium", systemImage: "star")
                     }
+                    
+                    Button {
+                        showingProfileModalView = true
+                    } label: {
+                        Label("Profile", systemImage: "person")
+                    }
                 }
             }
             .sheet(isPresented: $showingBuyPremiumModalView) {
-                Text("Buy premium")
+                BuyPremiumModalView()
             }
             
             .sheet(isPresented: $showingSettingsModalView) {
                 SettingsModalView()
             }
+            
+            .sheet(isPresented: $showingProfileModalView) {
+                ProfileModalView()
+            }
         }
         .navigationViewStyle(StackNavigationViewStyle())
     }
--- a/GeoQuiz/GeoQuizApp.swift	Sat Oct 08 21:36:40 2022 +0200
+++ b/GeoQuiz/GeoQuizApp.swift	Sun Oct 09 17:02:34 2022 +0200
@@ -6,12 +6,28 @@
 //
 
 import SwiftUI
+import RevenueCat
 
 @main
 struct GeoQuizApp: App {
+    
+    init() {
+        Purchases.configure(withAPIKey: "appl_BymTxroeoaWiXAraaFjcPlHlqbf")
+    }
+    
     var body: some Scene {
         WindowGroup {
             ContentView()
+                .onAppear(perform: testRevenueCat)
+        }
+    }
+    
+    private func testRevenueCat() {
+        Purchases.shared.getOfferings { (offerings, error) in
+            if let packages = offerings?.current?.availablePackages {
+                // Display packages for sale
+                print(packages)
+            }
         }
     }
 }
--- a/GeoQuiz/GuessTheFlagView.swift	Sat Oct 08 21:36:40 2022 +0200
+++ b/GeoQuiz/GuessTheFlagView.swift	Sun Oct 09 17:02:34 2022 +0200
@@ -20,7 +20,7 @@
                     GameToolbar(game: game, color: .mayaBlue)
                         .padding(.bottom)
                     
-                    VStack(spacing: 10) {
+                    VStack(alignment: .center, spacing: 10) {
                         Text("Question \(game.questionCounter) of \(game.data.count)")
                             .font(.title3)
                             .foregroundColor(.white.opacity(0.7))