f59d81fc5a
Previously the widget was picking from course VocabCards, which could land on any course week and was showing unrelated phrases instead of the verbs the user is actually studying. Now the widget uses a new VerbStore.fetchVerbOfDay helper that: - Expands the user's selectedLevel via VerbLevelGroup.dataLevels - Runs a FetchDescriptor<Verb> filtered by those levels, sorted by rank - Uses fetchCount + fetchOffset for a deterministic daily pick The main app mirrors UserProgress.selectedLevel into the shared app group UserDefaults (key "selectedVerbLevel") on every WidgetDataService update, so the widget process can read it without touching the cloud store. WordOfDay.weekNumber was replaced with a more flexible subtitle: String so widgets can display "Level: Basic" instead of course week numbers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
1.8 KiB
Swift
65 lines
1.8 KiB
Swift
import Foundation
|
|
|
|
public struct WordOfDay: Codable, Equatable, Sendable {
|
|
public var spanish: String
|
|
public var english: String
|
|
public var subtitle: String
|
|
|
|
public init(spanish: String, english: String, subtitle: String) {
|
|
self.spanish = spanish
|
|
self.english = english
|
|
self.subtitle = subtitle
|
|
}
|
|
}
|
|
|
|
public struct WidgetData: Codable, Equatable, Sendable {
|
|
public var todayCount: Int
|
|
public var dailyGoal: Int
|
|
public var currentStreak: Int
|
|
public var dueCardCount: Int
|
|
public var wordOfTheDay: WordOfDay?
|
|
public var latestTestScore: Int?
|
|
public var latestTestWeek: Int?
|
|
public var currentWeek: Int
|
|
public var lastUpdated: Date
|
|
|
|
public init(
|
|
todayCount: Int,
|
|
dailyGoal: Int,
|
|
currentStreak: Int,
|
|
dueCardCount: Int,
|
|
wordOfTheDay: WordOfDay?,
|
|
latestTestScore: Int?,
|
|
latestTestWeek: Int?,
|
|
currentWeek: Int,
|
|
lastUpdated: Date
|
|
) {
|
|
self.todayCount = todayCount
|
|
self.dailyGoal = dailyGoal
|
|
self.currentStreak = currentStreak
|
|
self.dueCardCount = dueCardCount
|
|
self.wordOfTheDay = wordOfTheDay
|
|
self.latestTestScore = latestTestScore
|
|
self.latestTestWeek = latestTestWeek
|
|
self.currentWeek = currentWeek
|
|
self.lastUpdated = lastUpdated
|
|
}
|
|
|
|
public static let placeholder = WidgetData(
|
|
todayCount: 12,
|
|
dailyGoal: 50,
|
|
currentStreak: 3,
|
|
dueCardCount: 8,
|
|
wordOfTheDay: WordOfDay(spanish: "hablar", english: "to speak", subtitle: "Level: Basic"),
|
|
latestTestScore: 85,
|
|
latestTestWeek: 2,
|
|
currentWeek: 2,
|
|
lastUpdated: Date()
|
|
)
|
|
|
|
public var progressPercent: Double {
|
|
guard dailyGoal > 0 else { return 0 }
|
|
return min(Double(todayCount) / Double(dailyGoal), 1.0)
|
|
}
|
|
}
|