Rewrote the app to use Core Data, some features not working fully
This commit is contained in:
		
							
								
								
									
										50
									
								
								WordAX/Model/DataController.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								WordAX/Model/DataController.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| // | ||||
| //  DataController.swift | ||||
| //  WordAX | ||||
| // | ||||
| //  Created by Oliver Hnát on 08.04.2024. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import CoreData | ||||
|  | ||||
| class DataController: ObservableObject { | ||||
|     let container = NSPersistentContainer(name: "WordAXCD") | ||||
|     static let shared = DataController() | ||||
|      | ||||
|     var viewContext: NSManagedObjectContext { | ||||
|         container.viewContext | ||||
|     } | ||||
|      | ||||
|      | ||||
|     init() { | ||||
|         container.loadPersistentStores { description, error in | ||||
|             if let error = error { | ||||
|                 print("Core data failed to load: \(error.localizedDescription)") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public func addFlashcard(name: String, description: String) { | ||||
|         let flashcard = Flashcard(context: viewContext) | ||||
|         flashcard.id = UUID() | ||||
|         flashcard.name = name | ||||
|         flashcard.desc = description | ||||
|         flashcard.shown = false | ||||
|         flashcard.nextSpacedRepetitionMilestone = 0 | ||||
|         flashcard.lastSeenOn = nil | ||||
|         flashcard.shownCount = 0 | ||||
|         flashcard.dateAdded = Date() | ||||
|         try? viewContext.save() | ||||
|     } | ||||
|      | ||||
|     public func getAllFlashcards() -> [Flashcard]{ | ||||
|         let request = NSFetchRequest<Flashcard>(entityName: "Flashcard") | ||||
|          | ||||
|         do { | ||||
|             return try viewContext.fetch(request) | ||||
|         } catch { | ||||
|             return [] | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								WordAX/Model/Flashcard+CoreDataClass.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								WordAX/Model/Flashcard+CoreDataClass.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| // | ||||
| //  Flashcard+CoreDataClass.swift | ||||
| //  WordAX | ||||
| // | ||||
| //  Created by Oliver Hnát on 08.04.2024. | ||||
| // | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import CoreData | ||||
|  | ||||
| @objc(Flashcard) | ||||
| public class Flashcard: NSManagedObject { | ||||
|     typealias SpacedRepetitionMilestoneEnum = WordAX.SpacedRepetitionMilestoneEnum | ||||
|      | ||||
|     func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum { | ||||
|         return SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										32
									
								
								WordAX/Model/Flashcard+CoreDataProperties.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								WordAX/Model/Flashcard+CoreDataProperties.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // | ||||
| //  Flashcard+CoreDataProperties.swift | ||||
| //  WordAX | ||||
| // | ||||
| //  Created by Oliver Hnát on 08.04.2024. | ||||
| // | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import CoreData | ||||
|  | ||||
|  | ||||
| extension Flashcard { | ||||
|  | ||||
|     @nonobjc public class func fetchRequest() -> NSFetchRequest<Flashcard> { | ||||
|         return NSFetchRequest<Flashcard>(entityName: "Flashcard") | ||||
|     } | ||||
|  | ||||
|     @NSManaged public var name: String? | ||||
|     @NSManaged public var desc: String? | ||||
|     @NSManaged public var id: UUID? | ||||
|     @NSManaged public var shown: Bool | ||||
|     @NSManaged public var nextSpacedRepetitionMilestone: Int64 | ||||
|     @NSManaged public var lastSeenOn: Date? | ||||
|     @NSManaged public var dateAdded: Date? | ||||
|     @NSManaged public var shownCount: Int64 | ||||
|  | ||||
| } | ||||
|  | ||||
| extension Flashcard : Identifiable { | ||||
|  | ||||
| } | ||||
							
								
								
									
										8
									
								
								WordAX/Model/WordAXCD.xcdatamodeld/.xccurrentversion
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								WordAX/Model/WordAXCD.xcdatamodeld/.xccurrentversion
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
| <dict> | ||||
| 	<key>_XCCurrentVersionName</key> | ||||
| 	<string>WordAX.xcdatamodel</string> | ||||
| </dict> | ||||
| </plist> | ||||
| @@ -0,0 +1,13 @@ | ||||
| <?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="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> | ||||
| @@ -10,7 +10,7 @@ import SwiftUI | ||||
| struct AnkiView: View { | ||||
|     @EnvironmentObject var model: WordAXModelView | ||||
|     @State var showDescription = false | ||||
|     var flashcard: WordAX.FlashCard? { | ||||
|     var flashcard: Flashcard? { | ||||
|         model.getFlashCardsToDisplay() | ||||
|     } | ||||
|     var body: some View { | ||||
| @@ -25,8 +25,8 @@ struct AnkiView: View { | ||||
|                         HStack(alignment: .center) { | ||||
|                             NextRepetitionButtonView( | ||||
|                                 buttonText: "Wrong", | ||||
|                                 nextMilestone: flashcard!.nextSpacedRepetitionMilestone, | ||||
|                                 flashcardId: flashcard!.id, | ||||
|                                 nextMilestone: flashcard!.getSpacedRepetitionMilestone(), | ||||
|                                 flashcardId: flashcard!.id!, | ||||
|                                 width: geometry.size.width, | ||||
|                                 color: .red, | ||||
|                                 geometry: geometry, | ||||
| @@ -35,8 +35,8 @@ struct AnkiView: View { | ||||
|                             ) | ||||
|                             NextRepetitionButtonView( | ||||
|                                 buttonText: "Correct", | ||||
|                                 nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.nextSpacedRepetitionMilestone), | ||||
|                                 flashcardId: flashcard!.id, | ||||
|                                 nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone()), | ||||
|                                 flashcardId: flashcard!.id!, | ||||
|                                 width:geometry.size.width, | ||||
|                                 color: .orange, | ||||
|                                 geometry: geometry, | ||||
| @@ -45,8 +45,8 @@ struct AnkiView: View { | ||||
|                             ) | ||||
|                             NextRepetitionButtonView( | ||||
|                                 buttonText: "Easy", | ||||
|                                 nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.nextSpacedRepetitionMilestone)), | ||||
|                                 flashcardId: flashcard!.id, | ||||
|                                 nextMilestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: WordAX.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard!.getSpacedRepetitionMilestone())), | ||||
|                                 flashcardId: flashcard!.id!, | ||||
|                                 width: geometry.size.width, | ||||
|                                 color: .green, | ||||
|                                 geometry: geometry, | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import SwiftUI | ||||
|  | ||||
| struct FlashCardListRowView: View { | ||||
|     @EnvironmentObject var model: WordAXModelView | ||||
|     var flashcard: WordAX.FlashCard | ||||
|     var flashcard: Flashcard | ||||
|     @State var favorite = true | ||||
|     var body: some View { | ||||
|         HStack { | ||||
| @@ -30,12 +30,12 @@ struct FlashCardListRowView: View { | ||||
|             } | ||||
|             .padding(.trailing) | ||||
|             VStack { | ||||
|                 Text(flashcard.name) | ||||
|                 Text(flashcard.name ?? "Unknown") | ||||
|                     .bold() | ||||
|                     .font(.system(size: 19)) | ||||
|                     .multilineTextAlignment(.leading) | ||||
|                     .frame(maxWidth: .infinity, alignment: .leading) | ||||
|                 Text(flashcard.description) | ||||
|                 Text(flashcard.desc ?? "Unknown") | ||||
|                     .multilineTextAlignment(.leading) | ||||
|                     .frame(maxWidth: .infinity, alignment: .leading) | ||||
|                     .lineLimit(1) | ||||
| @@ -46,12 +46,16 @@ struct FlashCardListRowView: View { | ||||
| } | ||||
|  | ||||
| #Preview { | ||||
|     Group { | ||||
|         FlashCardListRowView(flashcard: WordAX.FlashCard(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) | ||||
|     let fc = Flashcard() | ||||
|     fc.id = UUID() | ||||
|     fc.name = "Mesmerizing" | ||||
|     fc.desc = "Some very long description like Lorem Ipsum which I'm to lazy to copy" | ||||
|     return Group { | ||||
|         FlashCardListRowView(flashcard: fc) | ||||
|             .environmentObject(WordAXModelView()) | ||||
|         FlashCardListRowView(flashcard: WordAX.FlashCard(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) | ||||
|         FlashCardListRowView(flashcard: fc) | ||||
|             .environmentObject(WordAXModelView()) | ||||
|         FlashCardListRowView(flashcard: WordAX.FlashCard(id: 0, name: "Mesmerizing", description: "Some very long description like Lorem Ipsum which I'm to lazy to copy", shown: false, nextSpacedRepetitionMilestone: WordAX.SpacedRepetitionMilestoneEnum.OneDay, lastSeenOn: Date(), shownCount: 1)) | ||||
|         FlashCardListRowView(flashcard: fc) | ||||
|             .environmentObject(WordAXModelView()) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,12 +15,12 @@ struct FlashCardListView: View { | ||||
|         GeometryReader { geometry in | ||||
|             NavigationSplitView { | ||||
|                 Group { | ||||
|                     if !model.flashcards.isEmpty { | ||||
|                         List(model.flashcards) { word in | ||||
|                     if !DataController.shared.getAllFlashcards().isEmpty { | ||||
|                         List(DataController.shared.getAllFlashcards()) { flashcard in | ||||
|                             NavigationLink { | ||||
|                                 FlashCardView(flashcard: word, showDescription: $showDescription) | ||||
|                                 FlashCardView(flashcard: flashcard, showDescription: $showDescription) | ||||
|                             } label: { | ||||
|                                 FlashCardListRowView(flashcard: word) | ||||
|                                 FlashCardListRowView(flashcard: flashcard) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| @@ -32,7 +32,7 @@ struct FlashCardListView: View { | ||||
|                             .frame(maxWidth: geometry.size.width - 30) | ||||
|                     } | ||||
|                 } | ||||
|                 .navigationTitle("Word List") | ||||
|                 .navigationTitle("All Flashcards") | ||||
|                 .toolbar { | ||||
|                     Button(action: { | ||||
|                         self.addFlashcard = true | ||||
|   | ||||
| @@ -9,14 +9,14 @@ import SwiftUI | ||||
| import UIKit | ||||
|  | ||||
| struct FlashCardView: View { | ||||
|     var flashcard: WordAX.FlashCard | ||||
|     var flashcard: Flashcard | ||||
|     @Binding var showDescription: Bool | ||||
|     @EnvironmentObject var model: WordAXModelView | ||||
|     @Environment(\.colorScheme) var colorScheme | ||||
|      | ||||
|      | ||||
|     var body: some View { | ||||
|         let flashcardText = Text(flashcard.name) | ||||
|         let flashcardText = Text(flashcard.name ?? "Unknown") | ||||
|             .font(.title) | ||||
|             .bold() | ||||
|         VStack { | ||||
| @@ -30,7 +30,7 @@ struct FlashCardView: View { | ||||
|                 Divider() | ||||
|                     .background(colorScheme == .light ? Color.black : Color.white) | ||||
|                     .padding(.horizontal) | ||||
|                 Text(flashcard.description) | ||||
|                 Text(flashcard.desc ?? "No description added") | ||||
|                     .multilineTextAlignment(.center) | ||||
|             } else { | ||||
|                 flashcardText | ||||
| @@ -47,6 +47,6 @@ struct FlashCardView: View { | ||||
|  | ||||
| #Preview { | ||||
|     @State var showDescription = false | ||||
|     return FlashCardView(flashcard: WordAXModelView().getFlashCardsToDisplay()!, showDescription: $showDescription) | ||||
|     return FlashCardView(flashcard: DataController.shared.getAllFlashcards()[0], showDescription: $showDescription) | ||||
|         .environmentObject(WordAXModelView()) | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import SwiftUI | ||||
| struct NextRepetitionButtonView: View { | ||||
|     let buttonText: String | ||||
|     let nextMilestone: WordAX.SpacedRepetitionMilestoneEnum? | ||||
|     let flashcardId: Int | ||||
|     let flashcardId: UUID | ||||
|     let width: CGFloat | ||||
|     let color: Color | ||||
|     let geometry: GeometryProxy | ||||
| @@ -6,6 +6,7 @@ | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import SwiftUI | ||||
|  | ||||
| struct WordAX { | ||||
|     struct FlashCard: Identifiable, Hashable { | ||||
| @@ -25,7 +26,14 @@ struct WordAX { | ||||
|         case Monthly = 30 | ||||
|     } | ||||
|      | ||||
|     enum SpacedRepetitionMilestoneEnum: Int, CaseIterable { | ||||
|      | ||||
|     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 | ||||
| @@ -52,6 +60,11 @@ struct WordAX { | ||||
|             } | ||||
|             return nil | ||||
|         } | ||||
|  | ||||
|         static func getMilestoneFromInt(value: Int64) -> SpacedRepetitionMilestoneEnum { | ||||
|             return SpacedRepetitionMilestoneEnum.allCasesSorted.first(where: {$0.rawValue == value}) ?? SpacedRepetitionMilestoneEnum.Now | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
|     struct Settings { | ||||
| @@ -94,10 +107,6 @@ struct WordAX { | ||||
|     var flashcards: [FlashCard] = [] | ||||
|     var settings: Settings | ||||
|      | ||||
|     public mutating func add(flashcard: FlashCard) { | ||||
|         self.flashcards.append(flashcard) | ||||
|     } | ||||
|      | ||||
|     init() { | ||||
|         self.flashcards = [] | ||||
|         let dateFormatter = DateFormatter() | ||||
|   | ||||
| @@ -9,11 +9,13 @@ import SwiftUI | ||||
|  | ||||
| @main | ||||
| struct WordAXApp: App { | ||||
|     @StateObject var model = WordAXModelView() | ||||
|     @StateObject private var model = WordAXModelView() | ||||
|     @StateObject private var dataControler = DataController() | ||||
|     var body: some Scene { | ||||
|         WindowGroup { | ||||
|             MainView() | ||||
|                 .environmentObject(model) | ||||
|                 .environment(\.managedObjectContext, dataControler.container.viewContext) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,20 +10,21 @@ import Foundation | ||||
| class WordAXModelView: ObservableObject { | ||||
|     @Published private var model: WordAX | ||||
|     typealias FlashCard = WordAX.FlashCard | ||||
|     typealias SpacedRepetitionMilestoneEnum = WordAX.SpacedRepetitionMilestoneEnum | ||||
|     init() { | ||||
|         model = WordAX() | ||||
|     } | ||||
|      | ||||
|     public var flashcards: [FlashCard] { | ||||
|         model.flashcards | ||||
|     public var flashcards: [Flashcard] { | ||||
|         DataController.shared.getAllFlashcards() | ||||
|     } | ||||
|      | ||||
|     public func getDateFormatter() -> DateFormatter { | ||||
|         model.settings.dateFormatter | ||||
|     } | ||||
|      | ||||
|     public func getFlashCardsToDisplay() -> FlashCard? { | ||||
|         let flashcards = model.flashcards | ||||
|     public func getFlashCardsToDisplay() -> Flashcard? { | ||||
|         let flashcards = self.flashcards | ||||
|          | ||||
|         if flashcards.count > 0 { | ||||
|             let notShownFlashCards = flashcards.filter({!$0.shown}) | ||||
| @@ -32,7 +33,7 @@ class WordAXModelView: ObservableObject { | ||||
|             } | ||||
|             // if today is the date they're supposed to be shown | ||||
|              | ||||
|             let displayToday = flashcards.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: $0.nextSpacedRepetitionMilestone).isBeforeTodayOrToday()}) | ||||
|             let displayToday = flashcards.filter({ $0.lastSeenOn != nil && $0.lastSeenOn!.addSpacedRepetitionMilestone(milestone: SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: $0.nextSpacedRepetitionMilestone)).isBeforeTodayOrToday()}) | ||||
|             if  displayToday.count > 0 { | ||||
|                 return displayToday.first! | ||||
|             } | ||||
| @@ -53,13 +54,15 @@ class WordAXModelView: ObservableObject { | ||||
|         return nil | ||||
|     } | ||||
|      | ||||
|     public func ankiButtonClicked(flashcardId: Int, milestone: WordAX.SpacedRepetitionMilestoneEnum?) { | ||||
|         model.setSpacedRepetitionMilestone(flashcardId: flashcardId, milestone: milestone) | ||||
|         model.flashcardShown(flashcardId: flashcardId) | ||||
|     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)) | ||||
| //        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) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user