Resize countdown, refactor ButtonView

Countdown was resizing with bigger/smaller countdown left, so added a finite background
Turn NextRepetitionButtonView from AnkiView into ButtonHStackView
This commit is contained in:
2024-04-12 16:22:30 +02:00
parent dae08d79f6
commit 91c92f4a52
4 changed files with 86 additions and 67 deletions

View File

@@ -29,11 +29,10 @@ 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.OneYear.rawValue
flashcard.lastSeenOn = [Date().addingTimeInterval([86400, 24000, 100000].randomElement()!)].randomElement()!
flashcard.nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCases.randomElement()!.rawValue
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()!
// flashcard.calculatedNextRepetition = flashcard.lastSeenOn ?? Date() + TimeInterval(flashcard.nextSpacedRepetitionMilestone)
}
do {
try viewContext.save()

View File

@@ -11,6 +11,8 @@ 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)
@@ -22,19 +24,16 @@ struct AnkiView: View {
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
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State var sortedFlashcards: [Flashcard] = []
@State var showDescription = false
@Environment(\.colorScheme) var colorScheme
// get the most recent flashcard
@FetchRequest(sortDescriptors: [],
predicate: NSPredicate(format: "%K != nil", "lastSeenOn")) var soonestFlashcard: FetchedResults<Flashcard>
@State var showDescription = false
var body: some View {
if !flashcards.isEmpty && flashcards.first != nil {
@@ -47,67 +46,39 @@ struct AnkiView: View {
// Text("How did you do?")
// .font(.subheadline)
// .foregroundStyle(.gray)
HStack(alignment: .center) {
// TODO: Maybe create an algorithm to take into account the shownCount and not just always restart from 1 min?
NextRepetitionButtonView(
buttonText: "Wrong",
nextMilestone: DataController.SpacedRepetitionMilestoneEnum.OneMinute,
flashcardId: flashcards.first!.id!,
width: geometry.size.width,
color: .red,
geometry: geometry,
timeText: DataController.SpacedRepetitionMilestoneEnum.OneMinute.rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
NextRepetitionButtonView(
buttonText: "Correct",
nextMilestone: flashcards.first!.getSpacedRepetitionMilestone(),
flashcardId: flashcards.first!.id!,
width:geometry.size.width,
color: .orange,
geometry: geometry,
timeText: flashcards.first!.getSpacedRepetitionMilestone().rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
NextRepetitionButtonView(
buttonText: "Easy",
nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone()),
flashcardId: flashcards.first!.id!,
width: geometry.size.width,
color: .green,
geometry: geometry,
timeText: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcards.first!.getSpacedRepetitionMilestone()).rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
}
.padding([.bottom, .trailing, .leading])
ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, showDescription: $showDescription)
.padding([.bottom, .trailing, .leading])
}
}
}
} else {
if !soonestFlashcard.isEmpty {
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
.foregroundStyle(.black)
.padding()
.background(.yellow)
.clipShape(.buttonBorder)
.padding(.vertical, 50)
.padding(.horizontal)
.background(.gray.opacity(0.3))
.clipShape(.buttonBorder)
.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)
Group {
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
.foregroundStyle(.black)
.padding()
.frame(maxWidth: .infinity - 50)
.background(.yellow)
.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)
}
}
}
.onReceive(timer) { time in
if timeRemaining > 0 {
timeRemaining -= 1
.onReceive(timer) { time in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
}
.background(.gray.opacity(0.3))
.clipShape(.buttonBorder)
.padding(.horizontal)
}
}
}
}

View File

@@ -0,0 +1,50 @@
//
// ButtonHStackView.swift
// WordAX
//
// Created by Oliver Hnát on 12.04.2024.
//
import SwiftUI
struct ButtonHStackView: View {
let flashcard: Flashcard
let geometry: GeometryProxy
@Binding var showDescription: Bool
var body: some View {
HStack(alignment: .center) {
// TODO: Maybe create an algorithm to take into account the shownCount and not just always restart from 1 min?
NextRepetitionButtonView(
buttonText: "Wrong",
nextMilestone: DataController.SpacedRepetitionMilestoneEnum.OneMinute,
flashcardId: flashcard.id!,
color: .red,
geometry: geometry,
timeText: DataController.SpacedRepetitionMilestoneEnum.OneMinute.rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
NextRepetitionButtonView(
buttonText: "Correct",
nextMilestone: flashcard.getSpacedRepetitionMilestone(),
flashcardId: flashcard.id!,
color: .orange,
geometry: geometry,
timeText: flashcard.getSpacedRepetitionMilestone().rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
NextRepetitionButtonView(
buttonText: "Easy",
nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard.getSpacedRepetitionMilestone()),
flashcardId: flashcard.id!,
color: .green,
geometry: geometry,
timeText: Flashcard.SpacedRepetitionMilestoneEnum.getNext(milestone: flashcard.getSpacedRepetitionMilestone()).rawValue.convertDurationSecondsToString(),
showDescription: $showDescription
)
}
}
}
//#Preview {
// ButtonHStackView()
//}

View File

@@ -12,7 +12,6 @@ struct NextRepetitionButtonView: View {
let buttonText: String
let nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum?
let flashcardId: UUID
let width: CGFloat
let color: Color
let geometry: GeometryProxy
let timeText: String
@@ -45,7 +44,7 @@ struct NextRepetitionButtonView: View {
}
.padding(.vertical, geometry.size.height / 80)
.foregroundColor(.black)
.frame(maxWidth: width)
.frame(maxWidth: geometry.size.width)
}
.background(color)
.buttonStyle(.plain)