From 1c928fa8765378b9690e4d14a4e4c3c8b94c9dc9 Mon Sep 17 00:00:00 2001 From: Avery Pace Date: Tue, 9 Nov 2021 13:17:22 -0500 Subject: [PATCH] Flash Cards now used stored lesson information --- Toki Trainer.xcodeproj/project.pbxproj | 4 + Toki Trainer/Constants.swift | 7 ++ .../Toki_Trainer.xcdatamodel/contents | 6 ++ .../Views/FlashCardLessonResultsView.swift | 20 +++++ Toki Trainer/Views/FlashCardLessonsView.swift | 64 +++++++++++++- Toki Trainer/Views/FlashCardResultsView.swift | 9 -- Toki Trainer/Views/FlashCardView.swift | 83 ++++++++++++------- 7 files changed, 151 insertions(+), 42 deletions(-) create mode 100644 Toki Trainer/Views/FlashCardLessonResultsView.swift diff --git a/Toki Trainer.xcodeproj/project.pbxproj b/Toki Trainer.xcodeproj/project.pbxproj index 8ff750e..508d38f 100644 --- a/Toki Trainer.xcodeproj/project.pbxproj +++ b/Toki Trainer.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 7E716B4027398ABD009E2CF6 /* toki-lessons.json in Resources */ = {isa = PBXBuildFile; fileRef = 7E716B3F27398ABD009E2CF6 /* toki-lessons.json */; }; 7E716B4227398CDF009E2CF6 /* FlashCardLessonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */; }; 7E716B4427398D3D009E2CF6 /* FlashCardLessonsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E716B4327398D3D009E2CF6 /* FlashCardLessonsViewModel.swift */; }; + 7E716B462739B968009E2CF6 /* FlashCardLessonResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E716B452739B968009E2CF6 /* FlashCardLessonResultsView.swift */; }; 7E71E6ED2735D70C007CFF72 /* FlashCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */; }; 7E71E6F12736DAE4007CFF72 /* FlashCardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E71E6F02736DAE4007CFF72 /* FlashCardsViewModel.swift */; }; 7E943A21273211C200E7DDF4 /* Toki_TrainerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E943A20273211C200E7DDF4 /* Toki_TrainerApp.swift */; }; @@ -43,6 +44,7 @@ 7E716B3F27398ABD009E2CF6 /* toki-lessons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "toki-lessons.json"; path = "../../../../../Desktop/toki-pona-dict-json/output/toki-lessons.json"; sourceTree = ""; }; 7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardLessonsView.swift; sourceTree = ""; }; 7E716B4327398D3D009E2CF6 /* FlashCardLessonsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardLessonsViewModel.swift; sourceTree = ""; }; + 7E716B452739B968009E2CF6 /* FlashCardLessonResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardLessonResultsView.swift; sourceTree = ""; }; 7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardView.swift; sourceTree = ""; }; 7E71E6F02736DAE4007CFF72 /* FlashCardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardsViewModel.swift; sourceTree = ""; }; 7E943A1D273211C200E7DDF4 /* Toki Trainer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Toki Trainer.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -86,6 +88,7 @@ 7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */, 7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */, 7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */, + 7E716B452739B968009E2CF6 /* FlashCardLessonResultsView.swift */, ); path = Views; sourceTree = ""; @@ -236,6 +239,7 @@ 7E2811172733027F0063DC78 /* TokiDictionary.swift in Sources */, 7E71E6ED2735D70C007CFF72 /* FlashCardView.swift in Sources */, 7E943A21273211C200E7DDF4 /* Toki_TrainerApp.swift in Sources */, + 7E716B462739B968009E2CF6 /* FlashCardLessonResultsView.swift in Sources */, 7E2811182733027F0063DC78 /* TokiJSONLoader.swift in Sources */, 7E716B3E273986E5009E2CF6 /* TokiLesson.swift in Sources */, 7E28112227330DD30063DC78 /* Constants.swift in Sources */, diff --git a/Toki Trainer/Constants.swift b/Toki Trainer/Constants.swift index 452977d..ad5eded 100644 --- a/Toki Trainer/Constants.swift +++ b/Toki Trainer/Constants.swift @@ -39,4 +39,11 @@ struct K { return request } + + static var getLessonAnswersFetchRequest: NSFetchRequest { + let request: NSFetchRequest = LessonAnswer.fetchRequest() + request.sortDescriptors = [] + + return request + } } diff --git a/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents b/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents index c6b2f32..b0681b1 100644 --- a/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents +++ b/Toki Trainer/Toki_Trainer.xcdatamodeld/Toki_Trainer.xcdatamodel/contents @@ -8,8 +8,14 @@ + + + + + + \ No newline at end of file diff --git a/Toki Trainer/Views/FlashCardLessonResultsView.swift b/Toki Trainer/Views/FlashCardLessonResultsView.swift new file mode 100644 index 0000000..41943d2 --- /dev/null +++ b/Toki Trainer/Views/FlashCardLessonResultsView.swift @@ -0,0 +1,20 @@ +// +// FlashCardLessonsResultsView.swift +// Toki Trainer +// +// Created by Avery Ada Pace on 11/8/21. +// + +import SwiftUI + +struct FlashCardLessonsResultsView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct FlashCardLessonsResultsView_Previews: PreviewProvider { + static var previews: some View { + FlashCardLessonsResultsView() + } +} diff --git a/Toki Trainer/Views/FlashCardLessonsView.swift b/Toki Trainer/Views/FlashCardLessonsView.swift index 2eae3b0..b764a7c 100644 --- a/Toki Trainer/Views/FlashCardLessonsView.swift +++ b/Toki Trainer/Views/FlashCardLessonsView.swift @@ -8,14 +8,76 @@ import SwiftUI struct FlashCardLessonsView: View { + @Environment(\.managedObjectContext) private var viewContext + + @FetchRequest(fetchRequest: K.getFlashCardAnswersFetchRequest) var answers: FetchedResults + @FetchRequest(fetchRequest: K.getLessonAnswersFetchRequest) var lessonAnswers: FetchedResults + @ObservedObject var flashCardLessonsVM = FlashCardLessonsViewModel() + @State private var lessonStatistics: [String: Double] = [:] + @State private var statisticsCalculated = false + + func calculateStatistics(_ lesson: TokiLesson) { + for lessonAnswer in lessonAnswers { + if lessonAnswer.lesson == lesson.lesson { + self.lessonStatistics[lesson.lesson] = (Double(lessonAnswer.correctCount) / Double(lessonAnswer.triesCount) * 100) + } + } + self.statisticsCalculated = true + } +// func calculateStatistics(_ lesson: TokiLesson) { +// for answer in answers { +// wordStatistics[answer.word!] = (Double(answer.correctCount) / Double(answer.triesCount)) * 100 +// } +// +// +// for word in lesson.words { +// buildLessonStatistics[lesson.lesson] = [] +// buildLessonStatistics[lesson.lesson]?.append(wordStatistics[word.word]!) +// } +// +// for (key, value) in buildLessonStatistics { +// let sumArray = value.reduce(0, +) +// let avgArrayValue = sumArray / Double(value.count) +// lessonStatistics[key] = avgArrayValue +// } +// +// +//// for word in lesson.words { +//// for answer in answers { +//// if answer.word == word.word { +//// lessonStatistics[lesson.lesson] = (Double(answer.correctCount) / Double(answer.triesCount)) * 100 +//// } +//// } +//// } +// self.statisticsCalculated = true +// } + + func calculateBackgroundColor(_ percent: Double) -> Color { + if percent >= 80 { + return Color.green + } else if percent >= 40 { + return Color.yellow + } else { + return Color.red + } + } + var body: some View { NavigationView { List(flashCardLessonsVM.lessons, id: \.lesson) { lesson in - NavigationLink(destination: FlashCardView(lesson.words)) { + NavigationLink(destination: FlashCardView(lesson: lesson.lesson, passedDictionary: lesson.words)) { Text(lesson.lesson) .bold() + .onAppear { + calculateStatistics(lesson) + } + Spacer() + if statisticsCalculated && lessonStatistics[lesson.lesson] != 0.0 && lessonStatistics[lesson.lesson] != nil { + Text("\(String(format: "%.0f", lessonStatistics[lesson.lesson]!)) %") + .multilineTextAlignment(.leading) + } } } .navigationBarTitle("Lessons") diff --git a/Toki Trainer/Views/FlashCardResultsView.swift b/Toki Trainer/Views/FlashCardResultsView.swift index 62d0d49..b50b5c8 100644 --- a/Toki Trainer/Views/FlashCardResultsView.swift +++ b/Toki Trainer/Views/FlashCardResultsView.swift @@ -16,7 +16,6 @@ struct FlashCardResultsView: View { @State private var wordStatistics: [String: Double] = [:] @State private var sortedWordStatistics: [(String, Double)] = [] - @State private var statistics = 0.0 func calculateStatistics() { for answer in answers { @@ -38,7 +37,6 @@ struct FlashCardResultsView: View { } else { return Color.red } - } @@ -57,13 +55,6 @@ struct FlashCardResultsView: View { } } -extension Double { - func formatAsPercent(places: Int) -> String { - let formattedValue = String(format: "%.2f", self) - return formattedValue - } -} - struct FlashCardResultView_Previews: PreviewProvider { static var previews: some View { FlashCardResultsView() diff --git a/Toki Trainer/Views/FlashCardView.swift b/Toki Trainer/Views/FlashCardView.swift index 24945f9..610b37d 100644 --- a/Toki Trainer/Views/FlashCardView.swift +++ b/Toki Trainer/Views/FlashCardView.swift @@ -18,30 +18,28 @@ struct FlashCardView: View { @ObservedObject var flashCardsViewModel = FlashCardsViewModel() - @State var dictionary: [TokiDictEntry]? + @State var currentLesson: String + @State var dictionary: [TokiDictEntry] - init(_ passedDictionary: [TokiDictEntry]?) { - if passedDictionary != nil { - if let safePassedDictionary = passedDictionary { - self.dictionary = safePassedDictionary - } - } + init(lesson: String, passedDictionary: [TokiDictEntry]) { + self.dictionary = passedDictionary + currentLesson = lesson } var body: some View { VStack { - FlashCardStack(dictionary: getDictionary()) + FlashCardStack(currentLesson: currentLesson, dictionary: dictionary) } } - func getDictionary() -> [TokiDictEntry] { - if dictionary != nil { - dictionary?.shuffle() - return dictionary ?? [] - } else { - return flashCardsViewModel.randomDictionary - } - } +// func getDictionary() -> [TokiDictEntry] { +// if dictionary != nil { +// dictionary?.shuffle() +// return dictionary ?? [] +// } else { +// return flashCardsViewModel.randomDictionary +// } +// } } extension Binding { @@ -59,7 +57,9 @@ struct FlashCardStack: View { @Environment(\.managedObjectContext) private var viewContext @FetchRequest(fetchRequest: K.getFlashCardAnswersFetchRequest) var flashCardAnswers: FetchedResults + @FetchRequest(fetchRequest: K.getLessonAnswersFetchRequest) var lessonAnswers: FetchedResults + var currentLesson: String var dictionary: [TokiDictEntry] @State private var flashCards: [FlashCard] = [] @State private var topFlashCard: FlashCard? = nil @@ -135,6 +135,28 @@ struct FlashCardStack: View { } } + var lessonInDatabase = false + for lessonAnswer in lessonAnswers { + if lessonAnswer.lesson == currentLesson { + lessonInDatabase = true + lessonAnswer.setValue((lessonAnswer.triesCount + 1), forKey: "triesCount") + if correct { + lessonAnswer.setValue((lessonAnswer.correctCount + 1), forKey: "correctCount") + } + print("lesson found in database") + } + } + + if lessonInDatabase == false { + let lessonAnswer = LessonAnswer(context: viewContext) + lessonAnswer.lesson = currentLesson + lessonAnswer.triesCount = 1 + if correct { + lessonAnswer.correctCount = 1 + } + print("lesson not found in database") + } + if cardInDatabase == false { let answer = FlashCardAnswer(context: viewContext) answer.word = dictionary[currentFlashCard].word @@ -145,15 +167,6 @@ struct FlashCardStack: View { print("answer not found in database") } - // for answer in flashCardAnswers { - // if answer.word == dictionary[currentFlashCard].word { - // flashCardAnswer.word = answer.word - // flashCardAnswer.triesCount = answer.triesCount + 1 - // if correct { - // flashCardAnswer.correctCount = answer.correctCount + 1 - // } - // } - // } try? viewContext.save() } @@ -169,23 +182,27 @@ struct FlashCardStack: View { } func nextFlashCard() { - currentFlashCard += 1 - if(currentFlashCard > 0 ) { - flashCardsVertOffset[currentFlashCard - 1] = -1000 + flashCardsVertOffset[currentFlashCard] = -1000 + if currentFlashCard == (flashCards.count - 1) { + return } + currentFlashCard += 1 flashCardsVertOffset[currentFlashCard] = 50 flashCardsAreInteractive[currentFlashCard] = true + self.fadeOutOverlay = true - if flashCards.count - currentFlashCard >= 3 { + if ((flashCards.count - 1) - currentFlashCard) > 3 { + print("flashCards: \(flashCards.count)") + print("currentFlashCard: \(currentFlashCard)") flashCardsVertOffset[currentFlashCard + 1] = 310 flashCardsVertOffset[currentFlashCard + 2] = 340 flashCardsVertOffset[currentFlashCard + 3] = 370 - } else if flashCards.count - currentFlashCard == 2 { + } else if (flashCards.count - 1) - currentFlashCard > 2 { flashCardsVertOffset[currentFlashCard + 1] = 310 flashCardsVertOffset[currentFlashCard + 2] = 340 - } else if flashCards.count - currentFlashCard == 1 { + } else if (flashCards.count - 1) - currentFlashCard > 1 { flashCardsVertOffset[currentFlashCard + 1] = 310 } } @@ -317,7 +334,9 @@ struct CardFlipModifier: AnimatableModifier { } struct FlashCardView_Previews: PreviewProvider { + static var viewModel = TokiDictionaryViewModel() + static var previews: some View { - FlashCardView(nil).environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) + FlashCardView(lesson: "Preview", passedDictionary: viewModel.dictionary).environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } }