Mercurial > public > geoquiz
changeset 15:f1967f8cc67b
first iteration of core data
author | Dennis C. M. <dennis@denniscm.com> |
---|---|
date | Wed, 19 Oct 2022 10:04:17 +0200 |
parents | 136928bae534 |
children | 1011e56b7832 |
files | GeoQuiz.xcodeproj/project.pbxproj GeoQuiz/Components/GameAlertsModifier.swift GeoQuiz/GeoQuiz.xcdatamodeld/GeoQuiz.xcdatamodel/contents GeoQuiz/GeoQuizApp.swift GeoQuiz/GuessTheCapitalView.swift GeoQuiz/GuessTheCountryView.swift GeoQuiz/GuessTheFlagView.swift GeoQuiz/GuessThePopulationView.swift GeoQuiz/Logic/CityGameClass.swift GeoQuiz/Logic/CountryGameClass.swift GeoQuiz/Logic/DataController.swift GeoQuiz/Logic/GameProtocol+Extension.swift GeoQuiz/Logic/GameTypeEnum.swift GeoQuiz/Logic/PlayedGame+CoreDataClass.swift GeoQuiz/Logic/PlayedGame+CoreDataProperties.swift GeoQuiz/ProfileModalView.swift |
diffstat | 16 files changed, 157 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/GeoQuiz.xcodeproj/project.pbxproj Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz.xcodeproj/project.pbxproj Wed Oct 19 10:04:17 2022 +0200 @@ -45,6 +45,9 @@ 95C6456E28FE8C04000CD570 /* UserImageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6456D28FE8C04000CD570 /* UserImageHelper.swift */; }; 95C6457228FFC4DC000CD570 /* ProfileEditModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6457128FFC4DC000CD570 /* ProfileEditModalView.swift */; }; 95C6457428FFC8E0000CD570 /* DataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6457328FFC8E0000CD570 /* DataController.swift */; }; + 95C6457728FFC934000CD570 /* GeoQuiz.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 95C6457528FFC934000CD570 /* GeoQuiz.xcdatamodeld */; }; + 95C6459A28FFE5A3000CD570 /* PlayedGame+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6459828FFE5A3000CD570 /* PlayedGame+CoreDataClass.swift */; }; + 95C6459B28FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6459928FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift */; }; 95CA295028F6BB4500CE0B7A /* ActivityAlertHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CA294F28F6BB4500CE0B7A /* ActivityAlertHelper.swift */; }; 95CC404928F98503001F74E1 /* GameTypeEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CC404828F98503001F74E1 /* GameTypeEnum.swift */; }; 95FA409A28D9876B00129B60 /* GuessTheFlagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FA409928D9876B00129B60 /* GuessTheFlagView.swift */; }; @@ -90,6 +93,9 @@ 95C6456D28FE8C04000CD570 /* UserImageHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserImageHelper.swift; sourceTree = "<group>"; }; 95C6457128FFC4DC000CD570 /* ProfileEditModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditModalView.swift; sourceTree = "<group>"; }; 95C6457328FFC8E0000CD570 /* DataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataController.swift; sourceTree = "<group>"; }; + 95C6457628FFC934000CD570 /* GeoQuiz.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = GeoQuiz.xcdatamodel; sourceTree = "<group>"; }; + 95C6459828FFE5A3000CD570 /* PlayedGame+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlayedGame+CoreDataClass.swift"; sourceTree = "<group>"; }; + 95C6459928FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlayedGame+CoreDataProperties.swift"; sourceTree = "<group>"; }; 95CA294F28F6BB4500CE0B7A /* ActivityAlertHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityAlertHelper.swift; sourceTree = "<group>"; }; 95CC404828F98503001F74E1 /* GameTypeEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameTypeEnum.swift; sourceTree = "<group>"; }; 95E6188428DDDB5C003359ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; @@ -125,6 +131,8 @@ 95CC404828F98503001F74E1 /* GameTypeEnum.swift */, 95AE8D5628C8750E0067F219 /* LoadFunc.swift */, 95C6457328FFC8E0000CD570 /* DataController.swift */, + 95C6459828FFE5A3000CD570 /* PlayedGame+CoreDataClass.swift */, + 95C6459928FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift */, ); path = Logic; sourceTree = "<group>"; @@ -170,6 +178,7 @@ children = ( 95E6188428DDDB5C003359ED /* Info.plist */, 9539829628C51EDF00B70973 /* Assets.xcassets */, + 95C6457528FFC934000CD570 /* GeoQuiz.xcdatamodeld */, 9539829228C51EDE00B70973 /* GeoQuizApp.swift */, 95C4315528C64A8C00212131 /* ContentView.swift */, 95FA409928D9876B00129B60 /* GuessTheFlagView.swift */, @@ -297,6 +306,7 @@ files = ( 955A65A928D7815E00CEEC6D /* HapticsClass.swift in Sources */, 95BC392D28EC42570049AB49 /* CityMapHelper.swift in Sources */, + 95C6459A28FFE5A3000CD570 /* PlayedGame+CoreDataClass.swift in Sources */, 952E41E928DC521200198643 /* GameAlertsModifier.swift in Sources */, 95197EFD28F339AE00FE67E9 /* StoreKitRCClass.swift in Sources */, 9509A8E228E5A3D700CFCDBA /* GuessThePopulationView.swift in Sources */, @@ -320,9 +330,11 @@ 95CA295028F6BB4500CE0B7A /* ActivityAlertHelper.swift in Sources */, 955A658128D703EB00CEEC6D /* GameToolbarHelper.swift in Sources */, 95AE8D5728C8750E0067F219 /* LoadFunc.swift in Sources */, + 95C6457728FFC934000CD570 /* GeoQuiz.xcdatamodeld in Sources */, 9590359528E098FF00B24560 /* ProfileModalView.swift in Sources */, 955950BB28F15FF2001BDEE8 /* FormatterExtension.swift in Sources */, 95C6456C28FE87E4000CD570 /* UserDataModel.swift in Sources */, + 95C6459B28FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift in Sources */, 951D197328D485E000671FAD /* ColorExtension.swift in Sources */, 95C6457228FFC4DC000CD570 /* ProfileEditModalView.swift in Sources */, 95C430F928D0A8E500480D23 /* GradientExtension.swift in Sources */, @@ -558,6 +570,19 @@ productName = RevenueCat; }; /* End XCSwiftPackageProductDependency section */ + +/* Begin XCVersionGroup section */ + 95C6457528FFC934000CD570 /* GeoQuiz.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 95C6457628FFC934000CD570 /* GeoQuiz.xcdatamodel */, + ); + currentVersion = 95C6457628FFC934000CD570 /* GeoQuiz.xcdatamodel */; + path = GeoQuiz.xcdatamodeld; + sourceTree = "<group>"; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ }; rootObject = 9539828728C51EDE00B70973 /* Project object */; }
--- a/GeoQuiz/Components/GameAlertsModifier.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/Components/GameAlertsModifier.swift Wed Oct 19 10:04:17 2022 +0200 @@ -6,9 +6,14 @@ // import SwiftUI +import CoreData struct GameAlertsModifier<T: Game>: ViewModifier { @ObservedObject var game: T + + var gameType: GameType + var moc: NSManagedObjectContext + @Environment(\.dismiss) var dismiss func body(content: Content) -> some View { @@ -22,25 +27,12 @@ } message: { Text(game.alertMessage) } - - .alert(game.alertTitle, isPresented: $game.showingGameOverAlert) { - Button("Try again") { - game.reset { - game.selector() - } - } - Button("Exit", role: .cancel) { dismiss()} - } message: { - Text(game.alertMessage) - } .alert(game.alertTitle, isPresented: $game.showingEndGameAlert) { - Button("Play again") { - game.reset() { - game.selector() - } + Button("Exit", role: .cancel) { + game.save(gameType, with: moc) + dismiss() } - Button("Exit", role: .cancel) { dismiss() } } message: { Text(game.alertMessage) }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GeoQuiz/GeoQuiz.xcdatamodeld/GeoQuiz.xcdatamodel/contents Wed Oct 19 10:04:17 2022 +0200 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21279" systemVersion="21G115" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier=""> + <entity name="PlayedGame" representedClassName="PlayedGame" syncable="YES"> + <attribute name="correctAnswers" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData" customClassName="[String]"/> + <attribute name="date" attributeType="Date" usesScalarValueType="NO"/> + <attribute name="id" attributeType="UUID" usesScalarValueType="NO"/> + <attribute name="score" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/> + <attribute name="type" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> + <attribute name="wrongAnswers" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData" customClassName="[String]"/> + <uniquenessConstraints> + <uniquenessConstraint> + <constraint value="id"/> + </uniquenessConstraint> + </uniquenessConstraints> + </entity> +</model> \ No newline at end of file
--- a/GeoQuiz/GeoQuizApp.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/GeoQuizApp.swift Wed Oct 19 10:04:17 2022 +0200 @@ -10,6 +10,7 @@ @main struct GeoQuizApp: App { + @StateObject private var dataController = DataController() init() { Purchases.configure(withAPIKey: "appl_BymTxroeoaWiXAraaFjcPlHlqbf") @@ -18,6 +19,7 @@ var body: some Scene { WindowGroup { ContentView() + .environment(\.managedObjectContext, dataController.container.viewContext) } } }
--- a/GeoQuiz/GuessTheCapitalView.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/GuessTheCapitalView.swift Wed Oct 19 10:04:17 2022 +0200 @@ -10,6 +10,8 @@ struct GuessTheCapitalView: View { @StateObject var game = CountryGame() + @Environment(\.managedObjectContext) var moc + var body: some View { ZStack { LinearGradient(gradient: .secondary, startPoint: .top, endPoint: .bottom) @@ -62,7 +64,7 @@ } } .navigationBarHidden(true) - .modifier(GameAlertsModifier(game: game)) + .modifier(GameAlertsModifier(game: game, gameType: .guessTheCapital, moc: moc)) } }
--- a/GeoQuiz/GuessTheCountryView.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/GuessTheCountryView.swift Wed Oct 19 10:04:17 2022 +0200 @@ -10,6 +10,8 @@ struct GuessTheCountryView: View { @StateObject var game = CityGame() + @Environment(\.managedObjectContext) var moc + var body: some View { ZStack { LinearGradient(gradient: .tertiary, startPoint: .top, endPoint: .bottom) @@ -60,7 +62,7 @@ } } .navigationBarHidden(true) - .modifier(GameAlertsModifier(game: game)) + .modifier(GameAlertsModifier(game: game, gameType: .guessTheCountry, moc: moc)) } }
--- a/GeoQuiz/GuessTheFlagView.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/GuessTheFlagView.swift Wed Oct 19 10:04:17 2022 +0200 @@ -10,6 +10,8 @@ struct GuessTheFlagView: View { @StateObject var game = CountryGame() + @Environment(\.managedObjectContext) var moc + var body: some View { ZStack { LinearGradient(gradient: .main, startPoint: .top, endPoint: .bottom) @@ -62,7 +64,7 @@ } } .navigationBarHidden(true) - .modifier(GameAlertsModifier(game: game)) + .modifier(GameAlertsModifier(game: game, gameType: .guessTheFlag, moc: moc)) } }
--- a/GeoQuiz/GuessThePopulationView.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/GuessThePopulationView.swift Wed Oct 19 10:04:17 2022 +0200 @@ -10,6 +10,8 @@ struct GuessThePopulationView: View { @StateObject var game = CountryGame() + @Environment(\.managedObjectContext) var moc + var body: some View { ZStack { LinearGradient(gradient: .quaternary, startPoint: .top, endPoint: .bottom) @@ -63,7 +65,7 @@ } } .navigationBarHidden(true) - .modifier(GameAlertsModifier(game: game)) + .modifier(GameAlertsModifier(game: game, gameType: .guessThePopulation, moc: moc)) } }
--- a/GeoQuiz/Logic/CityGameClass.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/Logic/CityGameClass.swift Wed Oct 19 10:04:17 2022 +0200 @@ -32,7 +32,6 @@ // Alerts @Published var alertTitle = String() @Published var alertMessage = String() - @Published var showingGameOverAlert = false @Published var showingEndGameAlert = false @Published var showingWrongAnswerAlert = false @Published var showingExitGameAlert = false
--- a/GeoQuiz/Logic/CountryGameClass.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/Logic/CountryGameClass.swift Wed Oct 19 10:04:17 2022 +0200 @@ -32,7 +32,6 @@ // Alerts @Published var alertTitle = String() @Published var alertMessage = String() - @Published var showingGameOverAlert = false @Published var showingEndGameAlert = false @Published var showingWrongAnswerAlert = false @Published var showingExitGameAlert = false
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GeoQuiz/Logic/DataController.swift Wed Oct 19 10:04:17 2022 +0200 @@ -0,0 +1,21 @@ +// +// DataController.swift +// GeoQuiz +// +// Created by Dennis Concepción Martín on 19/10/22. +// + +import CoreData +import Foundation + +class DataController: ObservableObject { + let container = NSPersistentContainer(name: "GeoQuiz") + + init() { + container.loadPersistentStores { description, error in + if let error = error { + print("Core Data failed to load: \(error.localizedDescription)") + } + } + } +}
--- a/GeoQuiz/Logic/GameProtocol+Extension.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/Logic/GameProtocol+Extension.swift Wed Oct 19 10:04:17 2022 +0200 @@ -8,6 +8,7 @@ import Foundation import SwiftUI import AVFAudio +import CoreData protocol Game: ObservableObject { @@ -29,7 +30,6 @@ // Alerts var alertTitle: String { get set } var alertMessage: String { get set } - var showingGameOverAlert: Bool { get set } var showingEndGameAlert: Bool { get set } var showingWrongAnswerAlert: Bool { get set } var showingExitGameAlert: Bool { get set } @@ -91,7 +91,7 @@ if userLives == 0 { alertTitle = "🤕 Game over 🤕" alertMessage = "Get up and try again." - showingGameOverAlert = true + showingEndGameAlert = true } else { alertTitle = "🔴 Wrong 🔴" alertMessage = "You have \(userLives) lives left." @@ -107,14 +107,20 @@ } } - func reset(selector: () -> Void) { - dataAsked = [String: T]() - userScore = 0 - userLives = 3 - correctAnswers = [String: T]() - wrongAnswers = [String: T]() - askQuestion { - selector() + func save(_ gameType: GameType, with moc: NSManagedObjectContext) { + let playedGame = PlayedGame(context: moc) + + playedGame.id = UUID() + playedGame.type = gameType + playedGame.date = Date() + playedGame.score = Int32(userScore) + playedGame.correctAnswers = Array(correctAnswers.keys) + playedGame.wrongAnswers = Array(wrongAnswers.keys) + + do { + try moc.save() + } catch { + print("Couldn't save object to CoreData: \(error)") } }
--- a/GeoQuiz/Logic/GameTypeEnum.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/Logic/GameTypeEnum.swift Wed Oct 19 10:04:17 2022 +0200 @@ -7,6 +7,7 @@ import Foundation -enum GameType { +@objc +public enum GameType: Int16 { case guessTheFlag, guessTheCapital, guessTheCountry, guessThePopulation }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GeoQuiz/Logic/PlayedGame+CoreDataClass.swift Wed Oct 19 10:04:17 2022 +0200 @@ -0,0 +1,15 @@ +// +// PlayedGame+CoreDataClass.swift +// GeoQuiz +// +// Created by Dennis Concepción Martín on 19/10/22. +// +// + +import Foundation +import CoreData + +@objc(PlayedGame) +public class PlayedGame: NSManagedObject { + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GeoQuiz/Logic/PlayedGame+CoreDataProperties.swift Wed Oct 19 10:04:17 2022 +0200 @@ -0,0 +1,30 @@ +// +// PlayedGame+CoreDataProperties.swift +// GeoQuiz +// +// Created by Dennis Concepción Martín on 19/10/22. +// +// + +import Foundation +import CoreData + + +extension PlayedGame { + + @nonobjc public class func fetchRequest() -> NSFetchRequest<PlayedGame> { + return NSFetchRequest<PlayedGame>(entityName: "PlayedGame") + } + + @NSManaged public var id: UUID + @NSManaged public var type: GameType + @NSManaged public var score: Int32 + @NSManaged public var date: Date + @NSManaged public var correctAnswers: [String]? + @NSManaged public var wrongAnswers: [String]? + +} + +extension PlayedGame : Identifiable { + +}
--- a/GeoQuiz/ProfileModalView.swift Wed Oct 19 07:56:33 2022 +0200 +++ b/GeoQuiz/ProfileModalView.swift Wed Oct 19 10:04:17 2022 +0200 @@ -13,6 +13,11 @@ @ObservedObject var storeKitRC: StoreKitRC @Environment(\.dismiss) var dismiss + @Environment(\.managedObjectContext) var moc + + @FetchRequest(sortDescriptors: [ + SortDescriptor(\.date), + ]) var playedGames: FetchedResults<PlayedGame> @State private var showingEditModalView = false @@ -63,8 +68,11 @@ } Section { - ForEach(1..<10) { _ in - Text("Hello") + ForEach(playedGames) { playedGame in + HStack { + Text("\(playedGame.id)") + Text("\(playedGame.date)") + } } } header: { Text("Recent games")