Fix textbook section missing on installs that predate bundled JSON
Earlier launches (before cd491bd bundled textbook_data.json) ran
seedTextbookData, got "not bundled — skipping", and still bumped
UserDefaults textbookDataVersion to 9. Subsequent launches then
short-circuited in refreshTextbookDataIfNeeded and never re-seeded,
so ZTEXTBOOKCHAPTER stayed empty and the Course tab hid the section.
- seedTextbookData now returns Bool (true only when chapters inserted).
- Both call sites only write the version key on success, so a missing
or unparseable bundle no longer locks us out of future retries.
- Bumped textbookDataVersion to 10 to force existing installs to
re-seed on next launch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ actor DataLoader {
|
|||||||
static let courseDataVersion = 7
|
static let courseDataVersion = 7
|
||||||
static let courseDataKey = "courseDataVersion"
|
static let courseDataKey = "courseDataVersion"
|
||||||
|
|
||||||
static let textbookDataVersion = 9
|
static let textbookDataVersion = 10
|
||||||
static let textbookDataKey = "textbookDataVersion"
|
static let textbookDataKey = "textbookDataVersion"
|
||||||
|
|
||||||
/// Quick check: does the DB need seeding or course data refresh?
|
/// Quick check: does the DB need seeding or course data refresh?
|
||||||
@@ -140,10 +140,13 @@ actor DataLoader {
|
|||||||
// Seed course data (uses the same mainContext so @Query sees it)
|
// Seed course data (uses the same mainContext so @Query sees it)
|
||||||
seedCourseData(context: context)
|
seedCourseData(context: context)
|
||||||
|
|
||||||
// Seed textbook data
|
// Seed textbook data — only bump the version key if the seed
|
||||||
seedTextbookData(context: context)
|
// actually inserted rows, so a missing/unparseable bundle doesn't
|
||||||
|
// permanently lock us out of future re-seeds.
|
||||||
|
if seedTextbookData(context: context) {
|
||||||
UserDefaults.standard.set(textbookDataVersion, forKey: textbookDataKey)
|
UserDefaults.standard.set(textbookDataVersion, forKey: textbookDataKey)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Re-seed textbook data if the version has changed.
|
/// Re-seed textbook data if the version has changed.
|
||||||
static func refreshTextbookDataIfNeeded(container: ModelContainer) async {
|
static func refreshTextbookDataIfNeeded(container: ModelContainer) async {
|
||||||
@@ -165,9 +168,12 @@ actor DataLoader {
|
|||||||
}
|
}
|
||||||
try? context.save()
|
try? context.save()
|
||||||
|
|
||||||
seedTextbookData(context: context)
|
if seedTextbookData(context: context) {
|
||||||
shared.set(textbookDataVersion, forKey: textbookDataKey)
|
shared.set(textbookDataVersion, forKey: textbookDataKey)
|
||||||
print("Textbook data re-seeded to version \(textbookDataVersion)")
|
print("Textbook data re-seeded to version \(textbookDataVersion)")
|
||||||
|
} else {
|
||||||
|
print("Textbook re-seed failed — leaving version key untouched so next launch retries")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-seed course data if the version has changed (e.g. examples were added).
|
/// Re-seed course data if the version has changed (e.g. examples were added).
|
||||||
@@ -378,21 +384,22 @@ actor DataLoader {
|
|||||||
|
|
||||||
// MARK: - Textbook seeding
|
// MARK: - Textbook seeding
|
||||||
|
|
||||||
private static func seedTextbookData(context: ModelContext) {
|
@discardableResult
|
||||||
|
private static func seedTextbookData(context: ModelContext) -> Bool {
|
||||||
let url = Bundle.main.url(forResource: "textbook_data", withExtension: "json")
|
let url = Bundle.main.url(forResource: "textbook_data", withExtension: "json")
|
||||||
?? Bundle.main.bundleURL.appendingPathComponent("textbook_data.json")
|
?? Bundle.main.bundleURL.appendingPathComponent("textbook_data.json")
|
||||||
guard let data = try? Data(contentsOf: url) else {
|
guard let data = try? Data(contentsOf: url) else {
|
||||||
print("[DataLoader] textbook_data.json not bundled — skipping textbook seed")
|
print("[DataLoader] textbook_data.json not bundled — skipping textbook seed")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
||||||
print("[DataLoader] ERROR: Could not parse textbook_data.json")
|
print("[DataLoader] ERROR: Could not parse textbook_data.json")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
let courseName = (json["courseName"] as? String) ?? "Textbook"
|
let courseName = (json["courseName"] as? String) ?? "Textbook"
|
||||||
guard let chapters = json["chapters"] as? [[String: Any]] else {
|
guard let chapters = json["chapters"] as? [[String: Any]] else {
|
||||||
print("[DataLoader] ERROR: textbook_data.json missing chapters")
|
print("[DataLoader] ERROR: textbook_data.json missing chapters")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var inserted = 0
|
var inserted = 0
|
||||||
@@ -480,6 +487,7 @@ actor DataLoader {
|
|||||||
seedTextbookVocabDecks(context: context, courseName: courseName)
|
seedTextbookVocabDecks(context: context, courseName: courseName)
|
||||||
|
|
||||||
print("Textbook seeding complete: \(inserted) chapters")
|
print("Textbook seeding complete: \(inserted) chapters")
|
||||||
|
return inserted > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func seedTextbookVocabDecks(context: ModelContext, courseName: String) {
|
private static func seedTextbookVocabDecks(context: ModelContext, courseName: String) {
|
||||||
|
|||||||
Reference in New Issue
Block a user