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 very short description",
"This is a medium length description that should be long enough to cover all cases" "This is a medium length description that should be long enough to cover all cases"
].randomElement()! ].randomElement()!
flashcard.nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.OneYear.rawValue flashcard.nextSpacedRepetitionMilestone = SpacedRepetitionMilestoneEnum.allCases.randomElement()!.rawValue
flashcard.lastSeenOn = [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.shownCount = [0, 1, 2, 3, 4, 5].randomElement()!
flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()! flashcard.dateAdded = [Date(), Date().addingTimeInterval(-86400), Date().addingTimeInterval(-172800)].randomElement()!
// flashcard.calculatedNextRepetition = flashcard.lastSeenOn ?? Date() + TimeInterval(flashcard.nextSpacedRepetitionMilestone)
} }
do { do {
try viewContext.save() try viewContext.save()

View File

@@ -11,6 +11,8 @@ import CoreData
struct AnkiView: View { struct AnkiView: View {
@EnvironmentObject var model: WordAXModelView @EnvironmentObject var model: WordAXModelView
@Environment(\.managedObjectContext) var moc @Environment(\.managedObjectContext) var moc
// get flashcards to display
@FetchRequest(sortDescriptors: [ @FetchRequest(sortDescriptors: [
NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false), NSSortDescriptor(key: "nextSpacedRepetitionMilestone", ascending: false),
NSSortDescriptor(key: "lastSeenOn", ascending: true) NSSortDescriptor(key: "lastSeenOn", ascending: true)
@@ -22,20 +24,17 @@ struct AnkiView: View {
NSPredicate(format: "lastSeenOn == nil") NSPredicate(format: "lastSeenOn == nil")
])) var flashcards: FetchedResults<Flashcard> ])) var flashcards: FetchedResults<Flashcard>
@State private var timeRemaining = 10
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State var sortedFlashcards: [Flashcard] = []
@Environment(\.colorScheme) var colorScheme
// get the most recent flashcard // get the most recent flashcard
@FetchRequest(sortDescriptors: [], @FetchRequest(sortDescriptors: [],
predicate: NSPredicate(format: "%K != nil", "lastSeenOn")) var soonestFlashcard: FetchedResults<Flashcard> 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 @State var showDescription = false
@Environment(\.colorScheme) var colorScheme
var body: some View { var body: some View {
if !flashcards.isEmpty && flashcards.first != nil { if !flashcards.isEmpty && flashcards.first != nil {
GeometryReader { geometry in GeometryReader { geometry in
@@ -47,54 +46,22 @@ struct AnkiView: View {
// Text("How did you do?") // Text("How did you do?")
// .font(.subheadline) // .font(.subheadline)
// .foregroundStyle(.gray) // .foregroundStyle(.gray)
HStack(alignment: .center) { ButtonHStackView(flashcard: flashcards.first!, geometry: geometry, showDescription: $showDescription)
// 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]) .padding([.bottom, .trailing, .leading])
} }
} }
} }
} else { } else {
if !soonestFlashcard.isEmpty { if !soonestFlashcard.isEmpty {
Group {
Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())") Text("Next flashcard in: \(timeRemaining.convertDurationSecondsToCountdown())")
.foregroundStyle(.black) .foregroundStyle(.black)
.padding() .padding()
.frame(maxWidth: .infinity - 50)
.background(.yellow) .background(.yellow)
.clipShape(.buttonBorder) .clipShape(.buttonBorder)
.padding(.vertical, 50) .padding(.vertical, 50)
.padding(.horizontal) .padding(.horizontal)
.background(.gray.opacity(0.3))
.clipShape(.buttonBorder)
.onAppear { .onAppear {
if !soonestFlashcard.isEmpty { if !soonestFlashcard.isEmpty {
sortedFlashcards = soonestFlashcard.sorted(by: { sortedFlashcards = soonestFlashcard.sorted(by: {
@@ -108,6 +75,10 @@ struct AnkiView: View {
timeRemaining -= 1 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 buttonText: String
let nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum? let nextMilestone: Flashcard.SpacedRepetitionMilestoneEnum?
let flashcardId: UUID let flashcardId: UUID
let width: CGFloat
let color: Color let color: Color
let geometry: GeometryProxy let geometry: GeometryProxy
let timeText: String let timeText: String
@@ -45,7 +44,7 @@ struct NextRepetitionButtonView: View {
} }
.padding(.vertical, geometry.size.height / 80) .padding(.vertical, geometry.size.height / 80)
.foregroundColor(.black) .foregroundColor(.black)
.frame(maxWidth: width) .frame(maxWidth: geometry.size.width)
} }
.background(color) .background(color)
.buttonStyle(.plain) .buttonStyle(.plain)