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)