From 38b01b4a7e96e076b0673ca8d277119487142834 Mon Sep 17 00:00:00 2001 From: oliverhnat Date: Mon, 29 Apr 2024 16:41:47 +0200 Subject: [PATCH] When countdown finishes, fetch requests reload --- README.md | 4 +- WordAX/Model/DataController.swift | 5 +- WordAX/Model/Flashcard+CoreDataClass.swift | 4 +- WordAX/Views/AnkiView.swift | 69 +++++++++------------ WordAX/Views/ButtonHStackView.swift | 4 ++ WordAX/Views/NextRepetitionButtonView.swift | 2 + 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 9a631f6..4cee5de 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Why settle for pricey apps when you can have WordAX? We're here to prove that ef ## Roadmap - [ ] Anki card "store" - download any anki flashcards you want from the online store that already exists somewhere + - [ ] Export your anki to the store? - [ ] Import anki cards in the .anki format - [x] Create flashcards - [ ] Add tags to cards @@ -65,8 +66,7 @@ Why settle for pricey apps when you can have WordAX? We're here to prove that ef - [x] For start store them on the phone - stored using Core Data - [ ] Maybe later add a storage in cloud, so that you can sync with other devices if the app is multi-platform? - [ ] Add some animations? -- [ ] Implement logic -- [ ] Export your anki to the store? +- [x] Implement logic - [ ] Make an apple watch version of the app

(back to top)

diff --git a/WordAX/Model/DataController.swift b/WordAX/Model/DataController.swift index 512672f..96fb8ca 100644 --- a/WordAX/Model/DataController.swift +++ b/WordAX/Model/DataController.swift @@ -30,7 +30,7 @@ class DataController: ObservableObject { "This is a medium length description that should be long enough to cover all cases" ].randomElement()! flashcard.nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCases.randomElement()!.rawValue - flashcard.lastSeenOn = [nil, Date(), Date().addingTimeInterval([-86400, -24000, -100000].randomElement()!)].randomElement()! + flashcard.lastSeenOn = [nil, Date(), Date().addingTimeInterval([-86400, -24000, -100000].randomElement()!)].randomElement()! flashcard.shownCount = [0, 1, 2, 3, 4, 5].randomElement()! flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()! } @@ -120,6 +120,9 @@ extension Int { // else { // result = "\(self)" // } + if days == 0 && hours == 0 && minutes == 0 { + return "\(seconds)s" + } return result diff --git a/WordAX/Model/Flashcard+CoreDataClass.swift b/WordAX/Model/Flashcard+CoreDataClass.swift index d6d9f56..b650601 100644 --- a/WordAX/Model/Flashcard+CoreDataClass.swift +++ b/WordAX/Model/Flashcard+CoreDataClass.swift @@ -35,6 +35,7 @@ public class Flashcard: NSManagedObject { } let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})! if milestoneIndex < sorted.count { + // 1 minute is only if answer was wrong, so 10 minutes is the first valid milestone return sorted[milestoneIndex + 1] == .OneMinute ? .TenMinutes : sorted[milestoneIndex + 1] } return .OneYear @@ -47,7 +48,6 @@ public class Flashcard: NSManagedObject { } func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum { - let milestone = SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) - return milestone == .OneMinute ? .TenMinutes : milestone + SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) } } diff --git a/WordAX/Views/AnkiView.swift b/WordAX/Views/AnkiView.swift index b01ff5e..e305c0a 100644 --- a/WordAX/Views/AnkiView.swift +++ b/WordAX/Views/AnkiView.swift @@ -9,30 +9,12 @@ import SwiftUI import CoreData struct AnkiView: View { - // @EnvironmentObject var model: WordAXModelView @Environment(\.managedObjectContext) var moc - // get flashcards to display - // @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 - - // get the most recent flashcard - // @FetchRequest(sortDescriptors: [], - // predicate: NSPredicate(format: "%K != nil", "lastSeenOn")) var soonestFlashcard: FetchedResults - @State private var timeRemaining = 10 let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() @State var flashcards: [Flashcard] = [] - @State var sortedFlashcards: [Flashcard] = [] - @State var soonestFlashcard: [Flashcard] = [] + @State var soonestFlashcards: [Flashcard] = [] @State var showDescription = false var body: some View { @@ -47,13 +29,13 @@ struct AnkiView: View { // Text("How did you do?") // .font(.subheadline) // .foregroundStyle(.gray) - ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, showDescription: $showDescription) + ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, reload: refreshFlashcards, showDescription: $showDescription) .padding([.bottom, .trailing, .leading]) } } } } else { - if !soonestFlashcard.isEmpty { + if !soonestFlashcards.isEmpty { Group { Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())") .foregroundStyle(.black) @@ -63,15 +45,6 @@ struct AnkiView: View { .clipShape(.buttonBorder) .padding(.vertical, 50) .padding(.horizontal) - .onAppear { - if !soonestFlashcard.isEmpty { - sortedFlashcards = soonestFlashcard.sorted(by: { - ($0.lastSeenOn!.addSpacedRepetitionMilestone(milestone:$0.getSpacedRepetitionMilestone()).timeIntervalSinceNow) < ($1.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $1.getSpacedRepetitionMilestone()).timeIntervalSinceNow) - }) - timeRemaining = Int(sortedFlashcards.first!.lastSeenOn!.addSpacedRepetitionMilestone(milestone:sortedFlashcards.first!.getSpacedRepetitionMilestone()).timeIntervalSinceNow) - } - refreshFlashcards() - } .onReceive(timer) { time in if timeRemaining > 1 { timeRemaining -= 1 @@ -103,32 +76,50 @@ struct AnkiView: View { } func refreshFlashcards() { - let request = NSFetchRequest(entityName: "Flashcard") - request.predicate = NSCompoundPredicate(type: .or, subpredicates: [ + let requestAllFlashcards = NSFetchRequest(entityName: "Flashcard") + requestAllFlashcards.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") ]) - request.sortDescriptors = [ + requestAllFlashcards.sortDescriptors = [ NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false), NSSortDescriptor(key: "lastSeenOn", ascending: true) ] do { - flashcards = try moc.fetch(request) + flashcards = try moc.fetch(requestAllFlashcards) } catch { - print("Something went wroooong") + print("Something went wrong while fetching available flashcards") } - let req = NSFetchRequest(entityName: "Flashcard") - req.predicate = NSPredicate(format: "%K != nil", "lastSeenOn") + let requestSoonestFlashcards = NSFetchRequest(entityName: "Flashcard") + requestSoonestFlashcards.predicate = NSPredicate(format: "%K != nil", "lastSeenOn") do { - soonestFlashcard = try moc.fetch(request) + soonestFlashcards = try moc.fetch(requestSoonestFlashcards) +// print("This is soonest flashcards") +// for flashcard in soonestFlashcards { +// print("\(flashcard.name ?? "") is \(Int(flashcard.lastSeenOn!.addSpacedRepetitionMilestone(milestone:flashcard.getSpacedRepetitionMilestone()).timeIntervalSinceNow.rounded()))") +// } } catch { - print("Something went bum") + print("Something went wrong while fetching latest flashcard") + } + if !soonestFlashcards.isEmpty { + soonestFlashcards = soonestFlashcards.sorted { + if $0.lastSeenOn != nil && $1.lastSeenOn != nil { + return $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone:$0.getSpacedRepetitionMilestone()).timeIntervalSinceNow < $1.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $1.getSpacedRepetitionMilestone()).timeIntervalSinceNow + } else { + return $0.lastSeenOn != nil + } + } + if soonestFlashcards.first!.lastSeenOn != nil { + timeRemaining = Int(soonestFlashcards.first!.lastSeenOn!.addSpacedRepetitionMilestone(milestone:soonestFlashcards.first!.getSpacedRepetitionMilestone()).timeIntervalSinceNow.rounded()) + } else { + print("Something went wrong while getting latest flashcard") + } } } } diff --git a/WordAX/Views/ButtonHStackView.swift b/WordAX/Views/ButtonHStackView.swift index 68c14bd..0051e09 100644 --- a/WordAX/Views/ButtonHStackView.swift +++ b/WordAX/Views/ButtonHStackView.swift @@ -10,6 +10,7 @@ import SwiftUI struct ButtonHStackView: View { let flashcard: Flashcard let geometry: GeometryProxy + let reload: () -> Void @Binding var showDescription: Bool var body: some View { HStack(alignment: .center) { @@ -21,6 +22,7 @@ struct ButtonHStackView: View { color: .red, geometry: geometry, timeText: DataController.SpacedRepetitionMilestoneEnum.OneMinute.rawValue.convertDurationSecondsToString(), + reload: reload, showDescription: $showDescription ) NextRepetitionButtonView( @@ -30,6 +32,7 @@ struct ButtonHStackView: View { color: .orange, geometry: geometry, timeText: flashcard.getSpacedRepetitionMilestone().rawValue.convertDurationSecondsToString(), + reload: reload, showDescription: $showDescription ) NextRepetitionButtonView( @@ -39,6 +42,7 @@ struct ButtonHStackView: View { color: .green, geometry: geometry, timeText: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard.getSpacedRepetitionMilestone()).rawValue.convertDurationSecondsToString(), + reload: reload, showDescription: $showDescription ) } diff --git a/WordAX/Views/NextRepetitionButtonView.swift b/WordAX/Views/NextRepetitionButtonView.swift index a1032fb..2999adb 100644 --- a/WordAX/Views/NextRepetitionButtonView.swift +++ b/WordAX/Views/NextRepetitionButtonView.swift @@ -15,6 +15,7 @@ struct NextRepetitionButtonView: View { let color: Color let geometry: GeometryProxy let timeText: String + let reload: () -> Void @Environment(\.managedObjectContext) var moc // { colorScheme == .light ? .cyan : .darkCyan } @Binding var showDescription: Bool @@ -34,6 +35,7 @@ struct NextRepetitionButtonView: View { print("Something went wrong while saving the flashcard info: \(error.localizedDescription)") } self.showDescription = false + reload() }) { VStack { Text(buttonText)