Lessons implementation
This commit is contained in:
parent
c2d0dfa5e6
commit
3bce439bc4
@ -15,6 +15,10 @@
|
||||
7E28111C273302860063DC78 /* toki-partsofspeech.json in Resources */ = {isa = PBXBuildFile; fileRef = 7E28111A273302860063DC78 /* toki-partsofspeech.json */; };
|
||||
7E28111D273302860063DC78 /* toki-dictionary.json in Resources */ = {isa = PBXBuildFile; fileRef = 7E28111B273302860063DC78 /* toki-dictionary.json */; };
|
||||
7E28112227330DD30063DC78 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E28112127330DD20063DC78 /* Constants.swift */; };
|
||||
7E716B3E273986E5009E2CF6 /* TokiLesson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E716B3D273986E5009E2CF6 /* TokiLesson.swift */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@ -35,6 +39,10 @@
|
||||
7E28111A273302860063DC78 /* toki-partsofspeech.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "toki-partsofspeech.json"; sourceTree = "<group>"; };
|
||||
7E28111B273302860063DC78 /* toki-dictionary.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "toki-dictionary.json"; sourceTree = "<group>"; };
|
||||
7E28112127330DD20063DC78 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
7E716B3D273986E5009E2CF6 /* TokiLesson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokiLesson.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardLessonsView.swift; sourceTree = "<group>"; };
|
||||
7E716B4327398D3D009E2CF6 /* FlashCardLessonsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardLessonsViewModel.swift; sourceTree = "<group>"; };
|
||||
7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardView.swift; sourceTree = "<group>"; };
|
||||
7E71E6F02736DAE4007CFF72 /* FlashCardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlashCardsViewModel.swift; sourceTree = "<group>"; };
|
||||
7E943A1D273211C200E7DDF4 /* Toki Trainer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Toki Trainer.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -64,6 +72,7 @@
|
||||
7E2811142733027F0063DC78 /* TokiDictionary.swift */,
|
||||
7E2811152733027F0063DC78 /* TokiJSONLoader.swift */,
|
||||
7E2811162733027F0063DC78 /* TokiPartOfSpeech.swift */,
|
||||
7E716B3D273986E5009E2CF6 /* TokiLesson.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@ -76,6 +85,7 @@
|
||||
7E20D5FE2733AFE700D75B9A /* PartsOfSpeechView.swift */,
|
||||
7E71E6EC2735D70C007CFF72 /* FlashCardView.swift */,
|
||||
7EF546152737B8FA00537AE6 /* FlashCardResultsView.swift */,
|
||||
7E716B4127398CDF009E2CF6 /* FlashCardLessonsView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -85,6 +95,7 @@
|
||||
children = (
|
||||
7E20D6002734466800D75B9A /* TokiDictionaryViewModel.swift */,
|
||||
7E71E6F02736DAE4007CFF72 /* FlashCardsViewModel.swift */,
|
||||
7E716B4327398D3D009E2CF6 /* FlashCardLessonsViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
@ -93,6 +104,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7E28111B273302860063DC78 /* toki-dictionary.json */,
|
||||
7E716B3F27398ABD009E2CF6 /* toki-lessons.json */,
|
||||
7E28111A273302860063DC78 /* toki-partsofspeech.json */,
|
||||
);
|
||||
path = "JSON Data";
|
||||
@ -197,6 +209,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7E943A28273211C300E7DDF4 /* Preview Assets.xcassets in Resources */,
|
||||
7E716B4027398ABD009E2CF6 /* toki-lessons.json in Resources */,
|
||||
7E943A25273211C300E7DDF4 /* Assets.xcassets in Resources */,
|
||||
7E28111D273302860063DC78 /* toki-dictionary.json in Resources */,
|
||||
7E28111C273302860063DC78 /* toki-partsofspeech.json in Resources */,
|
||||
@ -215,13 +228,16 @@
|
||||
7E20D5FF2733AFE700D75B9A /* PartsOfSpeechView.swift in Sources */,
|
||||
7E71E6F12736DAE4007CFF72 /* FlashCardsViewModel.swift in Sources */,
|
||||
7E20D6012734466800D75B9A /* TokiDictionaryViewModel.swift in Sources */,
|
||||
7E716B4427398D3D009E2CF6 /* FlashCardLessonsViewModel.swift in Sources */,
|
||||
7E2811192733027F0063DC78 /* TokiPartOfSpeech.swift in Sources */,
|
||||
7E943A23273211C200E7DDF4 /* ContentView.swift in Sources */,
|
||||
7EF546162737B8FB00537AE6 /* FlashCardResultsView.swift in Sources */,
|
||||
7E716B4227398CDF009E2CF6 /* FlashCardLessonsView.swift in Sources */,
|
||||
7E2811172733027F0063DC78 /* TokiDictionary.swift in Sources */,
|
||||
7E71E6ED2735D70C007CFF72 /* FlashCardView.swift in Sources */,
|
||||
7E943A21273211C200E7DDF4 /* Toki_TrainerApp.swift in Sources */,
|
||||
7E2811182733027F0063DC78 /* TokiJSONLoader.swift in Sources */,
|
||||
7E716B3E273986E5009E2CF6 /* TokiLesson.swift in Sources */,
|
||||
7E28112227330DD30063DC78 /* Constants.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -31,6 +31,17 @@ class TokiJSONLoader: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func loadLessons() -> [TokiLesson]? {
|
||||
let jsonData = loadJSON("toki-lessons")
|
||||
do {
|
||||
let decodedData = try JSONDecoder().decode([TokiLesson].self, from: jsonData!)
|
||||
return decodedData
|
||||
} catch {
|
||||
print("Decode error: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func loadJSON(_ resource: String) -> Data? {
|
||||
do {
|
||||
if let bundlePath = Bundle.main.path(forResource: resource, ofType: "json"), let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
|
||||
|
15
Toki Trainer/Models/TokiLesson.swift
Normal file
15
Toki Trainer/Models/TokiLesson.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// TokiLesson.swift
|
||||
// Toki Trainer
|
||||
//
|
||||
// Created by Avery Ada Pace on 11/8/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TokiLesson: Decodable {
|
||||
var lesson: String
|
||||
var words: [TokiDictEntry]
|
||||
}
|
||||
|
||||
|
22
Toki Trainer/ViewModels/FlashCardLessonsViewModel.swift
Normal file
22
Toki Trainer/ViewModels/FlashCardLessonsViewModel.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// FlashCardLessonsViewModel.swift
|
||||
// Toki Trainer
|
||||
//
|
||||
// Created by Avery Ada Pace on 11/8/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class FlashCardLessonsViewModel: ObservableObject {
|
||||
|
||||
let jsonLoader: TokiJSONLoader = TokiJSONLoader()
|
||||
|
||||
@Published var lessons: [TokiLesson] = []
|
||||
|
||||
|
||||
init() {
|
||||
if let safeLessons = jsonLoader.loadLessons() {
|
||||
lessons = safeLessons
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ struct ContentView: View {
|
||||
Image(systemName: "pencil")
|
||||
Text("Phrase Lookup")
|
||||
}
|
||||
FlashCardView()
|
||||
FlashCardLessonsView()
|
||||
.tabItem {
|
||||
Image(systemName: "character.textbox")
|
||||
Text("Flash Cards")
|
||||
|
30
Toki Trainer/Views/FlashCardLessonsView.swift
Normal file
30
Toki Trainer/Views/FlashCardLessonsView.swift
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// FlashCardLessonsView.swift
|
||||
// Toki Trainer
|
||||
//
|
||||
// Created by Avery Ada Pace on 11/8/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct FlashCardLessonsView: View {
|
||||
@ObservedObject var flashCardLessonsVM = FlashCardLessonsViewModel()
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List(flashCardLessonsVM.lessons, id: \.lesson) { lesson in
|
||||
NavigationLink(destination: FlashCardView(lesson.words)) {
|
||||
Text(lesson.lesson)
|
||||
.bold()
|
||||
}
|
||||
}
|
||||
.navigationBarTitle("Lessons")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FlashCardLessonsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
FlashCardLessonsView()
|
||||
}
|
||||
}
|
@ -18,9 +18,27 @@ struct FlashCardView: View {
|
||||
|
||||
@ObservedObject var flashCardsViewModel = FlashCardsViewModel()
|
||||
|
||||
@State var dictionary: [TokiDictEntry]?
|
||||
|
||||
init(_ passedDictionary: [TokiDictEntry]?) {
|
||||
if passedDictionary != nil {
|
||||
if let safePassedDictionary = passedDictionary {
|
||||
self.dictionary = safePassedDictionary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
FlashCardStack(dictionary: flashCardsViewModel.randomDictionary)
|
||||
FlashCardStack(dictionary: getDictionary())
|
||||
}
|
||||
}
|
||||
|
||||
func getDictionary() -> [TokiDictEntry] {
|
||||
if dictionary != nil {
|
||||
return dictionary ?? []
|
||||
} else {
|
||||
return flashCardsViewModel.randomDictionary
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +77,7 @@ struct FlashCardStack: View {
|
||||
ForEach(flashCards.indices, id: \.self) { index in
|
||||
flashCards[index]
|
||||
.offset(x: 0, y: flashCardsVertOffset[index])
|
||||
.zIndex(-(CGFloat(index * 100)))
|
||||
.zIndex(-(CGFloat(index * 10)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,9 +90,9 @@ struct FlashCardStack: View {
|
||||
}.opacity(fadeOutOverlay ? 0.0 : 1.0), alignment: .top)
|
||||
}
|
||||
Spacer()
|
||||
.onAppear {
|
||||
initFlashCards()
|
||||
}
|
||||
.onAppear {
|
||||
initFlashCards()
|
||||
}
|
||||
}
|
||||
|
||||
func initFlashCards() {
|
||||
@ -83,17 +101,17 @@ struct FlashCardStack: View {
|
||||
flashCardsAreInteractive.append(false)
|
||||
flashCardsResults.append(FlashCardResult.Unanswered)
|
||||
flashCards.append(FlashCard(isInteractive: $flashCardsAreInteractive[index], result: $flashCardsResults[index].onChange(cardAnswerReceived), dictionaryEntry: dictionary[index]))
|
||||
flashCardsVertOffset.append(470)
|
||||
flashCardsVertOffset.append(370)
|
||||
}
|
||||
if flashCards.count - currentFlashCard >= 3 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 440
|
||||
flashCardsVertOffset[currentFlashCard + 3] = 470
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 340
|
||||
flashCardsVertOffset[currentFlashCard + 3] = 370
|
||||
} else if flashCards.count - currentFlashCard == 2 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 440
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 340
|
||||
} else if flashCards.count - currentFlashCard == 1 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
}
|
||||
|
||||
flashCardsVertOffset[currentFlashCard] = 100
|
||||
@ -126,15 +144,15 @@ 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
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// 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()
|
||||
}
|
||||
|
||||
@ -160,14 +178,14 @@ struct FlashCardStack: View {
|
||||
self.fadeOutOverlay = true
|
||||
|
||||
if flashCards.count - currentFlashCard >= 3 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 440
|
||||
flashCardsVertOffset[currentFlashCard + 3] = 470
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 340
|
||||
flashCardsVertOffset[currentFlashCard + 3] = 370
|
||||
} else if flashCards.count - currentFlashCard == 2 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 440
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
flashCardsVertOffset[currentFlashCard + 2] = 340
|
||||
} else if flashCards.count - currentFlashCard == 1 {
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 410
|
||||
flashCardsVertOffset[currentFlashCard + 1] = 310
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +238,7 @@ struct FlashCard: View {
|
||||
|
||||
Text("")
|
||||
.modifier(CardFlipModifier(isFaceDown: isFaceDown, frontText: dictionaryEntry.word, backText: concatenateDefinitions()))
|
||||
.frame(width: 0.8 * screen.width, height: 200.0)
|
||||
.frame(width: 0.8 * screen.width)
|
||||
.offset(x: isFaceDown ? -dragAmount : dragAmount, y: abs(dragAmount) / 10)
|
||||
.rotationEffect(.degrees(isFaceDown ? -(dragAmount / 50) : dragAmount / 50))
|
||||
.font(.title)
|
||||
@ -298,6 +316,6 @@ struct CardFlipModifier: AnimatableModifier {
|
||||
|
||||
struct FlashCardView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
FlashCardView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
|
||||
FlashCardView(nil).environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user