From 7b6daef4c2a723c7a8a4c8395452bd88765d5d1d Mon Sep 17 00:00:00 2001 From: Avery Pace Date: Sun, 7 Nov 2021 13:03:41 -0500 Subject: [PATCH] Add overlay to flash cards, add a debug window for statistics --- Toki Trainer.xcodeproj/project.pbxproj | 4 +++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 8 ++--- .../Toki_Trainer.xcdatamodel/contents | 7 +++- Toki Trainer/Views/ContentView.swift | 15 ++++++--- Toki Trainer/Views/FlashCardResultView.swift | 30 +++++++++++++++++ Toki Trainer/Views/FlashCardView.swift | 33 +++++++++++++++++-- Toki Trainer/Views/PartsOfSpeechView.swift | 4 --- 7 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 Toki Trainer/Views/FlashCardResultView.swift diff --git a/Toki Trainer.xcodeproj/project.pbxproj b/Toki Trainer.xcodeproj/project.pbxproj index a1e0c6e..4c75fc5 100644 --- a/Toki Trainer.xcodeproj/project.pbxproj +++ b/Toki Trainer.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 7E943A28273211C300E7DDF4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7E943A27273211C300E7DDF4 /* Preview Assets.xcassets */; }; 7E943A2A273211C300E7DDF4 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E943A29273211C300E7DDF4 /* Persistence.swift */; }; 7E943A2D273211C300E7DDF4 /* Toki_Trainer.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 7E943A2B273211C300E7DDF4 /* Toki_Trainer.xcdatamodeld */; }; + 7EF546162737B8FB00537AE6 /* FlashCardResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EF546152737B8FA00537AE6 /* FlashCardResultView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -43,6 +44,7 @@ 7E943A27273211C300E7DDF4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 7E943A29273211C300E7DDF4 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; 7E943A2C273211C300E7DDF4 /* Toki_Trainer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Toki_Trainer.xcdatamodel; sourceTree = ""; }; + 7EF546152737B8FA00537AE6 /* FlashCardResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardResultView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -73,6 +75,7 @@ 7E943A22273211C200E7DDF4 /* ContentView.swift */, 7E20D5FE2733AFE700D75B9A /* PartsOfSpeechView.swift */, 7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */, + 7EF546152737B8FA00537AE6 /* FlashCardResultView.swift */, ); path = Views; sourceTree = ""; @@ -214,6 +217,7 @@ 7E20D6012734466800D75B9A /* TokiDictionaryViewModel.swift in Sources */, 7E2811192733027F0063DC78 /* TokiPartOfSpeech.swift in Sources */, 7E943A23273211C200E7DDF4 /* ContentView.swift in Sources */, + 7EF546162737B8FB00537AE6 /* FlashCardResultView.swift in Sources */, 7E2811172733027F0063DC78 /* TokiDictionary.swift in Sources */, 7E71E6ED2735D70C007CFF72 /* FlashCardView.swift in Sources */, 7E943A21273211C200E7DDF4 /* Toki_TrainerApp.swift in Sources */, diff --git a/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index edc97ec..e1bd7fc 100644 --- a/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -14,10 +14,10 @@ filePath = "Toki Trainer/Views/FlashCardView.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "194" - endingLineNumber = "194" - landmarkName = "CardFlipModifier" - landmarkType = "14"> + startingLineNumber = "223" + endingLineNumber = "223" + landmarkName = "init(isFaceDown:frontText:backText:)" + landmarkType = "7"> diff --git a/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents b/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents index 9ed2921..2b031dd 100644 --- a/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents +++ b/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents @@ -1,9 +1,14 @@ - + + + + + + \ No newline at end of file diff --git a/Toki Trainer/Views/ContentView.swift b/Toki Trainer/Views/ContentView.swift index bc5ceba..a088fa3 100644 --- a/Toki Trainer/Views/ContentView.swift +++ b/Toki Trainer/Views/ContentView.swift @@ -20,15 +20,20 @@ struct ContentView: View { var body: some View { TabView { TranslatorView() - .tabItem { - Image(systemName: "pencil") - Text("Phrase Lookup") - } + .tabItem { + Image(systemName: "pencil") + Text("Phrase Lookup") + } FlashCardView() .tabItem { Image(systemName: "character.textbox") Text("Flash Cards") } + FlashCardResultView() + .tabItem { + Image(systemName: "phone.fill") + Text("Flash Card Results") + } } } @@ -86,6 +91,6 @@ struct TranslatorView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } } diff --git a/Toki Trainer/Views/FlashCardResultView.swift b/Toki Trainer/Views/FlashCardResultView.swift new file mode 100644 index 0000000..471e16a --- /dev/null +++ b/Toki Trainer/Views/FlashCardResultView.swift @@ -0,0 +1,30 @@ +// +// FlashCardResultView.swift +// Toki Trainer +// +// Created by Avery Ada Pace on 11/7/21. +// + +import SwiftUI + +struct FlashCardResultView: View { + @Environment(\.managedObjectContext) private var viewContext + + @FetchRequest var flashCardAnswers: FetchedResults + + init() { + self._flashCardAnswers = FetchRequest(entity: FlashCardAnswer.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \FlashCardAnswer.word, ascending: true)], predicate: nil, animation: .none) + } + + var body: some View { + List(flashCardAnswers, id: \.self) { answer in + Text(answer.word ?? "Unknown") + } + } +} + +struct FlashCardResultView_Previews: PreviewProvider { + static var previews: some View { + FlashCardResultView() + } +} diff --git a/Toki Trainer/Views/FlashCardView.swift b/Toki Trainer/Views/FlashCardView.swift index 12b2bb1..ee5877b 100644 --- a/Toki Trainer/Views/FlashCardView.swift +++ b/Toki Trainer/Views/FlashCardView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import CoreData enum FlashCardResult { case Correct @@ -36,6 +37,7 @@ extension Binding { } struct FlashCardStack: View { + @Environment(\.managedObjectContext) private var viewContext var dictionary: [TokiDictEntry] @State private var flashCards: [FlashCard] = [] @@ -44,6 +46,7 @@ struct FlashCardStack: View { @State private var flashCardsAreInteractive: [Bool] = [] @State private var flashCardsVertOffset: [CGFloat] = [] @State private var flashCardsResults: [FlashCardResult] = [] + @State private var fadeOutOverlay = false @State private var currentFlashCard = 0 @@ -58,6 +61,13 @@ struct FlashCardStack: View { } } } + .overlay(HStack { + Image(systemName: "arrow.backward") + Text("Incorrect") + Spacer() + Text("Correct") + Image(systemName: "arrow.right") + }.opacity(fadeOutOverlay ? 0.0 : 1.0), alignment: .top) } Spacer() .onAppear { @@ -71,7 +81,7 @@ struct FlashCardStack: View { for index in dictionary.indices { flashCardsAreInteractive.append(false) flashCardsResults.append(FlashCardResult.Unanswered) - flashCards.append(FlashCard(isInteractive: $flashCardsAreInteractive[index], result: $flashCardsResults[index].onChange(nextFlashCard), dictionaryEntry: dictionary[index])) + flashCards.append(FlashCard(isInteractive: $flashCardsAreInteractive[index], result: $flashCardsResults[index].onChange(cardAnswerReceived), dictionaryEntry: dictionary[index])) flashCardsVertOffset.append(470) } if flashCards.count - currentFlashCard >= 3 { @@ -89,6 +99,21 @@ struct FlashCardStack: View { flashCardsAreInteractive[currentFlashCard] = true } + func cardAnswerReceived() { + let flashCardAnswer = FlashCardAnswer(context: viewContext) + flashCardAnswer.word = dictionary[currentFlashCard].word + if flashCardsResults[currentFlashCard] == FlashCardResult.Correct { + flashCardAnswer.correct = true + } else if flashCardsResults[currentFlashCard] == FlashCardResult.Incorrect { + flashCardAnswer.correct = false + } else { + return + } + try? viewContext.save() + + nextFlashCard() + } + func nextFlashCard() { currentFlashCard += 1 if(currentFlashCard > 0 ) { @@ -97,6 +122,8 @@ struct FlashCardStack: View { flashCardsVertOffset[currentFlashCard] = 100 flashCardsAreInteractive[currentFlashCard] = true + self.fadeOutOverlay = true + if flashCards.count - currentFlashCard >= 3 { flashCardsVertOffset[currentFlashCard + 1] = 410 flashCardsVertOffset[currentFlashCard + 2] = 440 @@ -146,6 +173,8 @@ struct FlashCard: View { } else if self.dragAmount > 20 { self.dragAmount = 500 self.result = FlashCardResult.Correct + } else { + self.dragAmount = 0 } } } @@ -228,6 +257,6 @@ struct CardFlipModifier: AnimatableModifier { struct FlashCardView_Previews: PreviewProvider { static var previews: some View { - FlashCardView() + FlashCardView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } } diff --git a/Toki Trainer/Views/PartsOfSpeechView.swift b/Toki Trainer/Views/PartsOfSpeechView.swift index f65ed6f..949bc59 100644 --- a/Toki Trainer/Views/PartsOfSpeechView.swift +++ b/Toki Trainer/Views/PartsOfSpeechView.swift @@ -14,10 +14,6 @@ struct PartsOfSpeechView: View { var partsOfSpeech: [TokiPartOfSpeech] -// init(selectedPartOfSpeech: String) { -// _selectedPartOfSpeech = State(initialValue: selectedPartOfSpeech) -// } - var body: some View { VStack { Text("Parts of Speech")