When countdown finishes, fetch requests reload

This commit is contained in:
2024-04-29 16:41:47 +02:00
parent 2c87cc340e
commit 38b01b4a7e
6 changed files with 44 additions and 44 deletions

View File

@@ -56,6 +56,7 @@ Why settle for pricey apps when you can have WordAX? We're here to prove that ef
## Roadmap ## Roadmap
- [ ] Anki card "store" - download any anki flashcards you want from the online store that already exists somewhere - [ ] 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 - [ ] Import anki cards in the .anki format
- [x] Create flashcards - [x] Create flashcards
- [ ] Add tags to cards - [ ] 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 - [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? - [ ] Maybe later add a storage in cloud, so that you can sync with other devices if the app is multi-platform?
- [ ] Add some animations? - [ ] Add some animations?
- [ ] Implement logic - [x] Implement logic
- [ ] Export your anki to the store?
- [ ] Make an apple watch version of the app - [ ] Make an apple watch version of the app
<p align="right">(<a href="#readme-top">back to top</a>)</p> <p align="right">(<a href="#readme-top">back to top</a>)</p>

View File

@@ -120,6 +120,9 @@ extension Int {
// else { // else {
// result = "\(self)" // result = "\(self)"
// } // }
if days == 0 && hours == 0 && minutes == 0 {
return "\(seconds)s"
}
return result return result

View File

@@ -35,6 +35,7 @@ public class Flashcard: NSManagedObject {
} }
let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})! let milestoneIndex = sorted.firstIndex(where: {$0.rawValue == milestone!.rawValue})!
if milestoneIndex < sorted.count { 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 sorted[milestoneIndex + 1] == .OneMinute ? .TenMinutes : sorted[milestoneIndex + 1]
} }
return .OneYear return .OneYear
@@ -47,7 +48,6 @@ public class Flashcard: NSManagedObject {
} }
func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum { func getSpacedRepetitionMilestone() -> SpacedRepetitionMilestoneEnum {
let milestone = SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone) SpacedRepetitionMilestoneEnum.getMilestoneFromInt(value: self.nextSpacedRepetitionMilestone)
return milestone == .OneMinute ? .TenMinutes : milestone
} }
} }

View File

@@ -9,30 +9,12 @@ import SwiftUI
import CoreData import CoreData
struct AnkiView: View { struct AnkiView: View {
// @EnvironmentObject var model: WordAXModelView
@Environment(\.managedObjectContext) var moc @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<Flashcard>
// get the most recent flashcard
// @FetchRequest(sortDescriptors: [],
// predicate: NSPredicate(format: "%K != nil", "lastSeenOn")) var soonestFlashcard: FetchedResults<Flashcard>
@State private var timeRemaining = 10 @State private var timeRemaining = 10
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State var flashcards: [Flashcard] = [] @State var flashcards: [Flashcard] = []
@State var sortedFlashcards: [Flashcard] = [] @State var soonestFlashcards: [Flashcard] = []
@State var soonestFlashcard: [Flashcard] = []
@State var showDescription = false @State var showDescription = false
var body: some View { var body: some View {
@@ -47,13 +29,13 @@ struct AnkiView: View {
// Text("How did you do?") // Text("How did you do?")
// .font(.subheadline) // .font(.subheadline)
// .foregroundStyle(.gray) // .foregroundStyle(.gray)
ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, showDescription: $showDescription) ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, reload: refreshFlashcards, showDescription: $showDescription)
.padding([.bottom, .trailing, .leading]) .padding([.bottom, .trailing, .leading])
} }
} }
} }
} else { } else {
if !soonestFlashcard.isEmpty { if !soonestFlashcards.isEmpty {
Group { Group {
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())") Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
.foregroundStyle(.black) .foregroundStyle(.black)
@@ -63,15 +45,6 @@ struct AnkiView: View {
.clipShape(.buttonBorder) .clipShape(.buttonBorder)
.padding(.vertical, 50) .padding(.vertical, 50)
.padding(.horizontal) .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 .onReceive(timer) { time in
if timeRemaining > 1 { if timeRemaining > 1 {
timeRemaining -= 1 timeRemaining -= 1
@@ -103,32 +76,50 @@ struct AnkiView: View {
} }
func refreshFlashcards() { func refreshFlashcards() {
let request = NSFetchRequest<Flashcard>(entityName: "Flashcard") let requestAllFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
request.predicate = NSCompoundPredicate(type: .or, subpredicates: [ requestAllFlashcards.predicate = NSCompoundPredicate(type: .or, subpredicates: [
NSCompoundPredicate(type: .and, subpredicates: [ NSCompoundPredicate(type: .and, subpredicates: [
NSPredicate(format: "%K != nil", "lastSeenOn"), NSPredicate(format: "%K != nil", "lastSeenOn"),
NSPredicate(format: "lastSeenOn + nextSpacedRepetitionMilestone < %@", Date() as CVarArg) NSPredicate(format: "lastSeenOn + nextSpacedRepetitionMilestone < %@", Date() as CVarArg)
]), ]),
NSPredicate(format: "lastSeenOn == nil") NSPredicate(format: "lastSeenOn == nil")
]) ])
request.sortDescriptors = [ requestAllFlashcards.sortDescriptors = [
NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false), NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false),
NSSortDescriptor(key: "lastSeenOn", ascending: true) NSSortDescriptor(key: "lastSeenOn", ascending: true)
] ]
do { do {
flashcards = try moc.fetch(request) flashcards = try moc.fetch(requestAllFlashcards)
} catch { } catch {
print("Something went wroooong") print("Something went wrong while fetching available flashcards")
} }
let req = NSFetchRequest<Flashcard>(entityName: "Flashcard") let requestSoonestFlashcards = NSFetchRequest<Flashcard>(entityName: "Flashcard")
req.predicate = NSPredicate(format: "%K != nil", "lastSeenOn") requestSoonestFlashcards.predicate = NSPredicate(format: "%K != nil", "lastSeenOn")
do { 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 { } 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")
}
} }
} }
} }

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct ButtonHStackView: View { struct ButtonHStackView: View {
let flashcard: Flashcard let flashcard: Flashcard
let geometry: GeometryProxy let geometry: GeometryProxy
let reload: () -> Void
@Binding var showDescription: Bool @Binding var showDescription: Bool
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
@@ -21,6 +22,7 @@ struct ButtonHStackView: View {
color: .red, color: .red,
geometry: geometry, geometry: geometry,
timeText: DataController.SpacedRepetitionMilestoneEnum.OneMinute.rawValue.convertDurationSecondsToString(), timeText: DataController.SpacedRepetitionMilestoneEnum.OneMinute.rawValue.convertDurationSecondsToString(),
reload: reload,
showDescription: $showDescription showDescription: $showDescription
) )
NextRepetitionButtonView( NextRepetitionButtonView(
@@ -30,6 +32,7 @@ struct ButtonHStackView: View {
color: .orange, color: .orange,
geometry: geometry, geometry: geometry,
timeText: flashcard.getSpacedRepetitionMilestone().rawValue.convertDurationSecondsToString(), timeText: flashcard.getSpacedRepetitionMilestone().rawValue.convertDurationSecondsToString(),
reload: reload,
showDescription: $showDescription showDescription: $showDescription
) )
NextRepetitionButtonView( NextRepetitionButtonView(
@@ -39,6 +42,7 @@ struct ButtonHStackView: View {
color: .green, color: .green,
geometry: geometry, geometry: geometry,
timeText: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard.getSpacedRepetitionMilestone()).rawValue.convertDurationSecondsToString(), timeText: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard.getSpacedRepetitionMilestone()).rawValue.convertDurationSecondsToString(),
reload: reload,
showDescription: $showDescription showDescription: $showDescription
) )
} }

View File

@@ -15,6 +15,7 @@ struct NextRepetitionButtonView: View {
let color: Color let color: Color
let geometry: GeometryProxy let geometry: GeometryProxy
let timeText: String let timeText: String
let reload: () -> Void
@Environment(\.managedObjectContext) var moc @Environment(\.managedObjectContext) var moc
// { colorScheme == .light ? .cyan : .darkCyan } // { colorScheme == .light ? .cyan : .darkCyan }
@Binding var showDescription: Bool @Binding var showDescription: Bool
@@ -34,6 +35,7 @@ struct NextRepetitionButtonView: View {
print("Something went wrong while saving the flashcard info: \(error.localizedDescription)") print("Something went wrong while saving the flashcard info: \(error.localizedDescription)")
} }
self.showDescription = false self.showDescription = false
reload()
}) { }) {
VStack { VStack {
Text(buttonText) Text(buttonText)