Scope week tests to the selected course
WeekTestView filtered decks and TestResults by weekNumber alone, so Week 3 of any course pulled content from every course's Week 3 simultaneously. Thread courseName through the navigation destination, quiz view, and TestResult model so quiz cards, score history, and focus-area missed items are all scoped to the active course. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ struct MissedCourseItem: Codable, Hashable, Sendable {
|
|||||||
@Model
|
@Model
|
||||||
final class TestResult {
|
final class TestResult {
|
||||||
var id: String = ""
|
var id: String = ""
|
||||||
|
var courseName: String = ""
|
||||||
var weekNumber: Int = 0
|
var weekNumber: Int = 0
|
||||||
var quizType: String = ""
|
var quizType: String = ""
|
||||||
var totalQuestions: Int = 0
|
var totalQuestions: Int = 0
|
||||||
@@ -25,8 +26,9 @@ final class TestResult {
|
|||||||
return Int(round(Double(correctCount) / Double(totalQuestions) * 100))
|
return Int(round(Double(correctCount) / Double(totalQuestions) * 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
init(weekNumber: Int, quizType: String, totalQuestions: Int, correctCount: Int, missedItems: [MissedCourseItem]) {
|
init(courseName: String, weekNumber: Int, quizType: String, totalQuestions: Int, correctCount: Int, missedItems: [MissedCourseItem]) {
|
||||||
self.id = UUID().uuidString
|
self.id = UUID().uuidString
|
||||||
|
self.courseName = courseName
|
||||||
self.weekNumber = weekNumber
|
self.weekNumber = weekNumber
|
||||||
self.quizType = quizType
|
self.quizType = quizType
|
||||||
self.totalQuestions = totalQuestions
|
self.totalQuestions = totalQuestions
|
||||||
@@ -35,8 +37,9 @@ final class TestResult {
|
|||||||
self.missedItems = missedItems
|
self.missedItems = missedItems
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(weekNumber: Int, quizType: String, totalQuestions: Int, correctCount: Int, missedFronts: [String], missedBacks: [String]) {
|
convenience init(courseName: String, weekNumber: Int, quizType: String, totalQuestions: Int, correctCount: Int, missedFronts: [String], missedBacks: [String]) {
|
||||||
self.init(
|
self.init(
|
||||||
|
courseName: courseName,
|
||||||
weekNumber: weekNumber,
|
weekNumber: weekNumber,
|
||||||
quizType: quizType,
|
quizType: quizType,
|
||||||
totalQuestions: totalQuestions,
|
totalQuestions: totalQuestions,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import PencilKit
|
|||||||
struct CourseQuizView: View {
|
struct CourseQuizView: View {
|
||||||
let cards: [VocabCard]
|
let cards: [VocabCard]
|
||||||
let quizType: QuizType
|
let quizType: QuizType
|
||||||
|
let courseName: String
|
||||||
let weekNumber: Int
|
let weekNumber: Int
|
||||||
let isFocusMode: Bool
|
let isFocusMode: Bool
|
||||||
|
|
||||||
@@ -508,6 +509,7 @@ struct CourseQuizView: View {
|
|||||||
|
|
||||||
private func saveResult() {
|
private func saveResult() {
|
||||||
let result = TestResult(
|
let result = TestResult(
|
||||||
|
courseName: courseName,
|
||||||
weekNumber: weekNumber,
|
weekNumber: weekNumber,
|
||||||
quizType: quizType.rawValue,
|
quizType: quizType.rawValue,
|
||||||
totalQuestions: shuffledCards.count,
|
totalQuestions: shuffledCards.count,
|
||||||
@@ -521,7 +523,13 @@ struct CourseQuizView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
CourseQuizView(cards: [], quizType: .mcEsToEn, weekNumber: 1, isFocusMode: false)
|
CourseQuizView(
|
||||||
|
cards: [],
|
||||||
|
quizType: .mcEsToEn,
|
||||||
|
courseName: "LanGo Spanish | Beginner I",
|
||||||
|
weekNumber: 1,
|
||||||
|
isFocusMode: false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.modelContainer(for: [TestResult.self, VocabCard.self], inMemory: true)
|
.modelContainer(for: [TestResult.self, VocabCard.self], inMemory: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ struct CourseView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func bestScore(for week: Int) -> Int? {
|
private func bestScore(for week: Int) -> Int? {
|
||||||
let results = testResults.filter { $0.weekNumber == week }
|
let results = testResults.filter {
|
||||||
|
$0.courseName == activeCourse && $0.weekNumber == week
|
||||||
|
}
|
||||||
guard !results.isEmpty else { return nil }
|
guard !results.isEmpty else { return nil }
|
||||||
return results.map(\.scorePercent).max()
|
return results.map(\.scorePercent).max()
|
||||||
}
|
}
|
||||||
@@ -70,7 +72,7 @@ struct CourseView: View {
|
|||||||
ForEach(weekGroups, id: \.week) { week, weekDecks in
|
ForEach(weekGroups, id: \.week) { week, weekDecks in
|
||||||
Section {
|
Section {
|
||||||
// Test button
|
// Test button
|
||||||
NavigationLink(value: week) {
|
NavigationLink(value: WeekTestDestination(courseName: activeCourse, weekNumber: week)) {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
Image(systemName: "pencil.and.list.clipboard")
|
Image(systemName: "pencil.and.list.clipboard")
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
@@ -112,8 +114,8 @@ struct CourseView: View {
|
|||||||
.navigationDestination(for: CourseDeck.self) { deck in
|
.navigationDestination(for: CourseDeck.self) { deck in
|
||||||
DeckStudyView(deck: deck)
|
DeckStudyView(deck: deck)
|
||||||
}
|
}
|
||||||
.navigationDestination(for: Int.self) { week in
|
.navigationDestination(for: WeekTestDestination.self) { dest in
|
||||||
WeekTestView(weekNumber: week)
|
WeekTestView(courseName: dest.courseName, weekNumber: dest.weekNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +125,13 @@ struct CourseView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Navigation
|
||||||
|
|
||||||
|
struct WeekTestDestination: Hashable {
|
||||||
|
let courseName: String
|
||||||
|
let weekNumber: Int
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Deck Row
|
// MARK: - Deck Row
|
||||||
|
|
||||||
private struct DeckRowView: View {
|
private struct DeckRowView: View {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import SharedModels
|
|||||||
import SwiftData
|
import SwiftData
|
||||||
|
|
||||||
struct WeekTestView: View {
|
struct WeekTestView: View {
|
||||||
|
let courseName: String
|
||||||
let weekNumber: Int
|
let weekNumber: Int
|
||||||
@Environment(\.modelContext) private var modelContext
|
@Environment(\.modelContext) private var modelContext
|
||||||
@Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
|
@Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
|
||||||
@@ -60,6 +61,7 @@ struct WeekTestView: View {
|
|||||||
CourseQuizView(
|
CourseQuizView(
|
||||||
cards: weekCards,
|
cards: weekCards,
|
||||||
quizType: type,
|
quizType: type,
|
||||||
|
courseName: courseName,
|
||||||
weekNumber: weekNumber,
|
weekNumber: weekNumber,
|
||||||
isFocusMode: false
|
isFocusMode: false
|
||||||
)
|
)
|
||||||
@@ -139,6 +141,7 @@ struct WeekTestView: View {
|
|||||||
CourseQuizView(
|
CourseQuizView(
|
||||||
cards: focusCards,
|
cards: focusCards,
|
||||||
quizType: .mcEsToEn,
|
quizType: .mcEsToEn,
|
||||||
|
courseName: courseName,
|
||||||
weekNumber: weekNumber,
|
weekNumber: weekNumber,
|
||||||
isFocusMode: true
|
isFocusMode: true
|
||||||
)
|
)
|
||||||
@@ -206,7 +209,11 @@ struct WeekTestView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadCards() {
|
private func loadCards() {
|
||||||
let weekDecks = allDecks.filter { $0.weekNumber == weekNumber && !$0.isReversed }
|
let course = courseName
|
||||||
|
let week = weekNumber
|
||||||
|
let weekDecks = allDecks.filter {
|
||||||
|
$0.courseName == course && $0.weekNumber == week && !$0.isReversed
|
||||||
|
}
|
||||||
let deckIds = weekDecks.map(\.id)
|
let deckIds = weekDecks.map(\.id)
|
||||||
var cards: [VocabCard] = []
|
var cards: [VocabCard] = []
|
||||||
for deckId in deckIds {
|
for deckId in deckIds {
|
||||||
@@ -221,8 +228,12 @@ struct WeekTestView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadResults() {
|
private func loadResults() {
|
||||||
|
let course = courseName
|
||||||
|
let week = weekNumber
|
||||||
let descriptor = FetchDescriptor<TestResult>(
|
let descriptor = FetchDescriptor<TestResult>(
|
||||||
predicate: #Predicate<TestResult> { $0.weekNumber == weekNumber },
|
predicate: #Predicate<TestResult> {
|
||||||
|
$0.courseName == course && $0.weekNumber == week
|
||||||
|
},
|
||||||
sortBy: [SortDescriptor(\TestResult.dateTaken, order: .reverse)]
|
sortBy: [SortDescriptor(\TestResult.dateTaken, order: .reverse)]
|
||||||
)
|
)
|
||||||
weekResults = (try? cloudModelContext.fetch(descriptor)) ?? []
|
weekResults = (try? cloudModelContext.fetch(descriptor)) ?? []
|
||||||
@@ -237,7 +248,7 @@ struct WeekTestView: View {
|
|||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
WeekTestView(weekNumber: 1)
|
WeekTestView(courseName: "LanGo Spanish | Beginner I", weekNumber: 1)
|
||||||
}
|
}
|
||||||
.modelContainer(for: [TestResult.self, CourseDeck.self, VocabCard.self], inMemory: true)
|
.modelContainer(for: [TestResult.self, CourseDeck.self, VocabCard.self], inMemory: true)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user