mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Add chemistry and biology lessons for natural sciences.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
09312d8c93
commit
bd7ab09b1d
30 changed files with 2519 additions and 13 deletions
|
|
@ -168,6 +168,16 @@ final class AppModel: ObservableObject {
|
|||
refresh()
|
||||
}
|
||||
|
||||
func markChem(_ id: Int) {
|
||||
progress.markChem(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markBio(_ id: Int) {
|
||||
progress.markBio(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markMluv(_ n: Int) {
|
||||
progress.markMluv(n)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ final class Content {
|
|||
let lit2: [J]
|
||||
let lit3: [J]
|
||||
let lit4: [J]
|
||||
let chem: [J]
|
||||
let bio: [J]
|
||||
let mluvnice: [J]
|
||||
let books: [J]
|
||||
let changelog: [J]
|
||||
|
|
@ -78,6 +80,8 @@ final class Content {
|
|||
lit2 = raw.arr("lit2")
|
||||
lit3 = raw.arr("lit3")
|
||||
lit4 = raw.arr("lit4")
|
||||
chem = raw.arr("chem")
|
||||
bio = raw.arr("bio")
|
||||
mluvnice = raw.arr("mluvnice")
|
||||
books = raw.arr("books")
|
||||
changelog = raw.arr("changelog")
|
||||
|
|
@ -94,6 +98,8 @@ final class Content {
|
|||
func lit2Lesson(_ id: Int) -> J? { lit2.first { $0.int("id") == id } }
|
||||
func lit3Lesson(_ id: Int) -> J? { lit3.first { $0.int("id") == id } }
|
||||
func lit4Lesson(_ id: Int) -> J? { lit4.first { $0.int("id") == id } }
|
||||
func chemLesson(_ id: Int) -> J? { chem.first { $0.int("id") == id } }
|
||||
func bioLesson(_ id: Int) -> J? { bio.first { $0.int("id") == id } }
|
||||
func mluv(_ n: Int) -> J? { mluvnice.first { $0.int("id") == n } }
|
||||
func book(_ id: String) -> J? { books.first { $0.str("id") == id } }
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ final class ProgressStore {
|
|||
func lit4Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit4.\(id)") }
|
||||
func markLit4(_ id: Int) { defaults.set(true, forKey: "lit4.\(id)") }
|
||||
|
||||
func chemDone(_ id: Int) -> Bool { defaults.bool(forKey: "chem.\(id)") }
|
||||
func markChem(_ id: Int) { defaults.set(true, forKey: "chem.\(id)") }
|
||||
func bioDone(_ id: Int) -> Bool { defaults.bool(forKey: "bio.\(id)") }
|
||||
func markBio(_ id: Int) { defaults.set(true, forKey: "bio.\(id)") }
|
||||
|
||||
func mluvDone(_ n: Int) -> Bool { defaults.bool(forKey: "mluv.\(n)") }
|
||||
func markMluv(_ n: Int) { defaults.set(true, forKey: "mluv.\(n)") }
|
||||
|
||||
|
|
@ -162,6 +167,22 @@ func summarize(_ content: Content, _ p: ProgressStore) -> ProgressSum {
|
|||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.chem {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.chemDone(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.bio {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.bioDone(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
sum.totalEx += content.mluvnice.count
|
||||
sum.openUnits += 1
|
||||
let md = content.mluvnice.filter { p.mluvDone($0.int("id")) }.count
|
||||
|
|
|
|||
|
|
@ -49,6 +49,13 @@ enum Route: Hashable {
|
|||
case lit4Map
|
||||
case lit4Lesson(Int)
|
||||
case lit4Ex(Int)
|
||||
case sciMap
|
||||
case chemMap
|
||||
case chemLesson(Int)
|
||||
case chemEx(Int)
|
||||
case bioMap
|
||||
case bioLesson(Int)
|
||||
case bioEx(Int)
|
||||
case czechMap
|
||||
case mluvnice
|
||||
case mluvEx(Int)
|
||||
|
|
@ -100,6 +107,13 @@ enum Route: Hashable {
|
|||
case .lit4Map: return "lit4map"
|
||||
case .lit4Lesson(let id): return "lit4unit\(id)"
|
||||
case .lit4Ex(let id): return "lit4ex\(id)"
|
||||
case .sciMap: return "scimap"
|
||||
case .chemMap: return "chemmap"
|
||||
case .chemLesson(let id): return "chemunit\(id)"
|
||||
case .chemEx(let id): return "chemex\(id)"
|
||||
case .bioMap: return "biomap"
|
||||
case .bioLesson(let id): return "biounit\(id)"
|
||||
case .bioEx(let id): return "bioex\(id)"
|
||||
case .czechMap: return "czechmap"
|
||||
case .mluvnice: return "mluvnice"
|
||||
case .mluvEx(let n): return "mluve\(n)"
|
||||
|
|
@ -200,6 +214,20 @@ enum Route: Hashable {
|
|||
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id)]
|
||||
case .lit4Ex(let id):
|
||||
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id), .lit4Ex(id)]
|
||||
case .sciMap:
|
||||
return [.sciMap]
|
||||
case .chemMap:
|
||||
return [.sciMap, .chemMap]
|
||||
case .chemLesson(let id):
|
||||
return [.sciMap, .chemMap, .chemLesson(id)]
|
||||
case .chemEx(let id):
|
||||
return [.sciMap, .chemMap, .chemLesson(id), .chemEx(id)]
|
||||
case .bioMap:
|
||||
return [.sciMap, .bioMap]
|
||||
case .bioLesson(let id):
|
||||
return [.sciMap, .bioMap, .bioLesson(id)]
|
||||
case .bioEx(let id):
|
||||
return [.sciMap, .bioMap, .bioLesson(id), .bioEx(id)]
|
||||
case .czechMap:
|
||||
return [.czechMap]
|
||||
case .mluvnice:
|
||||
|
|
@ -238,6 +266,9 @@ func routeFromPage(_ page: String) -> Route? {
|
|||
case "lit2map": return .lit2Map
|
||||
case "lit3map": return .lit3Map
|
||||
case "lit4map": return .lit4Map
|
||||
case "scimap": return .sciMap
|
||||
case "chemmap": return .chemMap
|
||||
case "biomap": return .bioMap
|
||||
case "czechmap": return .czechMap
|
||||
case "mluvnice": return .mluvnice
|
||||
case "readinglist": return .readingList
|
||||
|
|
@ -281,6 +312,18 @@ func routeFromPage(_ page: String) -> Route? {
|
|||
if let m = page.wholeMatch(of: /hwex(\d+)/), let n = Int(m.1) {
|
||||
return .hwEx(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /chemunit(\d+)/), let n = Int(m.1) {
|
||||
return .chemLesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /chemex(\d+)/), let n = Int(m.1) {
|
||||
return .chemEx(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /biounit(\d+)/), let n = Int(m.1) {
|
||||
return .bioLesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /bioex(\d+)/), let n = Int(m.1) {
|
||||
return .bioEx(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /lit4unit(\d+)/), let n = Int(m.1) {
|
||||
return .lit4Lesson(n)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -607,6 +607,7 @@ func subjectSymbol(_ icon: String) -> String {
|
|||
case "chip": return "cpu"
|
||||
case "cz": return "text.book.closed.fill"
|
||||
case "people": return "person.2.fill"
|
||||
case "flask": return "flask.fill"
|
||||
default: return "lock.fill"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -625,6 +625,27 @@ struct NetQuizScreen: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct SciQuizScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
let area: String
|
||||
let id: Int
|
||||
|
||||
var body: some View {
|
||||
let lesson = area == "bio" ? vm.content.bioLesson(id) : vm.content.chemLesson(id)
|
||||
if let lesson {
|
||||
let spec = J([
|
||||
"type": "choice",
|
||||
"title": vm.tr(lesson.str("exTitleKey")),
|
||||
"sub": lesson.str("quizHeadKey"),
|
||||
"questions": lesson.rawArray("quiz"),
|
||||
])
|
||||
DispatchExercise(vm: vm, spec: spec, titleFallback: vm.tr(lesson.str("exTitleKey"))) {
|
||||
if area == "bio" { vm.markBio(id) } else { vm.markChem(id) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LitYearQuizScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
let year: Int
|
||||
|
|
|
|||
|
|
@ -695,6 +695,10 @@ private func subjectSum(_ vm: AppModel, _ s: J) -> ProgressSum {
|
|||
+ vm.content.on2.filter { vm.progress.on2Done($0.int("id")) }.count
|
||||
+ vm.content.on3.filter { vm.progress.on3Done($0.int("id")) }.count
|
||||
+ vm.content.on4.filter { vm.progress.on4Done($0.int("id")) }.count
|
||||
case "scimap":
|
||||
sum.totalEx = vm.content.chem.count + vm.content.bio.count
|
||||
sum.doneEx = vm.content.chem.filter { vm.progress.chemDone($0.int("id")) }.count
|
||||
+ vm.content.bio.filter { vm.progress.bioDone($0.int("id")) }.count
|
||||
case "czechmap":
|
||||
let litCount = vm.content.lit.count + vm.content.lit2.count + vm.content.lit3.count + vm.content.lit4.count
|
||||
let litDone = vm.content.lit.filter { vm.progress.litDone($0.int("id")) }.count
|
||||
|
|
@ -925,6 +929,16 @@ private func buildSearch(_ vm: AppModel) -> [Hit] {
|
|||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit\(l.int("id"))", extra: "literatura")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex\(l.int("id"))")
|
||||
}
|
||||
add(vm.tr("Chemie"), vm.tr("search_lesson"), "chemmap", extra: "chemie")
|
||||
add(vm.tr("Biologie"), vm.tr("search_lesson"), "biomap", extra: "biologie")
|
||||
for l in vm.content.chem {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "chemunit\(l.int("id"))", extra: "chemie")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "chemex\(l.int("id"))")
|
||||
}
|
||||
for l in vm.content.bio {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "biounit\(l.int("id"))", extra: "biologie")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "bioex\(l.int("id"))")
|
||||
}
|
||||
add(vm.tr("Mluvnice"), vm.tr("search_lesson"), "mluvnice")
|
||||
add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist")
|
||||
for b in vm.content.books {
|
||||
|
|
@ -1471,6 +1485,50 @@ struct LitYearsScreen: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct SciMapScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
MacFillGrid(count: 2, minWidth: 260, minHeight: 180) { i in
|
||||
if i == 0 {
|
||||
NavigationLink(value: Route.chemMap) {
|
||||
MacLinkCard(title: vm.tr("Chemie"), subtitle: vm.tr("chem_sub"), systemImage: "flask.fill")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
} else {
|
||||
NavigationLink(value: Route.bioMap) {
|
||||
MacLinkCard(title: vm.tr("Biologie"), subtitle: vm.tr("bio_sub"), systemImage: "leaf.fill")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
.navigationTitle(vm.tr("Základy Přírodopisných věd"))
|
||||
.navigationSubtitle(vm.tr("sci_sub"))
|
||||
#else
|
||||
List {
|
||||
NavigationLink(value: Route.chemMap) {
|
||||
Label {
|
||||
ListRowLabel(title: vm.tr("Chemie"), subtitle: vm.tr("chem_sub"))
|
||||
} icon: {
|
||||
Image(systemName: "flask.fill")
|
||||
}
|
||||
}
|
||||
NavigationLink(value: Route.bioMap) {
|
||||
Label {
|
||||
ListRowLabel(title: vm.tr("Biologie"), subtitle: vm.tr("bio_sub"))
|
||||
} icon: {
|
||||
Image(systemName: "leaf.fill")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(vm.tr("Základy Přírodopisných věd"))
|
||||
.navigationSubtitle(vm.tr("sci_sub"))
|
||||
.appListStyle()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct CzechMapScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
|
||||
|
|
@ -2151,6 +2209,50 @@ struct RouteDestination: View {
|
|||
}
|
||||
case .lit4Ex(let id):
|
||||
LitYearQuizScreen(vm: vm, year: 4, id: id)
|
||||
case .sciMap:
|
||||
SciMapScreen(vm: vm)
|
||||
case .chemMap:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("Chemie"),
|
||||
subtitle: vm.tr("chem_sub"),
|
||||
rows: vm.content.chem.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "c\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.chemDone(id),
|
||||
destination: .chemLesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .chemLesson(let id):
|
||||
if let l = vm.content.chemLesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .chemEx(id))
|
||||
}
|
||||
case .chemEx(let id):
|
||||
SciQuizScreen(vm: vm, area: "chem", id: id)
|
||||
case .bioMap:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("Biologie"),
|
||||
subtitle: vm.tr("bio_sub"),
|
||||
rows: vm.content.bio.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "b\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.bioDone(id),
|
||||
destination: .bioLesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .bioLesson(let id):
|
||||
if let l = vm.content.bioLesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .bioEx(id))
|
||||
}
|
||||
case .bioEx(let id):
|
||||
SciQuizScreen(vm: vm, area: "bio", id: id)
|
||||
case .mluvnice:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue