From 301e545f47d838f51facb760eadd6bcbddd91af5 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Wed, 10 Apr 2024 11:54:42 +0200 Subject: [PATCH] Got rid of WordAX class (so far without deleting, just to make sure if it's needed in the future) Moved AnkiView to use FetchRequest, still a couple of TODOs left --- WordAX.xcodeproj/project.pbxproj | 8 +- WordAX/Model/DataController.swift | 83 +++++++++- WordAX/Model/Flashcard+CoreDataClass.swift | 36 ++++- .../Model/Flashcard+CoreDataProperties.swift | 3 +- WordAX/Views/AddFlashCard.swift | 18 ++- WordAX/Views/AnkiView.swift | 37 +++-- WordAX/Views/FlashCardListView.swift | 16 +- WordAX/Views/FlashCardView.swift | 3 +- WordAX/Views/NextRepetitionButtonView.swift | 7 +- WordAX/WordAX.swift | 153 +++++------------- WordAX/WordAXModelView.swift | 72 +++------ 11 files changed, 240 insertions(+), 196 deletions(-) diff --git a/WordAX.xcodeproj/project.pbxproj b/WordAX.xcodeproj/project.pbxproj index 40afb5a..33cd776 100644 --- a/WordAX.xcodeproj/project.pbxproj +++ b/WordAX.xcodeproj/project.pbxproj @@ -19,7 +19,7 @@ 6CEF7F7D2BC457E600E205F6 /* DataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7C2BC457E600E205F6 /* DataController.swift */; }; 6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7F2BC4694900E205F6 /* WordAXCD.xcdatamodeld */; }; 6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */; }; - 6CEF7F852BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F832BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift */; }; + 6CEF7F8D2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F8B2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift */; }; 6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; }; 6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; }; 6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; }; @@ -39,7 +39,7 @@ 6CEF7F7C2BC457E600E205F6 /* DataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DataController.swift; path = WordAX/Model/DataController.swift; sourceTree = ""; }; 6CEF7F802BC4694900E205F6 /* WordAX.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WordAX.xcdatamodel; sourceTree = ""; }; 6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataClass.swift"; sourceTree = ""; }; - 6CEF7F832BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataProperties.swift"; sourceTree = ""; }; + 6CEF7F8B2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataProperties.swift"; sourceTree = ""; }; 6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = ""; }; 6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -76,8 +76,8 @@ 6CEF7F7B2BC456A100E205F6 /* Model */ = { isa = PBXGroup; children = ( + 6CEF7F8B2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift */, 6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */, - 6CEF7F832BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift */, ); path = Model; sourceTree = ""; @@ -206,7 +206,7 @@ 6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */, 6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */, 6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */, - 6CEF7F852BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift in Sources */, + 6CEF7F8D2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WordAX/Model/DataController.swift b/WordAX/Model/DataController.swift index 95c0f57..54882e8 100644 --- a/WordAX/Model/DataController.swift +++ b/WordAX/Model/DataController.swift @@ -10,7 +10,8 @@ import CoreData class DataController: ObservableObject { let container = NSPersistentContainer(name: "WordAXCD") - static let shared = DataController() +// static let shared = DataController() + typealias SpacedRepetitionMilestoneEnum = Flashcard.SpacedRepetitionMilestoneEnum var viewContext: NSManagedObjectContext { container.viewContext @@ -25,6 +26,7 @@ class DataController: ObservableObject { } } + // public func addFlashcard(name: String, description: String) { public func addFlashcard(name: String, description: String) { let flashcard = Flashcard(context: viewContext) flashcard.id = UUID() @@ -38,8 +40,48 @@ class DataController: ObservableObject { try? viewContext.save() } - public func getAllFlashcards() -> [Flashcard]{ + // TODO: Figure out if this does anything? + public func setNextSpacedRepetitionMilestone(flashcard: Flashcard) { + let current = SpacedRepetitionMilestoneEnum.allCasesSorted.firstIndex(of: flashcard.getSpacedRepetitionMilestone()) ?? SpacedRepetitionMilestoneEnum.allCases.count + let predicate = NSPredicate(format: "id == %@", flashcard.id! as CVarArg) + let flashcards = self.getAllFlashcards(predicate: predicate) + if !flashcards.isEmpty { + if current + 1 < SpacedRepetitionMilestoneEnum.allCases.count { + flashcards[0].nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCasesSorted[current + 1].rawValue + } + } + } + + public func setSpacedRepetitionMilestone(flashcardId: UUID, milestone: SpacedRepetitionMilestoneEnum?) { + let predicate = NSPredicate(format: "id == %@", flashcardId as CVarArg) + let flashcards = self.getAllFlashcards(predicate: predicate) + if !flashcards.isEmpty { + if milestone != nil { + flashcards[0].nextSpacedRepetitionMilestone = milestone!.rawValue + } else { + flashcards[0].nextSpacedRepetitionMilestone = 0 + } + if !flashcards[0].shown { + flashcards[0].shown = true + } + flashcards[0].lastSeenOn = Date() + } + } + + public func flashcardShown(flashcardId: UUID) { + let predicate = NSPredicate(format: "id == %@", flashcardId as CVarArg) + let flashcards = self.getAllFlashcards(predicate: predicate) + if !flashcards.isEmpty { + flashcards[0].shownCount += 1 + try? viewContext.save() + } + } + + public func getAllFlashcards(predicate: NSPredicate? = nil) -> [Flashcard]{ let request = NSFetchRequest(entityName: "Flashcard") + if predicate != nil { + request.predicate = predicate + } do { return try viewContext.fetch(request) @@ -47,4 +89,41 @@ class DataController: ObservableObject { return [] } } + +// public func getFlashCardsToDisplay() -> Flashcard? { +// let flashcards = self.getAllFlashcards() +// +// if flashcards.count > 0 { +// let notShownFlashCards = flashcards.filter({!$0.shown}) +// // if today is the date they're supposed to be shown +// +// let displayToday = flashcards.filter({ +// $0.lastSeenOn != nil && +// $0.lastSeenOn!.addSpacedRepetitionMilestone( +// milestone: SpacedRepetitionMilestoneEnum.getMilestoneFromInt( +// value: $0.nextSpacedRepetitionMilestone)) +// .isBeforeTodayOrToday() +// }) +// if displayToday.count > 0 { +// return displayToday.first! +// } +// +//// let shownWords = words.filter({ $0.shown }) +//// if shownWords.count == 0 { +// if notShownFlashCards.count == 0 { +// return nil +// } +// return notShownFlashCards.sorted(by: {$0.id < $1.id}).first +//// } +// // if today is the day to show a new word +//// let settings = model.settings +//// if shownWords.count == 0 || +//// settings.lastShownNew == nil || +//// settings.lastShownNew!.addFrequency(frequency: settings.frequency).isAfterToday() { +//// return words.first! +//// } +// } +// // otherwise show nothing +// return nil +// } } diff --git a/WordAX/Model/Flashcard+CoreDataClass.swift b/WordAX/Model/Flashcard+CoreDataClass.swift index e03b934..a7f942f 100644 --- a/WordAX/Model/Flashcard+CoreDataClass.swift +++ b/WordAX/Model/Flashcard+CoreDataClass.swift @@ -11,8 +11,42 @@ import CoreData @objc(Flashcard) public class Flashcard: NSManagedObject { - typealias SpacedRepetitionMilestoneEnum = WordAX.SpacedRepetitionMilestoneEnum + enum SpacedRepetitionMilestoneEnum: Int64, CaseIterable { + case Now = 0 // starting value + case OneMinute = 60 // 60 * 1 + case TenMinutes = 600 // 60 * 10 + case OneHour = 3600 // 60 * 60 + case OneDay = 86_400 // 24 * 60 * 60 + case OneWeek = 604_800 // 24 * 60 * 60 * 7 + case TwoWeeks = 1_209_600 // 24 * 60 * 60 * 14 + case OneMonth = 2_592_000 // 24 * 60 * 60 * 30 + case TwoMonths = 5_184_000 // 24 * 60 * 60 * 60 + case FiveMonths = 12_960_000 // 24 * 60 * 60 * 150 + case OneYear = 31_536_000 // 24 * 60 * 60 * 365 + + static var allCasesSorted: [SpacedRepetitionMilestoneEnum] { + allCases.sorted {$0.rawValue < $1.rawValue } + } + + static func getNext(milestone: SpacedRepetitionMilestoneEnum?) -> SpacedRepetitionMilestoneEnum? { + let sorted = SpacedRepetitionMilestoneEnum.allCasesSorted + if milestone == nil { + return sorted.first + } + let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})! + if milestoneIndex < SpacedRepetitionMilestoneEnum.allCasesSorted.count { + return sorted[milestoneIndex + 1] + } + return nil + } + + static func getMilestoneFromInt(value: Int64) -> SpacedRepetitionMilestoneEnum { + return SpacedRepetitionMilestoneEnum.allCasesSorted.first(where: {$0.rawValue == value}) ?? SpacedRepetitionMilestoneEnum.Now + } + + } + func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum { return SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) } diff --git a/WordAX/Model/Flashcard+CoreDataProperties.swift b/WordAX/Model/Flashcard+CoreDataProperties.swift index 7f3ceaa..e76a210 100644 --- a/WordAX/Model/Flashcard+CoreDataProperties.swift +++ b/WordAX/Model/Flashcard+CoreDataProperties.swift @@ -2,7 +2,7 @@ // Flashcard+CoreDataProperties.swift // WordAX // -// Created by Oliver Hnát on 08.04.2024. +// Created by Oliver Hnát on 09.04.2024. // // @@ -11,6 +11,7 @@ import CoreData extension Flashcard { + // TODO: Get rid of shown and instead just use lastSeenOn == nil @nonobjc public class func fetchRequest() -> NSFetchRequest { return NSFetchRequest(entityName: "Flashcard") diff --git a/WordAX/Views/AddFlashCard.swift b/WordAX/Views/AddFlashCard.swift index 03636ea..c38685c 100644 --- a/WordAX/Views/AddFlashCard.swift +++ b/WordAX/Views/AddFlashCard.swift @@ -11,7 +11,7 @@ struct AddFlashCard: View { @State var text: String = "" @State var description: String = "" @Binding var isShowing: Bool - var addFlashCard: (String, String) -> Void + @Environment(\.managedObjectContext) var moc var body: some View { NavigationStack { List { @@ -31,7 +31,16 @@ struct AddFlashCard: View { } ToolbarItemGroup(placement: .topBarTrailing) { Button(action: { - self.addFlashCard(self.text, self.description) + let flashcard = Flashcard(context: moc) + flashcard.id = UUID() + flashcard.name = self.text + flashcard.desc = self.description + flashcard.shown = false + flashcard.nextSpacedRepetitionMilestone = 0 + flashcard.lastSeenOn = nil + flashcard.shownCount = 0 + flashcard.dateAdded = Date() + try? moc.save() self.isShowing = false }, label: { Text("Create") @@ -46,8 +55,5 @@ struct AddFlashCard: View { #Preview { @State var isShowing = true - func add(name: String, desc: String) { - return - } - return AddFlashCard(isShowing: $isShowing, addFlashCard: add) + return AddFlashCard(isShowing: $isShowing) } diff --git a/WordAX/Views/AnkiView.swift b/WordAX/Views/AnkiView.swift index 75b40e1..81bb6fc 100644 --- a/WordAX/Views/AnkiView.swift +++ b/WordAX/Views/AnkiView.swift @@ -6,27 +6,40 @@ // import SwiftUI +import CoreData struct AnkiView: View { @EnvironmentObject var model: WordAXModelView + @Environment(\.managedObjectContext) var moc + @FetchRequest(sortDescriptors: [ + NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false), + NSSortDescriptor(key: "lastSeenOn", ascending: true) + ], predicate: NSCompoundPredicate(type: .or, subpredicates: [ + NSCompoundPredicate(type: .and, subpredicates: [ + NSPredicate(format: "%K != nil", "lastSeenOn"), + NSPredicate(format: "lastSeenOn + nextSpacedRepetitionMilestone < %@", Date() as CVarArg) + ]), + NSPredicate(format: "lastSeenOn == nil") + ])) var flashcards: FetchedResults + @State var showDescription = false - var flashcard: Flashcard? { - model.getFlashCardsToDisplay() - } + var body: some View { - if flashcard != nil { + if !flashcards.isEmpty && flashcards.first != nil { GeometryReader { geometry in VStack { - FlashCardView(flashcard: flashcard!, showDescription: $showDescription) - if showDescription { + if flashcards.first != nil { + FlashCardView(flashcard: flashcards.first!, showDescription: $showDescription) + } + if showDescription && flashcards.first != nil { // Text("How did you do?") // .font(.subheadline) // .foregroundStyle(.gray) HStack(alignment: .center) { NextRepetitionButtonView( buttonText: "Wrong", - nextMilestone: flashcard!.getSpacedRepetitionMilestone(), - flashcardId: flashcard!.id!, + nextMilestone: flashcards.first!.getSpacedRepetitionMilestone(), + flashcardId: flashcards.first!.id!, width: geometry.size.width, color: .red, geometry: geometry, @@ -35,8 +48,8 @@ struct AnkiView: View { ) NextRepetitionButtonView( buttonText: "Correct", - nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone()), - flashcardId: flashcard!.id!, + nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone()), + flashcardId: flashcards.first!.id!, width:geometry.size.width, color: .orange, geometry: geometry, @@ -45,8 +58,8 @@ struct AnkiView: View { ) NextRepetitionButtonView( buttonText: "Easy", - nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone())), - flashcardId: flashcard!.id!, + nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone())), + flashcardId: flashcards.first!.id!, width: geometry.size.width, color: .green, geometry: geometry, diff --git a/WordAX/Views/FlashCardListView.swift b/WordAX/Views/FlashCardListView.swift index cd28d34..e50378c 100644 --- a/WordAX/Views/FlashCardListView.swift +++ b/WordAX/Views/FlashCardListView.swift @@ -11,12 +11,14 @@ struct FlashCardListView: View { @EnvironmentObject var model: WordAXModelView @State var showDescription = true @State var addFlashcard = false +// @ObservedObject var flashcards = DataController.shared.getAllFlashcards() + @FetchRequest(sortDescriptors: []) var flashcards: FetchedResults var body: some View { GeometryReader { geometry in NavigationSplitView { Group { - if !DataController.shared.getAllFlashcards().isEmpty { - List(DataController.shared.getAllFlashcards()) { flashcard in + if !flashcards.isEmpty { + List(flashcards) { flashcard in NavigationLink { FlashCardView(flashcard: flashcard, showDescription: $showDescription) } label: { @@ -44,13 +46,13 @@ struct FlashCardListView: View { Text("Select word to get details about") } .sheet(isPresented: $addFlashcard, content: { - AddFlashCard(isShowing: $addFlashcard, addFlashCard: model.addFlashCard) + AddFlashCard(isShowing: $addFlashcard) }) } } } -#Preview { - FlashCardListView() - .environmentObject(WordAXModelView()) -} +//#Preview { +// FlashCardListView() +// .environmentObject(WordAXModelView()) +//} diff --git a/WordAX/Views/FlashCardView.swift b/WordAX/Views/FlashCardView.swift index 7324fa4..177b736 100644 --- a/WordAX/Views/FlashCardView.swift +++ b/WordAX/Views/FlashCardView.swift @@ -24,6 +24,7 @@ struct FlashCardView: View { Text("Last seen: " + model.getDateFormatter().string(from: flashcard.lastSeenOn!)) .font(.subheadline) } + Text("Next spaced repetition milestone: \(flashcard.nextSpacedRepetitionMilestone)") if showDescription { flashcardText .textSelection(.enabled) @@ -47,6 +48,6 @@ struct FlashCardView: View { #Preview { @State var showDescription = false - return FlashCardView(flashcard: DataController.shared.getAllFlashcards()[0], showDescription: $showDescription) + return FlashCardView(flashcard: DataController().getAllFlashcards()[0], showDescription: $showDescription) .environmentObject(WordAXModelView()) } diff --git a/WordAX/Views/NextRepetitionButtonView.swift b/WordAX/Views/NextRepetitionButtonView.swift index 77d382b..9bdffe9 100644 --- a/WordAX/Views/NextRepetitionButtonView.swift +++ b/WordAX/Views/NextRepetitionButtonView.swift @@ -9,7 +9,7 @@ import SwiftUI struct NextRepetitionButtonView: View { let buttonText: String - let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum? + let nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum? let flashcardId: UUID let width: CGFloat let color: Color @@ -21,7 +21,8 @@ struct NextRepetitionButtonView: View { @Environment(\.colorScheme) var colorScheme var body: some View { Button(action: { - model.ankiButtonClicked(flashcardId: flashcardId, milestone: nextMilestone) + // TODO: Fix this anki button clicked function +// model.ankiButtonClicked(flashcardId: flashcardId, milestone: nextMilestone) self.showDescription = false }) { VStack { @@ -49,6 +50,6 @@ extension ShapeStyle where Self == Color { //#Preview { // @State var showDescription = false -// return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) +// return NextRepetitionButtonView(buttonText: "Excellent", nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.OneDay, wordId: 0, showDescription: $showDescription) // .environmentObject(WordAXModelView()) //} diff --git a/WordAX/WordAX.swift b/WordAX/WordAX.swift index 3e57c85..bdd0526 100644 --- a/WordAX/WordAX.swift +++ b/WordAX/WordAX.swift @@ -8,112 +8,47 @@ import Foundation import SwiftUI -struct WordAX { - struct FlashCard: Identifiable, Hashable { - var id: Int - var name: String - var description: String - var shown: Bool = false - var nextSpacedRepetitionMilestone: SpacedRepetitionMilestoneEnum? - var lastSeenOn: Date? - var shownCount: Int = 0 - } - - enum FrequencyEnum: Int { - case Daily = 1 - case Weekly = 7 - case BiWeekly = 14 - case Monthly = 30 - } - - - public mutating func add(flashcard: FlashCard) { - self.flashcards.append(flashcard) - } - - - @objc enum SpacedRepetitionMilestoneEnum: Int64, CaseIterable { - case Now = 0 // starting value - case OneMinute = 60 // 60 * 1 - case TenMinutes = 600 // 60 * 10 - case OneHour = 3600 // 60 * 60 - case OneDay = 86_400 // 24 * 60 * 60 - case OneWeek = 604_800 // 24 * 60 * 60 * 7 - case TwoWeeks = 1_209_600 // 24 * 60 * 60 * 14 - case OneMonth = 2_592_000 // 24 * 60 * 60 * 30 - case TwoMonths = 5_184_000 // 24 * 60 * 60 * 60 - case FiveMonths = 12_960_000 // 24 * 60 * 60 * 150 - case OneYear = 31_536_000 // 24 * 60 * 60 * 365 - - static var allCasesSorted: [SpacedRepetitionMilestoneEnum] { - allCases.sorted {$0.rawValue < $1.rawValue } - } - - static func getNext(milestone: SpacedRepetitionMilestoneEnum?) -> SpacedRepetitionMilestoneEnum? { - let sorted = WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted - if milestone == nil { - return sorted.first - } - let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})! - if milestoneIndex < WordAX.SpacedRepetitionMilestoneEnum.allCasesSorted.count { - return sorted[milestoneIndex + 1] - } - return nil - } - - static func getMilestoneFromInt(value: Int64) -> SpacedRepetitionMilestoneEnum { - return SpacedRepetitionMilestoneEnum.allCasesSorted.first(where: {$0.rawValue == value}) ?? SpacedRepetitionMilestoneEnum.Now - } - - } - - struct Settings { - var frequency: FrequencyEnum = .Daily - var lastShownNew: Date? - var dateFormatter: DateFormatter - } - - public mutating func setNextSpacedRepetitionMilestone(flashcard: FlashCard) { - if flashcard.nextSpacedRepetitionMilestone != nil { - let current = SpacedRepetitionMilestoneEnum.allCasesSorted.firstIndex(of: flashcard.nextSpacedRepetitionMilestone!) ?? SpacedRepetitionMilestoneEnum.allCases.count - let index = flashcards.firstIndex(where:{$0.id == flashcard.id}) ?? nil - if current + 1 < SpacedRepetitionMilestoneEnum.allCases.count && index != nil { - flashcards[index!].nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCasesSorted[current + 1] - } else if index != nil { - flashcards[index!].nextSpacedRepetitionMilestone = nil - } - } - } - - public mutating func setSpacedRepetitionMilestone(flashcardId: Int, milestone: SpacedRepetitionMilestoneEnum?) { - let index = flashcards.firstIndex(where:{$0.id == flashcardId}) ?? nil - if index != nil { - flashcards[index!].nextSpacedRepetitionMilestone = milestone - if !flashcards[index!].shown { - flashcards[index!].shown = true - } - flashcards[index!].lastSeenOn = Date() - } - } - - public mutating func flashcardShown(flashcardId: Int) { - let index = flashcards.firstIndex(where:{$0.id == flashcardId}) ?? nil - if index != nil { - flashcards[index!].shownCount += 1 - } - - } - - var flashcards: [FlashCard] = [] - var settings: Settings - - init() { - self.flashcards = [] - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "dd/MM/YYYY" - self.settings = Settings(dateFormatter: dateFormatter) -// self.flashcards.append(FlashCard(id: 0, name: "Magnificent", description: "When something is awesome. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", shown: false)) -// self.flashcards.append(FlashCard(id: 1, name: "Mesmerising", description: "When something is beautiful", shown: false)) - } - -} +//struct WordAX { +// struct FlashCard: Identifiable, Hashable { +// var id: Int +// var name: String +// var description: String +// var shown: Bool = false +// var nextSpacedRepetitionMilestone: Flashcard.SpacedRepetitionMilestoneEnum? +// var lastSeenOn: Date? +// var shownCount: Int = 0 +// } +// +// enum FrequencyEnum: Int { +// case Daily = 1 +// case Weekly = 7 +// case BiWeekly = 14 +// case Monthly = 30 +// } +// +// +// public mutating func add(flashcard: FlashCard) { +// self.flashcards.append(flashcard) +// } +// +// +// struct Settings { +// var frequency: FrequencyEnum = .Daily +// var lastShownNew: Date? +// var dateFormatter: DateFormatter +// } +// +// +// var flashcards: [FlashCard] = [] +// var settings: Settings +// +// init() { +// self.flashcards = [] +// let dateFormatter = DateFormatter() +// dateFormatter.dateFormat = "dd/MM/YYYY" +// self.settings = Settings(dateFormatter: dateFormatter) +//// self.flashcards.append(FlashCard(id: 0, name: "Magnificent", description: "When something is awesome. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", shown: false)) +//// self.flashcards.append(FlashCard(id: 1, name: "Mesmerising", description: "When something is beautiful", shown: false)) +// } +// +//} diff --git a/WordAX/WordAXModelView.swift b/WordAX/WordAXModelView.swift index 0e4d0c3..061d1c1 100644 --- a/WordAX/WordAXModelView.swift +++ b/WordAX/WordAXModelView.swift @@ -6,63 +6,35 @@ // import Foundation +import SwiftUI class WordAXModelView: ObservableObject { - @Published private var model: WordAX - typealias FlashCard = WordAX.FlashCard - typealias SpacedRepetitionMilestoneEnum = WordAX.SpacedRepetitionMilestoneEnum + typealias SpacedRepetitionMilestoneEnum = Flashcard.SpacedRepetitionMilestoneEnum + + let settings: Settings + init() { - model = WordAX() + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "dd/MM/YYYY" + self.settings = Settings(dateFormatter: dateFormatter) } - public var flashcards: [Flashcard] { - DataController.shared.getAllFlashcards() + struct Settings { + var dateFormatter: DateFormatter + } + + public func getFlashcards(moc: DataController) -> [Flashcard] { + moc.getAllFlashcards() } public func getDateFormatter() -> DateFormatter { - model.settings.dateFormatter + self.settings.dateFormatter } - public func getFlashCardsToDisplay() -> Flashcard? { - let flashcards = self.flashcards - - if flashcards.count > 0 { - let notShownFlashCards = flashcards.filter({!$0.shown}) - if notShownFlashCards.count == 0 { - return nil - } - // if today is the date they're supposed to be shown - - let displayToday = flashcards.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: $0.nextSpacedRepetitionMilestone)).isBeforeTodayOrToday()}) - if displayToday.count > 0 { - return displayToday.first! - } - -// let shownWords = words.filter({ $0.shown }) -// if shownWords.count == 0 { - return notShownFlashCards.sorted(by: {$0.id < $1.id}).first -// } - // if today is the day to show a new word -// let settings = model.settings -// if shownWords.count == 0 || -// settings.lastShownNew == nil || -// settings.lastShownNew!.addFrequency(frequency: settings.frequency).isAfterToday() { -// return words.first! -// } - } - // otherwise show nothing - return nil - } - public func ankiButtonClicked(flashcardId: UUID, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { - // TODO: Fix this with Core Data -// model.setSpacedRepetitionMilestone(flashcardId: flashcardId, milestone: milestone) -// model.flashcardShown(flashcardId: flashcardId) - } - - public func addFlashCard(name: String, description: String) { -// self.model.add(flashcard: FlashCard(id: (self.flashcards.map{$0.id}.max() ?? -1) + 1, name: name, description: description)) - DataController.shared.addFlashcard(name: name, description: description) + public func ankiButtonClicked(flashcardId: UUID, milestone: Flashcard.SpacedRepetitionMilestoneEnum?, moc: DataController) { + moc.setSpacedRepetitionMilestone(flashcardId: flashcardId, milestone: milestone) + moc.flashcardShown(flashcardId: flashcardId) } } @@ -93,11 +65,11 @@ extension Date { return selfDate.year! < paramDate.year! || selfDate.month! < paramDate.month! || selfDate.day! < paramDate.day! } - func addFrequency(frequency: WordAX.FrequencyEnum) -> Date { - self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) - } +// func addFrequency(frequency: WordAX.FrequencyEnum) -> Date { +// self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60)) +// } - func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum?) -> Date { + func addSpacedRepetitionMilestone(milestone: Flashcard.SpacedRepetitionMilestoneEnum?) -> Date { if milestone == nil { return self }