Countdown not working yet
This commit is contained in:
		| @@ -29,8 +29,8 @@ class DataController: ObservableObject { | ||||
|                 "This is a very short description", | ||||
|                 "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.nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.OneYear.rawValue | ||||
|             flashcard.lastSeenOn  = [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()! | ||||
|         } | ||||
| @@ -70,43 +70,6 @@ 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 | ||||
|     //    } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -133,3 +96,32 @@ extension Int64 { | ||||
|         return result | ||||
|     } | ||||
| } | ||||
|  | ||||
| extension Int { | ||||
|     func convertDurationSecondsToCountdown() -> String { | ||||
|         var result = "" | ||||
|         // Separate into days, hours, minutes and seconds and take the largest one | ||||
|         let days: Int = self / 86400 | ||||
|         let hours: Int = self / 60 / 60 % 60 | ||||
|         let minutes: Int = self / 60 % 60 | ||||
|         let seconds: Int = self % 60 | ||||
|         if days > 0 { | ||||
|             result += "\(days)d" | ||||
|         } | ||||
|         if hours > 0 { | ||||
|             result += " \(hours)h" | ||||
|         } | ||||
|         if minutes > 0 { | ||||
|             result += " \(minutes)min" | ||||
|         } | ||||
|         if seconds > 0 { | ||||
|             result += " \(seconds)s" | ||||
|         } | ||||
| //        else { | ||||
| //            result = "\(self)" | ||||
| //        } | ||||
|          | ||||
|         return result | ||||
|          | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -39,14 +39,28 @@ public class Flashcard: NSManagedObject { | ||||
|             } | ||||
|             return SpacedRepetitionMilestoneEnum.OneYear | ||||
|         } | ||||
|  | ||||
|          | ||||
|         static func getMilestoneFromInt(value: Int64) -> SpacedRepetitionMilestoneEnum { | ||||
|             return SpacedRepetitionMilestoneEnum.allCasesSorted.first(where: {$0.rawValue == value}) ?? SpacedRepetitionMilestoneEnum.Now | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
|  | ||||
|     public override func didChangeValue(forKey key: String) { | ||||
|         super.didChangeValue(forKey: key) | ||||
|         if key == "lastSeenOn" || key == "nextSpacedRepetitionMilestone" { | ||||
|             //            updateCalculatedNextRepetition() | ||||
|             calculatedNextRepetition = lastSeenOn ?? Date() + TimeInterval(nextSpacedRepetitionMilestone) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     //    func updateCalculatedNextRepetition() { | ||||
|     //        if let lastSeen = lastSeenOn { | ||||
|     //            calculatedNextRepetition = Calendar.current.date(byAdding: .day, value: Int(nextSpacedRepetitionMilestone), to: lastSeen) | ||||
|     //        } | ||||
|     //    } | ||||
|      | ||||
|      | ||||
|     func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum { | ||||
|         return SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) | ||||
|     } | ||||
|   | ||||
							
								
								
									
										33
									
								
								WordAX/Model/Flashcard+CoreDataProperties.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								WordAX/Model/Flashcard+CoreDataProperties.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // | ||||
| //  Flashcard+CoreDataProperties.swift | ||||
| //  WordAX | ||||
| // | ||||
| //  Created by Oliver Hnát on 11.04.2024. | ||||
| // | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import CoreData | ||||
|  | ||||
|  | ||||
| extension Flashcard { | ||||
|  | ||||
|     @nonobjc public class func fetchRequest() -> NSFetchRequest<Flashcard> { | ||||
|         return NSFetchRequest<Flashcard>(entityName: "Flashcard") | ||||
|     } | ||||
|  | ||||
|     @NSManaged public var dateAdded: Date? | ||||
|     @NSManaged public var desc: String? | ||||
|     @NSManaged public var id: UUID? | ||||
|     @NSManaged public var lastSeenOn: Date? | ||||
|     @NSManaged public var name: String? | ||||
|     @NSManaged public var nextSpacedRepetitionMilestone: Int64 | ||||
|     @NSManaged public var shown: Bool | ||||
|     @NSManaged public var shownCount: Int64 | ||||
|     @NSManaged public var calculatedNextRepetition: Date? | ||||
|  | ||||
| } | ||||
|  | ||||
| extension Flashcard : Identifiable { | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||||
| <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23D60" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier=""> | ||||
|     <entity name="Flashcard" representedClassName="Flashcard" syncable="YES"> | ||||
|         <attribute name="calculatedNextRepetition" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||||
|         <attribute name="dateAdded" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||||
|         <attribute name="desc" optional="YES" attributeType="String"/> | ||||
|         <attribute name="id" optional="YES" attributeType="UUID" usesScalarValueType="NO"/> | ||||
|         <attribute name="lastSeenOn" optional="YES" attributeType="Date" usesScalarValueType="NO"/> | ||||
|         <attribute name="name" optional="YES" attributeType="String"/> | ||||
|         <attribute name="nextSpacedRepetitionMilestone" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/> | ||||
|         <attribute name="shown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/> | ||||
|         <attribute name="shownCount" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/> | ||||
|     </entity> | ||||
| </model> | ||||
| @@ -21,6 +21,19 @@ struct AnkiView: View { | ||||
|         ]), | ||||
|         NSPredicate(format: "lastSeenOn == nil") | ||||
|     ])) var flashcards: FetchedResults<Flashcard> | ||||
|     @FetchRequest( | ||||
|         sortDescriptors: [ | ||||
|             NSSortDescriptor(key: "calculatedNextRepetition", ascending: false) | ||||
|         ], | ||||
|           predicate: | ||||
|             NSCompoundPredicate(type: .and, subpredicates: [ | ||||
|                 NSPredicate(format: "%K != nil", "lastSeenOn"), | ||||
|             NSPredicate( | ||||
|                 format: "lastSeenOn + nextSpacedRepetitionMilestone > %@", Date() as CVarArg) | ||||
|                 ] | ||||
|     )) var soonestFlashcard: FetchedResults<Flashcard> | ||||
|  | ||||
|     // get the most recent flashcard | ||||
|      | ||||
|     @State var showDescription = false | ||||
|      | ||||
| @@ -73,12 +86,62 @@ struct AnkiView: View { | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             Text("There are currently no words to display") | ||||
|                 .padding() | ||||
|                 .background(.yellow) | ||||
|                 .clipShape(.buttonBorder) | ||||
|             // TODO: Add countdown to the next available word | ||||
|             VStack{ | ||||
|                 if !soonestFlashcard.isEmpty { | ||||
|                     Text("Time: \(timeRemaining.convertDurationSecondsToCountdown())") | ||||
|                         .foregroundStyle(.white) | ||||
|                         .padding(.horizontal, 20) | ||||
|                         .padding(.vertical, 5) | ||||
|                         .background(.black.opacity(0.75)) | ||||
|                         .clipShape(.capsule) | ||||
|                 } | ||||
|                  | ||||
| //                if !soonestFlashcard.isEmpty { | ||||
| //                    Text("HERE") | ||||
| //                    Text("\(soonestFlashcard.first!.lastSeenOn!.addingTimeInterval(TimeInterval(soonestFlashcard.first!.nextSpacedRepetitionMilestone)).timeIntervalSince(Date()))") | ||||
| //                    Text("\(Int64(timeRemaining))") | ||||
| //                    Text("\(soonestFlashcard.first!.lastSeenOn!)") | ||||
| //                    Text("\(soonestFlashcard.first!.getSpacedRepetitionMilestone().rawValue)") | ||||
| //                    Text("\(soonestFlashcard.first!.lastSeenOn!.addSpacedRepetitionMilestone(milestone: soonestFlashcard.first!.getSpacedRepetitionMilestone()))") | ||||
| //                } | ||||
| //                if soonestFlashcard.first! { | ||||
| //                    Text("HERE") | ||||
| //                } | ||||
|                  | ||||
|                 Text("There are currently no words to display") | ||||
|                     .padding() | ||||
|                     .background(.yellow) | ||||
|                     .clipShape(.buttonBorder) | ||||
|             } | ||||
|             .onAppear { | ||||
|                 if !soonestFlashcard.isEmpty { | ||||
|                     var lastSeen = soonestFlashcard.first!.lastSeenOn! | ||||
|                     var showIn = soonestFlashcard.first!.getSpacedRepetitionMilestone() | ||||
|                     var show = lastSeen.addSpacedRepetitionMilestone(milestone: showIn) | ||||
|                     timeRemaining = Int(show.timeIntervalSinceNow) | ||||
|                 } | ||||
|             } | ||||
|             .onReceive(timer) { time in | ||||
|                 if !soonestFlashcard.isEmpty { | ||||
|                     var lastSeen = soonestFlashcard.first!.lastSeenOn! | ||||
|                     var showIn = soonestFlashcard.first!.getSpacedRepetitionMilestone() | ||||
|                     var show = lastSeen.addSpacedRepetitionMilestone(milestone: showIn) | ||||
|                     timeRemaining = Int(show.timeIntervalSinceNow) | ||||
|                 } | ||||
| //                timeRemaining = Int(soonestFlashcard.first!.lastSeenOn!.addSpacedRepetitionMilestone(milestone: soonestFlashcard.first!.getSpacedRepetitionMilestone()).timeIntervalSince(Date())) | ||||
| //                timeRemaining = Int(soonestFlashcard.first!.lastSeenOn!.addingTimeInterval(TimeInterval(soonestFlashcard.first!.nextSpacedRepetitionMilestone)).timeIntervalSince(Date())) | ||||
| //                if timeRemaining > 0 { | ||||
| //                    timeRemaining -= 1 | ||||
| //                } | ||||
| //                if !soonestFlashcard.isEmpty { | ||||
| //                    timeRemaining = Int(Date().timeIntervalSince(soonestFlashcard.first!.lastSeenOn!)) | ||||
| //                } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     @State private var timeRemaining = 10 | ||||
|     let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() | ||||
| } | ||||
|  | ||||
| #Preview { | ||||
|   | ||||
| @@ -68,7 +68,7 @@ extension Date { | ||||
|         if milestone == nil { | ||||
|             return self | ||||
|         } | ||||
|         return self.addingTimeInterval(TimeInterval(milestone!.rawValue * 24 * 60 * 60)) | ||||
|         return self.addingTimeInterval(TimeInterval(milestone!.rawValue)) | ||||
|     } | ||||
|      | ||||
|     func isAfterToday() -> Bool { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user