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
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
6CEF7F7D2BC457E600E205F6 /* DataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7C2BC457E600E205F6 /* DataController.swift */; };
|
6CEF7F7D2BC457E600E205F6 /* DataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7C2BC457E600E205F6 /* DataController.swift */; };
|
||||||
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7F2BC4694900E205F6 /* WordAXCD.xcdatamodeld */; };
|
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F7F2BC4694900E205F6 /* WordAXCD.xcdatamodeld */; };
|
||||||
6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */; };
|
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 */; };
|
6CF439522B83541D004C3543 /* WordAXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439512B83541D004C3543 /* WordAXApp.swift */; };
|
||||||
6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; };
|
6CF439542B83541D004C3543 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF439532B83541D004C3543 /* MainView.swift */; };
|
||||||
6CF439562B83541E004C3543 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF439552B83541E004C3543 /* Assets.xcassets */; };
|
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 = "<group>"; };
|
6CEF7F7C2BC457E600E205F6 /* DataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DataController.swift; path = WordAX/Model/DataController.swift; sourceTree = "<group>"; };
|
||||||
6CEF7F802BC4694900E205F6 /* WordAX.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WordAX.xcdatamodel; sourceTree = "<group>"; };
|
6CEF7F802BC4694900E205F6 /* WordAX.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WordAX.xcdatamodel; sourceTree = "<group>"; };
|
||||||
6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataClass.swift"; sourceTree = "<group>"; };
|
6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||||
6CEF7F832BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
6CEF7F8B2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Flashcard+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||||
6CF4394E2B83541D004C3543 /* WordAX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WordAX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
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 = "<group>"; };
|
6CF439512B83541D004C3543 /* WordAXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordAXApp.swift; sourceTree = "<group>"; };
|
||||||
6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
6CF439532B83541D004C3543 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||||
@@ -76,8 +76,8 @@
|
|||||||
6CEF7F7B2BC456A100E205F6 /* Model */ = {
|
6CEF7F7B2BC456A100E205F6 /* Model */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
6CEF7F8B2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift */,
|
||||||
6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */,
|
6CEF7F822BC46B5900E205F6 /* Flashcard+CoreDataClass.swift */,
|
||||||
6CEF7F832BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift */,
|
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */,
|
6CEF7F812BC4694900E205F6 /* WordAXCD.xcdatamodeld in Sources */,
|
||||||
6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */,
|
6C81850C2B8BA6BC0033CF46 /* FlashCardListRowView.swift in Sources */,
|
||||||
6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */,
|
6CEF7F842BC46B5900E205F6 /* Flashcard+CoreDataClass.swift in Sources */,
|
||||||
6CEF7F852BC46B5900E205F6 /* Flashcard+CoreDataProperties.swift in Sources */,
|
6CEF7F8D2BC5613F00E205F6 /* Flashcard+CoreDataProperties.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import CoreData
|
|||||||
|
|
||||||
class DataController: ObservableObject {
|
class DataController: ObservableObject {
|
||||||
let container = NSPersistentContainer(name: "WordAXCD")
|
let container = NSPersistentContainer(name: "WordAXCD")
|
||||||
static let shared = DataController()
|
// static let shared = DataController()
|
||||||
|
typealias SpacedRepetitionMilestoneEnum = Flashcard.SpacedRepetitionMilestoneEnum
|
||||||
|
|
||||||
var viewContext: NSManagedObjectContext {
|
var viewContext: NSManagedObjectContext {
|
||||||
container.viewContext
|
container.viewContext
|
||||||
@@ -25,6 +26,7 @@ class DataController: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public func addFlashcard(name: String, description: String) {
|
||||||
public func addFlashcard(name: String, description: String) {
|
public func addFlashcard(name: String, description: String) {
|
||||||
let flashcard = Flashcard(context: viewContext)
|
let flashcard = Flashcard(context: viewContext)
|
||||||
flashcard.id = UUID()
|
flashcard.id = UUID()
|
||||||
@@ -38,8 +40,48 @@ class DataController: ObservableObject {
|
|||||||
try? viewContext.save()
|
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<Flashcard>(entityName: "Flashcard")
|
let request = NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
||||||
|
if predicate != nil {
|
||||||
|
request.predicate = predicate
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
return try viewContext.fetch(request)
|
return try viewContext.fetch(request)
|
||||||
@@ -47,4 +89,41 @@ class DataController: ObservableObject {
|
|||||||
return []
|
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
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,41 @@ import CoreData
|
|||||||
|
|
||||||
@objc(Flashcard)
|
@objc(Flashcard)
|
||||||
public class Flashcard: NSManagedObject {
|
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 {
|
func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum {
|
||||||
return SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone)
|
return SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Flashcard+CoreDataProperties.swift
|
// Flashcard+CoreDataProperties.swift
|
||||||
// WordAX
|
// 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 {
|
extension Flashcard {
|
||||||
|
// TODO: Get rid of shown and instead just use lastSeenOn == nil
|
||||||
|
|
||||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<Flashcard> {
|
@nonobjc public class func fetchRequest() -> NSFetchRequest<Flashcard> {
|
||||||
return NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
return NSFetchRequest<Flashcard>(entityName: "Flashcard")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ struct AddFlashCard: View {
|
|||||||
@State var text: String = ""
|
@State var text: String = ""
|
||||||
@State var description: String = ""
|
@State var description: String = ""
|
||||||
@Binding var isShowing: Bool
|
@Binding var isShowing: Bool
|
||||||
var addFlashCard: (String, String) -> Void
|
@Environment(\.managedObjectContext) var moc
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
@@ -31,7 +31,16 @@ struct AddFlashCard: View {
|
|||||||
}
|
}
|
||||||
ToolbarItemGroup(placement: .topBarTrailing) {
|
ToolbarItemGroup(placement: .topBarTrailing) {
|
||||||
Button(action: {
|
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
|
self.isShowing = false
|
||||||
}, label: {
|
}, label: {
|
||||||
Text("Create")
|
Text("Create")
|
||||||
@@ -46,8 +55,5 @@ struct AddFlashCard: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State var isShowing = true
|
@State var isShowing = true
|
||||||
func add(name: String, desc: String) {
|
return AddFlashCard(isShowing: $isShowing)
|
||||||
return
|
|
||||||
}
|
|
||||||
return AddFlashCard(isShowing: $isShowing, addFlashCard: add)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,27 +6,40 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import CoreData
|
||||||
|
|
||||||
struct AnkiView: View {
|
struct AnkiView: View {
|
||||||
@EnvironmentObject var model: WordAXModelView
|
@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<Flashcard>
|
||||||
|
|
||||||
@State var showDescription = false
|
@State var showDescription = false
|
||||||
var flashcard: Flashcard? {
|
|
||||||
model.getFlashCardsToDisplay()
|
|
||||||
}
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if flashcard != nil {
|
if !flashcards.isEmpty && flashcards.first != nil {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
VStack {
|
VStack {
|
||||||
FlashCardView(flashcard: flashcard!, showDescription: $showDescription)
|
if flashcards.first != nil {
|
||||||
if showDescription {
|
FlashCardView(flashcard: flashcards.first!, showDescription: $showDescription)
|
||||||
|
}
|
||||||
|
if showDescription && flashcards.first != nil {
|
||||||
// Text("How did you do?")
|
// Text("How did you do?")
|
||||||
// .font(.subheadline)
|
// .font(.subheadline)
|
||||||
// .foregroundStyle(.gray)
|
// .foregroundStyle(.gray)
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
NextRepetitionButtonView(
|
NextRepetitionButtonView(
|
||||||
buttonText: "Wrong",
|
buttonText: "Wrong",
|
||||||
nextMilestone: flashcard!.getSpacedRepetitionMilestone(),
|
nextMilestone: flashcards.first!.getSpacedRepetitionMilestone(),
|
||||||
flashcardId: flashcard!.id!,
|
flashcardId: flashcards.first!.id!,
|
||||||
width: geometry.size.width,
|
width: geometry.size.width,
|
||||||
color: .red,
|
color: .red,
|
||||||
geometry: geometry,
|
geometry: geometry,
|
||||||
@@ -35,8 +48,8 @@ struct AnkiView: View {
|
|||||||
)
|
)
|
||||||
NextRepetitionButtonView(
|
NextRepetitionButtonView(
|
||||||
buttonText: "Correct",
|
buttonText: "Correct",
|
||||||
nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone()),
|
nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone()),
|
||||||
flashcardId: flashcard!.id!,
|
flashcardId: flashcards.first!.id!,
|
||||||
width:geometry.size.width,
|
width:geometry.size.width,
|
||||||
color: .orange,
|
color: .orange,
|
||||||
geometry: geometry,
|
geometry: geometry,
|
||||||
@@ -45,8 +58,8 @@ struct AnkiView: View {
|
|||||||
)
|
)
|
||||||
NextRepetitionButtonView(
|
NextRepetitionButtonView(
|
||||||
buttonText: "Easy",
|
buttonText: "Easy",
|
||||||
nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone())),
|
nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone())),
|
||||||
flashcardId: flashcard!.id!,
|
flashcardId: flashcards.first!.id!,
|
||||||
width: geometry.size.width,
|
width: geometry.size.width,
|
||||||
color: .green,
|
color: .green,
|
||||||
geometry: geometry,
|
geometry: geometry,
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ struct FlashCardListView: View {
|
|||||||
@EnvironmentObject var model: WordAXModelView
|
@EnvironmentObject var model: WordAXModelView
|
||||||
@State var showDescription = true
|
@State var showDescription = true
|
||||||
@State var addFlashcard = false
|
@State var addFlashcard = false
|
||||||
|
// @ObservedObject var flashcards = DataController.shared.getAllFlashcards()
|
||||||
|
@FetchRequest(sortDescriptors: []) var flashcards: FetchedResults<Flashcard>
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
NavigationSplitView {
|
NavigationSplitView {
|
||||||
Group {
|
Group {
|
||||||
if !DataController.shared.getAllFlashcards().isEmpty {
|
if !flashcards.isEmpty {
|
||||||
List(DataController.shared.getAllFlashcards()) { flashcard in
|
List(flashcards) { flashcard in
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
FlashCardView(flashcard: flashcard, showDescription: $showDescription)
|
FlashCardView(flashcard: flashcard, showDescription: $showDescription)
|
||||||
} label: {
|
} label: {
|
||||||
@@ -44,13 +46,13 @@ struct FlashCardListView: View {
|
|||||||
Text("Select word to get details about")
|
Text("Select word to get details about")
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $addFlashcard, content: {
|
.sheet(isPresented: $addFlashcard, content: {
|
||||||
AddFlashCard(isShowing: $addFlashcard, addFlashCard: model.addFlashCard)
|
AddFlashCard(isShowing: $addFlashcard)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
//#Preview {
|
||||||
FlashCardListView()
|
// FlashCardListView()
|
||||||
.environmentObject(WordAXModelView())
|
// .environmentObject(WordAXModelView())
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct FlashCardView: View {
|
|||||||
Text("Last seen: " + model.getDateFormatter().string(from: flashcard.lastSeenOn!))
|
Text("Last seen: " + model.getDateFormatter().string(from: flashcard.lastSeenOn!))
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
}
|
}
|
||||||
|
Text("Next spaced repetition milestone: \(flashcard.nextSpacedRepetitionMilestone)")
|
||||||
if showDescription {
|
if showDescription {
|
||||||
flashcardText
|
flashcardText
|
||||||
.textSelection(.enabled)
|
.textSelection(.enabled)
|
||||||
@@ -47,6 +48,6 @@ struct FlashCardView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State var showDescription = false
|
@State var showDescription = false
|
||||||
return FlashCardView(flashcard: DataController.shared.getAllFlashcards()[0], showDescription: $showDescription)
|
return FlashCardView(flashcard: DataController().getAllFlashcards()[0], showDescription: $showDescription)
|
||||||
.environmentObject(WordAXModelView())
|
.environmentObject(WordAXModelView())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct NextRepetitionButtonView: View {
|
struct NextRepetitionButtonView: View {
|
||||||
let buttonText: String
|
let buttonText: String
|
||||||
let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum?
|
let nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum?
|
||||||
let flashcardId: UUID
|
let flashcardId: UUID
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
let color: Color
|
let color: Color
|
||||||
@@ -21,7 +21,8 @@ struct NextRepetitionButtonView: View {
|
|||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
model.ankiButtonClicked(flashcardId: flashcardId, milestone: nextMilestone)
|
// TODO: Fix this anki button clicked function
|
||||||
|
// model.ankiButtonClicked(flashcardId: flashcardId, milestone: nextMilestone)
|
||||||
self.showDescription = false
|
self.showDescription = false
|
||||||
}) {
|
}) {
|
||||||
VStack {
|
VStack {
|
||||||
@@ -49,6 +50,6 @@ extension ShapeStyle where Self == Color {
|
|||||||
|
|
||||||
//#Preview {
|
//#Preview {
|
||||||
// @State var showDescription = false
|
// @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())
|
// .environmentObject(WordAXModelView())
|
||||||
//}
|
//}
|
||||||
|
|||||||
@@ -8,112 +8,47 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct WordAX {
|
//struct WordAX {
|
||||||
struct FlashCard: Identifiable, Hashable {
|
// struct FlashCard: Identifiable, Hashable {
|
||||||
var id: Int
|
// var id: Int
|
||||||
var name: String
|
// var name: String
|
||||||
var description: String
|
// var description: String
|
||||||
var shown: Bool = false
|
// var shown: Bool = false
|
||||||
var nextSpacedRepetitionMilestone: SpacedRepetitionMilestoneEnum?
|
// var nextSpacedRepetitionMilestone: Flashcard.SpacedRepetitionMilestoneEnum?
|
||||||
var lastSeenOn: Date?
|
// var lastSeenOn: Date?
|
||||||
var shownCount: Int = 0
|
// var shownCount: Int = 0
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
enum FrequencyEnum: Int {
|
// enum FrequencyEnum: Int {
|
||||||
case Daily = 1
|
// case Daily = 1
|
||||||
case Weekly = 7
|
// case Weekly = 7
|
||||||
case BiWeekly = 14
|
// case BiWeekly = 14
|
||||||
case Monthly = 30
|
// case Monthly = 30
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
public mutating func add(flashcard: FlashCard) {
|
// public mutating func add(flashcard: FlashCard) {
|
||||||
self.flashcards.append(flashcard)
|
// self.flashcards.append(flashcard)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
@objc enum SpacedRepetitionMilestoneEnum: Int64, CaseIterable {
|
// struct Settings {
|
||||||
case Now = 0 // starting value
|
// var frequency: FrequencyEnum = .Daily
|
||||||
case OneMinute = 60 // 60 * 1
|
// var lastShownNew: Date?
|
||||||
case TenMinutes = 600 // 60 * 10
|
// var dateFormatter: DateFormatter
|
||||||
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
|
// var flashcards: [FlashCard] = []
|
||||||
case OneMonth = 2_592_000 // 24 * 60 * 60 * 30
|
// var settings: Settings
|
||||||
case TwoMonths = 5_184_000 // 24 * 60 * 60 * 60
|
//
|
||||||
case FiveMonths = 12_960_000 // 24 * 60 * 60 * 150
|
// init() {
|
||||||
case OneYear = 31_536_000 // 24 * 60 * 60 * 365
|
// self.flashcards = []
|
||||||
|
// let dateFormatter = DateFormatter()
|
||||||
static var allCasesSorted: [SpacedRepetitionMilestoneEnum] {
|
// dateFormatter.dateFormat = "dd/MM/YYYY"
|
||||||
allCases.sorted {$0.rawValue < $1.rawValue }
|
// 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))
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,63 +6,35 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
class WordAXModelView: ObservableObject {
|
class WordAXModelView: ObservableObject {
|
||||||
@Published private var model: WordAX
|
typealias SpacedRepetitionMilestoneEnum = Flashcard.SpacedRepetitionMilestoneEnum
|
||||||
typealias FlashCard = WordAX.FlashCard
|
|
||||||
typealias SpacedRepetitionMilestoneEnum = WordAX.SpacedRepetitionMilestoneEnum
|
let settings: Settings
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
model = WordAX()
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "dd/MM/YYYY"
|
||||||
|
self.settings = Settings(dateFormatter: dateFormatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var flashcards: [Flashcard] {
|
struct Settings {
|
||||||
DataController.shared.getAllFlashcards()
|
var dateFormatter: DateFormatter
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getFlashcards(moc: DataController) -> [Flashcard] {
|
||||||
|
moc.getAllFlashcards()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getDateFormatter() -> DateFormatter {
|
public func getDateFormatter() -> DateFormatter {
|
||||||
model.settings.dateFormatter
|
self.settings.dateFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getFlashCardsToDisplay() -> Flashcard? {
|
|
||||||
let flashcards = self.flashcards
|
|
||||||
|
|
||||||
if flashcards.count > 0 {
|
public func ankiButtonClicked(flashcardId: UUID, milestone: Flashcard.SpacedRepetitionMilestoneEnum?, moc: DataController) {
|
||||||
let notShownFlashCards = flashcards.filter({!$0.shown})
|
moc.setSpacedRepetitionMilestone(flashcardId: flashcardId, milestone: milestone)
|
||||||
if notShownFlashCards.count == 0 {
|
moc.flashcardShown(flashcardId: flashcardId)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,11 +65,11 @@ extension Date {
|
|||||||
return selfDate.year! < paramDate.year! || selfDate.month! < paramDate.month! || selfDate.day! < paramDate.day!
|
return selfDate.year! < paramDate.year! || selfDate.month! < paramDate.month! || selfDate.day! < paramDate.day!
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFrequency(frequency: WordAX.FrequencyEnum) -> Date {
|
// func addFrequency(frequency: WordAX.FrequencyEnum) -> Date {
|
||||||
self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60))
|
// self.addingTimeInterval(TimeInterval(frequency.rawValue * 24 * 60 * 60))
|
||||||
}
|
// }
|
||||||
|
|
||||||
func addSpacedRepetitionMilestone(milestone: WordAX.SpacedRepetitionMilestoneEnum?) -> Date {
|
func addSpacedRepetitionMilestone(milestone: Flashcard.SpacedRepetitionMilestoneEnum?) -> Date {
|
||||||
if milestone == nil {
|
if milestone == nil {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user