From ffa10947227800ee2dbd9a3d1400d658d62c38c1 Mon Sep 17 00:00:00 2001 From: Avery Pace Date: Sat, 6 Nov 2021 13:35:56 -0400 Subject: [PATCH] Stack of cards works properly, no animation --- Toki Trainer.xcodeproj/project.pbxproj | 4 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 16 ++++ .../ViewModels/FlashCardsViewModel.swift | 25 ++++++ .../ViewModels/TokiDictionaryViewModel.swift | 4 +- Toki Trainer/Views/FlashCardView.swift | 77 +++++++++++++++---- 5 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 Toki Trainer/ViewModels/FlashCardsViewModel.swift diff --git a/Toki Trainer.xcodeproj/project.pbxproj b/Toki Trainer.xcodeproj/project.pbxproj index 2d0a17e..a1e0c6e 100644 --- a/Toki Trainer.xcodeproj/project.pbxproj +++ b/Toki Trainer.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 7E28111D273302860063DC78 /* toki-dictionary.json in Resources */ = {isa = PBXBuildFile; fileRef = 7E28111B273302860063DC78 /* toki-dictionary.json */; }; 7E28112227330DD30063DC78 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E28112127330DD20063DC78 /* Constants.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 */; }; 7E943A23273211C200E7DDF4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E943A22273211C200E7DDF4 /* ContentView.swift */; }; 7E943A25273211C300E7DDF4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7E943A24273211C300E7DDF4 /* Assets.xcassets */; }; @@ -34,6 +35,7 @@ 7E28111B273302860063DC78 /* toki-dictionary.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "toki-dictionary.json"; sourceTree = ""; }; 7E28112127330DD20063DC78 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.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; }; 7E943A20273211C200E7DDF4 /* Toki_TrainerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toki_TrainerApp.swift; sourceTree = ""; }; 7E943A22273211C200E7DDF4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -79,6 +81,7 @@ isa = PBXGroup; children = ( 7E20D6002734466800D75B9A /* TokiDictionaryViewModel.swift */, + 7E71E6F02736DAE4007CFF72 /* FlashCardsViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -207,6 +210,7 @@ 7E943A2D273211C300E7DDF4 /* Toki_Trainer.xcdatamodeld in Sources */, 7E943A2A273211C300E7DDF4 /* Persistence.swift in Sources */, 7E20D5FF2733AFE700D75B9A /* PartsOfSpeechView.swift in Sources */, + 7E71E6F12736DAE4007CFF72 /* FlashCardsViewModel.swift in Sources */, 7E20D6012734466800D75B9A /* TokiDictionaryViewModel.swift in Sources */, 7E2811192733027F0063DC78 /* TokiPartOfSpeech.swift in Sources */, 7E943A23273211C200E7DDF4 /* ContentView.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 fd3f778..4eafe08 100644 --- a/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Toki Trainer.xcodeproj/xcuserdata/averyadapace.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -36,5 +36,21 @@ landmarkType = "24"> + + + + diff --git a/Toki Trainer/ViewModels/FlashCardsViewModel.swift b/Toki Trainer/ViewModels/FlashCardsViewModel.swift new file mode 100644 index 0000000..3c93748 --- /dev/null +++ b/Toki Trainer/ViewModels/FlashCardsViewModel.swift @@ -0,0 +1,25 @@ +// +// FlashCardsViewModel.swift +// Toki Trainer +// +// Created by Avery Ada Pace on 11/6/21. +// + +import Foundation + +class FlashCardsViewModel: ObservableObject { + + let jsonLoader = TokiJSONLoader() + + private var fullDictionary: [TokiDictEntry] = [] + @Published var randomDictionary: [TokiDictEntry] = [] + + init() { + if let safeDictionary = jsonLoader.loadDictionary() { + fullDictionary = safeDictionary + randomDictionary = safeDictionary + //randomDictionary.shuffle() + } + } + +} diff --git a/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift b/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift index e4d85e1..b55dd8b 100644 --- a/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift +++ b/Toki Trainer/ViewModels/TokiDictionaryViewModel.swift @@ -7,8 +7,8 @@ import Foundation -class TokiDictionaryViewModel: ObservableObject -{ +class TokiDictionaryViewModel: ObservableObject { + let jsonLoader: TokiJSONLoader = TokiJSONLoader() private var fullDictionary: [TokiDictEntry] = [] diff --git a/Toki Trainer/Views/FlashCardView.swift b/Toki Trainer/Views/FlashCardView.swift index 96fa485..7a83cde 100644 --- a/Toki Trainer/Views/FlashCardView.swift +++ b/Toki Trainer/Views/FlashCardView.swift @@ -9,28 +9,65 @@ import SwiftUI struct FlashCardView: View { + //@ObservedObject var tokiDictViewModel = TokiDictionaryViewModel() + @ObservedObject var flashCardsViewModel = FlashCardsViewModel() + var body: some View { VStack { - Spacer() - .frame(height: 100 - ) - FlashCard(canBeFlipped: true) - Spacer() - FlashCardStack() + //FlashCard(canBeFlipped: true, dictionaryEntry: tokiDictViewModel.dictionary.first!) + FlashCardStack(dictionary: flashCardsViewModel.randomDictionary) } } } struct FlashCardStack: View { + @State var dictionary: [TokiDictEntry] + @State private var flashCards: [FlashCard] = [] + @State private var flashCardsCanBeFlipped: [Bool] = [] + var body: some View { - ZStack { - ForEach(0 ..< 8) { item in - FlashCard(canBeFlipped: false) - .offset(x: 0, y: -30 * CGFloat(item)) + VStack { + ZStack { + ForEach(flashCards.indices, id: \.self) { i in + if i == 0 { + flashCards[0] + .offset(x: 0, y: -300) + .zIndex(0) + + } else if i < 10 { + flashCards[i] + .offset(x: 0, y: 30 * CGFloat(i)) + .zIndex(Double(-i)) + } + } } + .onAppear { + initFlashCardsArray() + flashCards[0].setCanBeFlipped(true) + } + Button { + self.popFromDictionary() + } label: { + Text("Next Card") + } + .background(.white) + .animation(.default) } } + + func initFlashCardsArray() { + flashCards = [] + for index in dictionary.indices { + flashCardsCanBeFlipped.append(false) + flashCards.append(FlashCard(canBeFlipped: $flashCardsCanBeFlipped[index], dictionaryEntry: dictionary[index])) + } + } + + func popFromDictionary() { + dictionary.removeFirst() + initFlashCardsArray() + } } struct FlashCard: View { @@ -38,28 +75,40 @@ struct FlashCard: View { @State var isFaceDown = false @State var rotationAngle: Double = 0 - @State var canBeFlipped: Bool + @Binding var canBeFlipped: Bool + + var dictionaryEntry: TokiDictEntry var body: some View { let flipDegrees = isFaceDown ? 0.0 : 180.0 Text("") - .modifier(CardFlipModifier(isFaceDown: isFaceDown, frontText: "linja", backText: "long, very thin, floppy thing, e.g. string, rope, hair, thread, cord, chain")) + .modifier(CardFlipModifier(isFaceDown: isFaceDown, frontText: dictionaryEntry.word, backText: concatenateDefinitions())) .frame(width: 0.8 * screen.width, height: 200.0) .font(.title) .rotation3DEffect(self.isFaceDown ? Angle(degrees: 180) : Angle(degrees: 0), axis: (x: 0.0, y: 10.0, z: 0.0)) .animation(.default) .onTapGesture { - if canBeFlipped == true { + print("onTapGesture called") + if self.canBeFlipped == true { self.isFaceDown.toggle() } } } + func concatenateDefinitions() -> String { + var result = String() + for definition in dictionaryEntry.definitions { + result.append(contentsOf: definition.definition) + } + return result + } + func setCanBeFlipped(_ input: Bool) { - canBeFlipped = input + print("setCanBeFlipped called") + self.canBeFlipped.toggle() } }