Compare commits

...

2 Commits

Author SHA1 Message Date
Trey t
4e874f60d7 Move Settings to Dashboard toolbar to kill iPhone More overflow
Six tabs forced iPhone to spill Course into the system "More" tab, whose
own NavigationStack nested with CourseView's and produced a double back
chevron on every week/deck push. Drop the Settings tab, reach it from a
gear button on Dashboard that presents SettingsView as a sheet, and keep
the visible tab count at five so no More overflow exists.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:22:27 -05:00
Trey t
644dbb7230 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>
2026-04-11 18:17:30 -05:00
6 changed files with 55 additions and 13 deletions

View File

@@ -9,6 +9,7 @@ struct MissedCourseItem: Codable, Hashable, Sendable {
@Model
final class TestResult {
var id: String = ""
var courseName: String = ""
var weekNumber: Int = 0
var quizType: String = ""
var totalQuestions: Int = 0
@@ -25,8 +26,9 @@ final class TestResult {
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.courseName = courseName
self.weekNumber = weekNumber
self.quizType = quizType
self.totalQuestions = totalQuestions
@@ -35,8 +37,9 @@ final class TestResult {
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(
courseName: courseName,
weekNumber: weekNumber,
quizType: quizType,
totalQuestions: totalQuestions,

View File

@@ -6,6 +6,7 @@ import PencilKit
struct CourseQuizView: View {
let cards: [VocabCard]
let quizType: QuizType
let courseName: String
let weekNumber: Int
let isFocusMode: Bool
@@ -508,6 +509,7 @@ struct CourseQuizView: View {
private func saveResult() {
let result = TestResult(
courseName: courseName,
weekNumber: weekNumber,
quizType: quizType.rawValue,
totalQuestions: shuffledCards.count,
@@ -521,7 +523,13 @@ struct CourseQuizView: View {
#Preview {
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)
}

View File

@@ -31,7 +31,9 @@ struct CourseView: View {
}
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 }
return results.map(\.scorePercent).max()
}
@@ -70,7 +72,7 @@ struct CourseView: View {
ForEach(weekGroups, id: \.week) { week, weekDecks in
Section {
// Test button
NavigationLink(value: week) {
NavigationLink(value: WeekTestDestination(courseName: activeCourse, weekNumber: week)) {
HStack(spacing: 12) {
Image(systemName: "pencil.and.list.clipboard")
.font(.title3)
@@ -112,8 +114,8 @@ struct CourseView: View {
.navigationDestination(for: CourseDeck.self) { deck in
DeckStudyView(deck: deck)
}
.navigationDestination(for: Int.self) { week in
WeekTestView(weekNumber: week)
.navigationDestination(for: WeekTestDestination.self) { dest in
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
private struct DeckRowView: View {

View File

@@ -3,6 +3,7 @@ import SharedModels
import SwiftData
struct WeekTestView: View {
let courseName: String
let weekNumber: Int
@Environment(\.modelContext) private var modelContext
@Environment(\.cloudModelContextProvider) private var cloudModelContextProvider
@@ -60,6 +61,7 @@ struct WeekTestView: View {
CourseQuizView(
cards: weekCards,
quizType: type,
courseName: courseName,
weekNumber: weekNumber,
isFocusMode: false
)
@@ -139,6 +141,7 @@ struct WeekTestView: View {
CourseQuizView(
cards: focusCards,
quizType: .mcEsToEn,
courseName: courseName,
weekNumber: weekNumber,
isFocusMode: true
)
@@ -206,7 +209,11 @@ struct WeekTestView: View {
}
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)
var cards: [VocabCard] = []
for deckId in deckIds {
@@ -221,8 +228,12 @@ struct WeekTestView: View {
}
private func loadResults() {
let course = courseName
let week = weekNumber
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)]
)
weekResults = (try? cloudModelContext.fetch(descriptor)) ?? []
@@ -237,7 +248,7 @@ struct WeekTestView: View {
#Preview {
NavigationStack {
WeekTestView(weekNumber: 1)
WeekTestView(courseName: "LanGo Spanish | Beginner I", weekNumber: 1)
}
.modelContainer(for: [TestResult.self, CourseDeck.self, VocabCard.self], inMemory: true)
}

View File

@@ -8,6 +8,7 @@ struct DashboardView: View {
@State private var dailyLogs: [DailyLog] = []
@State private var testResults: [TestResult] = []
@State private var reviewCards: [ReviewCard] = []
@State private var showingSettings = false
private var cloudModelContext: ModelContext { cloudModelContextProvider() }
@@ -33,6 +34,19 @@ struct DashboardView: View {
.adaptiveContainer(maxWidth: 800)
}
.navigationTitle("Dashboard")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
showingSettings = true
} label: {
Image(systemName: "gearshape")
}
.accessibilityLabel("Settings")
}
}
.sheet(isPresented: $showingSettings) {
SettingsView()
}
.onAppear(perform: loadData)
}
}

View File

@@ -18,9 +18,6 @@ struct MainTabView: View {
Tab("Course", systemImage: "list.clipboard") {
CourseView()
}
Tab("Settings", systemImage: "gearshape") {
SettingsView()
}
}
}
}