diff --git a/README.md b/README.md index 0e5304e..4f10f28 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,9 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses - **Správa počítačových sítí** — 1. ročník, 27 lekcí (VLSM + teorie a kvízy); ročníky 2–4 jsou zamčené - **Technické vybavení** — 1. ročník, 29 lekcí (architektura, data, skříň a deska, karty, disky, vstupní zařízení); ročníky 2–4 jsou zamčené -- **Český jazyk a literatura** — mluvnice (20 cvičení) a maturitní četba - (82 knih: zápisky, kvíz, sestavení děje); literární teorie je zatím zamčená +- **Český jazyk a literatura** — literatura (4 ročníky, 32 lekcí podle osnov + středních škol), mluvnice (20 cvičení) a maturitní četba + (82 knih: zápisky, kvíz, sestavení děje) - **Občanská nauka** — 1. ročník, 17 lekcí (člověk v lidském společenství); 2. ročník, 16 lekcí (člověk jako občan); 3. ročník, 16 lekcí (člověk a právo); 4. ročník, 16 lekcí (hospodářství, svět a filozofie) @@ -262,8 +263,9 @@ Intel Mac, another architecture, or hacking on the code → - **Computer networks** — year 1, 27 lessons (VLSM + theory/quizzes); years 2–4 are locked - **Computer hardware** — year 1, 29 lessons (architecture, data, case and board, cards, drives, input devices); years 2–4 are locked -- **Czech language** — grammar (20 exercises) and required reading - (82 books: notes, quiz, plot ordering); literature theory is still locked +- **Czech language** — literature (4 years, 32 lessons from the secondary-school + syllabus), grammar (20 exercises) and required reading + (82 books: notes, quiz, plot ordering) - **Civics** — year 1, 17 lessons (the individual and society); year 2, 16 lessons (the citizen in a democratic state); year 3, 16 lessons (the individual and the law); diff --git a/android/app/src/main/java/org/maturita/maturita/AppViewModel.kt b/android/app/src/main/java/org/maturita/maturita/AppViewModel.kt index ebab877..fe5a0a9 100644 --- a/android/app/src/main/java/org/maturita/maturita/AppViewModel.kt +++ b/android/app/src/main/java/org/maturita/maturita/AppViewModel.kt @@ -146,6 +146,26 @@ class AppViewModel(app: Application) : AndroidViewModel(app) { refresh() } + fun markLit(id: Int) { + progress.markLit(id) + refresh() + } + + fun markLit2(id: Int) { + progress.markLit2(id) + refresh() + } + + fun markLit3(id: Int) { + progress.markLit3(id) + refresh() + } + + fun markLit4(id: Int) { + progress.markLit4(id) + refresh() + } + fun markMluv(n: Int) { progress.markMluv(n) refresh() diff --git a/android/app/src/main/java/org/maturita/maturita/MainActivity.kt b/android/app/src/main/java/org/maturita/maturita/MainActivity.kt index 030ec78..68585c2 100644 --- a/android/app/src/main/java/org/maturita/maturita/MainActivity.kt +++ b/android/app/src/main/java/org/maturita/maturita/MainActivity.kt @@ -32,6 +32,7 @@ import org.maturita.maturita.ui.HomeScreen import org.maturita.maturita.ui.HwQuizScreen import org.maturita.maturita.ui.HwYearsScreen import org.maturita.maturita.ui.LessonListScreen +import org.maturita.maturita.ui.LitYearsScreen import org.maturita.maturita.ui.LessonRow import org.maturita.maturita.ui.LitQuizScreen import org.maturita.maturita.ui.MluvExercise @@ -288,6 +289,63 @@ private fun MaturitaAppBody(vm: AppViewModel) { } } is Route.On4Ex -> On4QuizScreen(vm, r.id) + Route.LitYears -> LitYearsScreen(vm) + Route.LitMap -> LessonListScreen( + vm, vm.tr("lit_year1"), vm.tr("lit_sub"), + vm.content.lit.map { l -> + val id = l.int("id") + LessonRow(vm.tr(l.str("titleKey")), vm.progress.litDone(id), Route.LitLesson(id)) + }, + ) + is Route.LitLesson -> { + val l = vm.content.litLesson(r.id) + if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) { + vm.replace(Route.LitEx(r.id)) + } + } + is Route.LitEx -> LitQuizScreen(vm, 1, r.id) + Route.Lit2Map -> LessonListScreen( + vm, vm.tr("lit_year2"), vm.tr("lit2_sub"), + vm.content.lit2.map { l -> + val id = l.int("id") + LessonRow(vm.tr(l.str("titleKey")), vm.progress.lit2Done(id), Route.Lit2Lesson(id)) + }, + ) + is Route.Lit2Lesson -> { + val l = vm.content.lit2Lesson(r.id) + if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) { + vm.replace(Route.Lit2Ex(r.id)) + } + } + is Route.Lit2Ex -> LitQuizScreen(vm, 2, r.id) + Route.Lit3Map -> LessonListScreen( + vm, vm.tr("lit_year3"), vm.tr("lit3_sub"), + vm.content.lit3.map { l -> + val id = l.int("id") + LessonRow(vm.tr(l.str("titleKey")), vm.progress.lit3Done(id), Route.Lit3Lesson(id)) + }, + ) + is Route.Lit3Lesson -> { + val l = vm.content.lit3Lesson(r.id) + if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) { + vm.replace(Route.Lit3Ex(r.id)) + } + } + is Route.Lit3Ex -> LitQuizScreen(vm, 3, r.id) + Route.Lit4Map -> LessonListScreen( + vm, vm.tr("lit_year4"), vm.tr("lit4_sub"), + vm.content.lit4.map { l -> + val id = l.int("id") + LessonRow(vm.tr(l.str("titleKey")), vm.progress.lit4Done(id), Route.Lit4Lesson(id)) + }, + ) + is Route.Lit4Lesson -> { + val l = vm.content.lit4Lesson(r.id) + if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) { + vm.replace(Route.Lit4Ex(r.id)) + } + } + is Route.Lit4Ex -> LitQuizScreen(vm, 4, r.id) Route.CzechMap -> CzechMapScreen(vm) Route.Mluvnice -> LessonListScreen( vm, vm.tr("Mluvnice"), vm.tr("mluv_sub"), diff --git a/android/app/src/main/java/org/maturita/maturita/Route.kt b/android/app/src/main/java/org/maturita/maturita/Route.kt index 41a6960..79bf595 100644 --- a/android/app/src/main/java/org/maturita/maturita/Route.kt +++ b/android/app/src/main/java/org/maturita/maturita/Route.kt @@ -30,6 +30,19 @@ sealed class Route(val page: String) { data object On4Map : Route("on4map") data class On4Lesson(val id: Int) : Route("on4unit$id") data class On4Ex(val id: Int) : Route("on4ex$id") + data object LitYears : Route("lityears") + data object LitMap : Route("litmap") + data class LitLesson(val id: Int) : Route("litunit$id") + data class LitEx(val id: Int) : Route("litex$id") + data object Lit2Map : Route("lit2map") + data class Lit2Lesson(val id: Int) : Route("lit2unit$id") + data class Lit2Ex(val id: Int) : Route("lit2ex$id") + data object Lit3Map : Route("lit3map") + data class Lit3Lesson(val id: Int) : Route("lit3unit$id") + data class Lit3Ex(val id: Int) : Route("lit3ex$id") + data object Lit4Map : Route("lit4map") + data class Lit4Lesson(val id: Int) : Route("lit4unit$id") + data class Lit4Ex(val id: Int) : Route("lit4ex$id") data object CzechMap : Route("czechmap") data object Mluvnice : Route("mluvnice") data class MluvEx(val n: Int) : Route("mluve$n") @@ -45,7 +58,9 @@ sealed class Route(val page: String) { val isExercise: Boolean get() = this is GermanEx || this is Vocab || this is NetEx || this is HwEx || this is OnEx || this is On2Ex || this is On3Ex || this is On4Ex || this is MluvEx || this is BookQuiz || this is BookPlot || - this is NetLesson || this is HwLesson || this is OnLesson || this is On2Lesson || this is On3Lesson || this is On4Lesson + this is NetLesson || this is HwLesson || this is OnLesson || this is On2Lesson || this is On3Lesson || this is On4Lesson || + this is LitLesson || this is LitEx || this is Lit2Lesson || this is Lit2Ex || + this is Lit3Lesson || this is Lit3Ex || this is Lit4Lesson || this is Lit4Ex /** Full stack from the practice root to this screen, so back always goes up one level. */ fun stack(): List = when (this) { @@ -77,6 +92,19 @@ sealed class Route(val page: String) { On4Map -> listOf(Subjects, OnYears, On4Map) is On4Lesson -> listOf(Subjects, OnYears, On4Map, this) is On4Ex -> listOf(Subjects, OnYears, On4Map, On4Lesson(id), this) + LitYears -> listOf(Subjects, CzechMap, LitYears) + LitMap -> listOf(Subjects, CzechMap, LitYears, LitMap) + is LitLesson -> listOf(Subjects, CzechMap, LitYears, LitMap, this) + is LitEx -> listOf(Subjects, CzechMap, LitYears, LitMap, LitLesson(id), this) + Lit2Map -> listOf(Subjects, CzechMap, LitYears, Lit2Map) + is Lit2Lesson -> listOf(Subjects, CzechMap, LitYears, Lit2Map, this) + is Lit2Ex -> listOf(Subjects, CzechMap, LitYears, Lit2Map, Lit2Lesson(id), this) + Lit3Map -> listOf(Subjects, CzechMap, LitYears, Lit3Map) + is Lit3Lesson -> listOf(Subjects, CzechMap, LitYears, Lit3Map, this) + is Lit3Ex -> listOf(Subjects, CzechMap, LitYears, Lit3Map, Lit3Lesson(id), this) + Lit4Map -> listOf(Subjects, CzechMap, LitYears, Lit4Map) + is Lit4Lesson -> listOf(Subjects, CzechMap, LitYears, Lit4Map, this) + is Lit4Ex -> listOf(Subjects, CzechMap, LitYears, Lit4Map, Lit4Lesson(id), this) CzechMap -> listOf(Subjects, CzechMap) Mluvnice -> listOf(Subjects, CzechMap, Mluvnice) is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this) @@ -102,6 +130,11 @@ fun routeFromPage(page: String): Route? = when (page) { "on2map" -> Route.On2Map "on3map" -> Route.On3Map "on4map" -> Route.On4Map + "lityears" -> Route.LitYears + "litmap" -> Route.LitMap + "lit2map" -> Route.Lit2Map + "lit3map" -> Route.Lit3Map + "lit4map" -> Route.Lit4Map "czechmap" -> Route.CzechMap "mluvnice" -> Route.Mluvnice "readinglist" -> Route.ReadingList @@ -133,6 +166,30 @@ fun routeFromPage(page: String): Route? = when (page) { Regex("""hwex(\d+)""").matchEntire(page)?.let { return Route.HwEx(it.groupValues[1].toInt()) } + Regex("""lit4unit(\d+)""").matchEntire(page)?.let { + return Route.Lit4Lesson(it.groupValues[1].toInt()) + } + Regex("""lit4ex(\d+)""").matchEntire(page)?.let { + return Route.Lit4Ex(it.groupValues[1].toInt()) + } + Regex("""lit3unit(\d+)""").matchEntire(page)?.let { + return Route.Lit3Lesson(it.groupValues[1].toInt()) + } + Regex("""lit3ex(\d+)""").matchEntire(page)?.let { + return Route.Lit3Ex(it.groupValues[1].toInt()) + } + Regex("""lit2unit(\d+)""").matchEntire(page)?.let { + return Route.Lit2Lesson(it.groupValues[1].toInt()) + } + Regex("""lit2ex(\d+)""").matchEntire(page)?.let { + return Route.Lit2Ex(it.groupValues[1].toInt()) + } + Regex("""litunit(\d+)""").matchEntire(page)?.let { + return Route.LitLesson(it.groupValues[1].toInt()) + } + Regex("""litex(\d+)""").matchEntire(page)?.let { + return Route.LitEx(it.groupValues[1].toInt()) + } Regex("""on4unit(\d+)""").matchEntire(page)?.let { return Route.On4Lesson(it.groupValues[1].toInt()) } diff --git a/android/app/src/main/java/org/maturita/maturita/data/Content.kt b/android/app/src/main/java/org/maturita/maturita/data/Content.kt index c44b3c2..0772f7e 100644 --- a/android/app/src/main/java/org/maturita/maturita/data/Content.kt +++ b/android/app/src/main/java/org/maturita/maturita/data/Content.kt @@ -33,6 +33,10 @@ class Content(root: JSONObject) { val on2 = raw.arr("on2") val on3 = raw.arr("on3") val on4 = raw.arr("on4") + val lit = raw.arr("lit") + val lit2 = raw.arr("lit2") + val lit3 = raw.arr("lit3") + val lit4 = raw.arr("lit4") val mluvnice = raw.arr("mluvnice") val books = raw.arr("books") val changelog = raw.arr("changelog") @@ -44,6 +48,10 @@ class Content(root: JSONObject) { fun on2Lesson(id: Int) = on2.firstOrNull { it.int("id") == id } fun on3Lesson(id: Int) = on3.firstOrNull { it.int("id") == id } fun on4Lesson(id: Int) = on4.firstOrNull { it.int("id") == id } + fun litLesson(id: Int) = lit.firstOrNull { it.int("id") == id } + fun lit2Lesson(id: Int) = lit2.firstOrNull { it.int("id") == id } + fun lit3Lesson(id: Int) = lit3.firstOrNull { it.int("id") == id } + fun lit4Lesson(id: Int) = lit4.firstOrNull { it.int("id") == id } fun mluv(n: Int) = mluvnice.firstOrNull { it.int("id") == n } fun book(id: String) = books.firstOrNull { it.str("id") == id } diff --git a/android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt b/android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt index 924ae6a..7ab7485 100644 --- a/android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt +++ b/android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt @@ -44,6 +44,15 @@ class ProgressStore(context: Context) { fun on4Done(id: Int) = prefs.getBoolean("on4.$id", false) fun markOn4(id: Int) { prefs.edit().putBoolean("on4.$id", true).apply() } + fun litDone(id: Int) = prefs.getBoolean("lit.$id", false) + fun markLit(id: Int) { prefs.edit().putBoolean("lit.$id", true).apply() } + fun lit2Done(id: Int) = prefs.getBoolean("lit2.$id", false) + fun markLit2(id: Int) { prefs.edit().putBoolean("lit2.$id", true).apply() } + fun lit3Done(id: Int) = prefs.getBoolean("lit3.$id", false) + fun markLit3(id: Int) { prefs.edit().putBoolean("lit3.$id", true).apply() } + fun lit4Done(id: Int) = prefs.getBoolean("lit4.$id", false) + fun markLit4(id: Int) { prefs.edit().putBoolean("lit4.$id", true).apply() } + fun mluvDone(n: Int) = prefs.getBoolean("mluv.$n", false) fun markMluv(n: Int) { prefs.edit().putBoolean("mluv.$n", true).apply() } @@ -114,6 +123,38 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum { sum.doneUnits += 1 } } + content.lit.forEach { l -> + sum.totalEx += 1 + sum.openUnits += 1 + if (p.litDone(l.int("id"))) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + content.lit2.forEach { l -> + sum.totalEx += 1 + sum.openUnits += 1 + if (p.lit2Done(l.int("id"))) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + content.lit3.forEach { l -> + sum.totalEx += 1 + sum.openUnits += 1 + if (p.lit3Done(l.int("id"))) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + content.lit4.forEach { l -> + sum.totalEx += 1 + sum.openUnits += 1 + if (p.lit4Done(l.int("id"))) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } sum.totalEx += content.mluvnice.size sum.openUnits += 1 val md = content.mluvnice.count { p.mluvDone(it.int("id")) } diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt b/android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt index 22ad84a..5b1db1b 100644 --- a/android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt +++ b/android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt @@ -146,6 +146,7 @@ private fun ChoiceEx(vm: AppViewModel, title: String, sub: String?, spec: J, onD if (revealed) { meanings.getOrNull(i)?.let { Meaning(vm.tr(it), true) } expls.getOrNull(i)?.let { Meaning(it, true) } + q.strOrNull("expl")?.let { Meaning(it, true) } } Spacer(Modifier.height(12.dp)) } @@ -848,6 +849,30 @@ fun NetQuizScreen(vm: AppViewModel, id: Int) { DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey"))) { vm.markNet(id) } } +@Composable +fun LitQuizScreen(vm: AppViewModel, year: Int, id: Int) { + val lesson = when (year) { + 2 -> vm.content.lit2Lesson(id) + 3 -> vm.content.lit3Lesson(id) + 4 -> vm.content.lit4Lesson(id) + else -> vm.content.litLesson(id) + } ?: return + val spec = J(org.json.JSONObject().apply { + put("type", "choice") + put("title", vm.tr(lesson.str("exTitleKey"))) + put("sub", lesson.str("quizHeadKey")) + put("questions", lesson.o.optJSONArray("quiz")) + }) + DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey"))) { + when (year) { + 2 -> vm.markLit2(id) + 3 -> vm.markLit3(id) + 4 -> vm.markLit4(id) + else -> vm.markLit(id) + } + } +} + @Composable fun OnQuizScreen(vm: AppViewModel, id: Int) { val lesson = vm.content.onLesson(id) ?: return diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Screens.kt b/android/app/src/main/java/org/maturita/maturita/ui/Screens.kt index 25b5206..a37e246 100644 --- a/android/app/src/main/java/org/maturita/maturita/ui/Screens.kt +++ b/android/app/src/main/java/org/maturita/maturita/ui/Screens.kt @@ -308,8 +308,13 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum { vm.content.on4.count { vm.progress.on4Done(it.int("id")) } } "czechmap" -> { - sum.totalEx = vm.content.mluvnice.size - sum.doneEx = vm.content.mluvnice.count { vm.progress.mluvDone(it.int("id")) } + val litDone = vm.content.lit.count { vm.progress.litDone(it.int("id")) } + + vm.content.lit2.count { vm.progress.lit2Done(it.int("id")) } + + vm.content.lit3.count { vm.progress.lit3Done(it.int("id")) } + + vm.content.lit4.count { vm.progress.lit4Done(it.int("id")) } + sum.totalEx = vm.content.mluvnice.size + vm.content.lit.size + vm.content.lit2.size + + vm.content.lit3.size + vm.content.lit4.size + sum.doneEx = vm.content.mluvnice.count { vm.progress.mluvDone(it.int("id")) } + litDone } } return sum @@ -514,6 +519,27 @@ private fun buildSearch(vm: AppViewModel): List { add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "on4unit${l.int("id")}", extra = "obcanka") add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "on4ex${l.int("id")}") } + add(vm.tr("Literatura"), vm.tr("search_lesson"), "lityears", extra = "literatura") + add(vm.tr("lit_year1"), vm.tr("search_lesson"), "litmap", extra = "rocnik") + add(vm.tr("lit_year2"), vm.tr("search_lesson"), "lit2map", extra = "rocnik") + add(vm.tr("lit_year3"), vm.tr("search_lesson"), "lit3map", extra = "rocnik") + add(vm.tr("lit_year4"), vm.tr("search_lesson"), "lit4map", extra = "rocnik") + vm.content.lit.forEach { l -> + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "litunit${l.int("id")}", extra = "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "litex${l.int("id")}") + } + vm.content.lit2.forEach { l -> + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit2unit${l.int("id")}", extra = "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit2ex${l.int("id")}") + } + vm.content.lit3.forEach { l -> + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit3unit${l.int("id")}", extra = "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit3ex${l.int("id")}") + } + vm.content.lit4.forEach { l -> + 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("Mluvnice"), vm.tr("search_lesson"), "mluvnice") vm.content.mluvnice.forEach { m -> add(m.str("name"), vm.tr("Mluvnice"), "mluve${m.int("id")}") } add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist") @@ -626,11 +652,27 @@ fun OnYearsScreen(vm: AppViewModel) { } } +@Composable +fun LitYearsScreen(vm: AppViewModel) { + DetailScaffold(vm, vm.tr("Literatura"), vm.tr("lit_years_sub")) { inner -> + LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) { + item { + NavRow(title = vm.tr("lit_year1"), subtitle = vm.tr("lit_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.LitMap) } + NavRow(title = vm.tr("lit_year2"), subtitle = vm.tr("lit2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit2Map) } + NavRow(title = vm.tr("lit_year3"), subtitle = vm.tr("lit3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit3Map) } + NavRow(title = vm.tr("lit_year4"), subtitle = vm.tr("lit4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit4Map) } + } + } + } +} + @Composable fun CzechMapScreen(vm: AppViewModel) { DetailScaffold(vm, vm.tr("Český jazyk a literatura"), vm.tr("czech_sub")) { inner -> LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) { - item { NavRow(title = vm.tr("Literatura"), locked = true, onClick = null) } + item { + NavRow(title = vm.tr("Literatura"), subtitle = vm.tr("lit_years_sub")) { vm.go(Route.LitYears) } + } item { NavRow( title = vm.tr("Mluvnice"), diff --git a/data/changelog.txt b/data/changelog.txt index 7aa382f..f9970d0 100644 --- a/data/changelog.txt +++ b/data/changelog.txt @@ -6,6 +6,12 @@ # cs: bullet # en: bullet +--- 2026-10-06 +cs: Český jazyk: literatura ve čtyřech ročnících podle osnov středních škol +cs: 32 lekcí od starověku po současnost, každá s výkladem a kvízem +en: Czech: literature across four years, following the secondary-school syllabus +en: 32 lessons from antiquity to the present, each with an overview and a quiz + --- 2026-10-03 cs: Občanská nauka: 4. ročník, 16 lekcí (hospodářství, svět a filozofie) en: Civics: year 4, 16 lessons (the economy, the world and philosophy) diff --git a/ios/Graduately/AppModel.swift b/ios/Graduately/AppModel.swift index d78c076..1bae8c9 100644 --- a/ios/Graduately/AppModel.swift +++ b/ios/Graduately/AppModel.swift @@ -148,6 +148,26 @@ final class AppModel: ObservableObject { refresh() } + func markLit(_ id: Int) { + progress.markLit(id) + refresh() + } + + func markLit2(_ id: Int) { + progress.markLit2(id) + refresh() + } + + func markLit3(_ id: Int) { + progress.markLit3(id) + refresh() + } + + func markLit4(_ id: Int) { + progress.markLit4(id) + refresh() + } + func markMluv(_ n: Int) { progress.markMluv(n) refresh() diff --git a/ios/Graduately/Data/Content.swift b/ios/Graduately/Data/Content.swift index c7899fc..8f93c38 100644 --- a/ios/Graduately/Data/Content.swift +++ b/ios/Graduately/Data/Content.swift @@ -35,6 +35,10 @@ final class Content { let on2: [J] let on3: [J] let on4: [J] + let lit: [J] + let lit2: [J] + let lit3: [J] + let lit4: [J] let mluvnice: [J] let books: [J] let changelog: [J] @@ -70,6 +74,10 @@ final class Content { on2 = raw.arr("on2") on3 = raw.arr("on3") on4 = raw.arr("on4") + lit = raw.arr("lit") + lit2 = raw.arr("lit2") + lit3 = raw.arr("lit3") + lit4 = raw.arr("lit4") mluvnice = raw.arr("mluvnice") books = raw.arr("books") changelog = raw.arr("changelog") @@ -82,6 +90,10 @@ final class Content { func on2Lesson(_ id: Int) -> J? { on2.first { $0.int("id") == id } } func on3Lesson(_ id: Int) -> J? { on3.first { $0.int("id") == id } } func on4Lesson(_ id: Int) -> J? { on4.first { $0.int("id") == id } } + func litLesson(_ id: Int) -> J? { lit.first { $0.int("id") == id } } + 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 mluv(_ n: Int) -> J? { mluvnice.first { $0.int("id") == n } } func book(_ id: String) -> J? { books.first { $0.str("id") == id } } diff --git a/ios/Graduately/Data/ProgressStore.swift b/ios/Graduately/Data/ProgressStore.swift index c7b6bef..d84eec7 100644 --- a/ios/Graduately/Data/ProgressStore.swift +++ b/ios/Graduately/Data/ProgressStore.swift @@ -46,6 +46,15 @@ final class ProgressStore { func on4Done(_ id: Int) -> Bool { defaults.bool(forKey: "on4.\(id)") } func markOn4(_ id: Int) { defaults.set(true, forKey: "on4.\(id)") } + func litDone(_ id: Int) -> Bool { defaults.bool(forKey: "lit.\(id)") } + func markLit(_ id: Int) { defaults.set(true, forKey: "lit.\(id)") } + func lit2Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit2.\(id)") } + func markLit2(_ id: Int) { defaults.set(true, forKey: "lit2.\(id)") } + func lit3Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit3.\(id)") } + func markLit3(_ id: Int) { defaults.set(true, forKey: "lit3.\(id)") } + func lit4Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit4.\(id)") } + func markLit4(_ id: Int) { defaults.set(true, forKey: "lit4.\(id)") } + func mluvDone(_ n: Int) -> Bool { defaults.bool(forKey: "mluv.\(n)") } func markMluv(_ n: Int) { defaults.set(true, forKey: "mluv.\(n)") } @@ -121,6 +130,38 @@ func summarize(_ content: Content, _ p: ProgressStore) -> ProgressSum { sum.doneUnits += 1 } } + for l in content.lit { + sum.totalEx += 1 + sum.openUnits += 1 + if p.litDone(l.int("id")) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + for l in content.lit2 { + sum.totalEx += 1 + sum.openUnits += 1 + if p.lit2Done(l.int("id")) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + for l in content.lit3 { + sum.totalEx += 1 + sum.openUnits += 1 + if p.lit3Done(l.int("id")) { + sum.doneEx += 1 + sum.doneUnits += 1 + } + } + for l in content.lit4 { + sum.totalEx += 1 + sum.openUnits += 1 + if p.lit4Done(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 diff --git a/ios/Graduately/Route.swift b/ios/Graduately/Route.swift index e303ad5..607f529 100644 --- a/ios/Graduately/Route.swift +++ b/ios/Graduately/Route.swift @@ -36,6 +36,19 @@ enum Route: Hashable { case on4Map case on4Lesson(Int) case on4Ex(Int) + case litYears + case litMap + case litLesson(Int) + case litEx(Int) + case lit2Map + case lit2Lesson(Int) + case lit2Ex(Int) + case lit3Map + case lit3Lesson(Int) + case lit3Ex(Int) + case lit4Map + case lit4Lesson(Int) + case lit4Ex(Int) case czechMap case mluvnice case mluvEx(Int) @@ -74,6 +87,19 @@ enum Route: Hashable { case .on4Map: return "on4map" case .on4Lesson(let id): return "on4unit\(id)" case .on4Ex(let id): return "on4ex\(id)" + case .litYears: return "lityears" + case .litMap: return "litmap" + case .litLesson(let id): return "litunit\(id)" + case .litEx(let id): return "litex\(id)" + case .lit2Map: return "lit2map" + case .lit2Lesson(let id): return "lit2unit\(id)" + case .lit2Ex(let id): return "lit2ex\(id)" + case .lit3Map: return "lit3map" + case .lit3Lesson(let id): return "lit3unit\(id)" + case .lit3Ex(let id): return "lit3ex\(id)" + case .lit4Map: return "lit4map" + case .lit4Lesson(let id): return "lit4unit\(id)" + case .lit4Ex(let id): return "lit4ex\(id)" case .czechMap: return "czechmap" case .mluvnice: return "mluvnice" case .mluvEx(let n): return "mluve\(n)" @@ -148,6 +174,32 @@ enum Route: Hashable { return [.onYears, .on4Map, .on4Lesson(id)] case .on4Ex(let id): return [.onYears, .on4Map, .on4Lesson(id), .on4Ex(id)] + case .litYears: + return [.czechMap, .litYears] + case .litMap: + return [.czechMap, .litYears, .litMap] + case .litLesson(let id): + return [.czechMap, .litYears, .litMap, .litLesson(id)] + case .litEx(let id): + return [.czechMap, .litYears, .litMap, .litLesson(id), .litEx(id)] + case .lit2Map: + return [.czechMap, .litYears, .lit2Map] + case .lit2Lesson(let id): + return [.czechMap, .litYears, .lit2Map, .lit2Lesson(id)] + case .lit2Ex(let id): + return [.czechMap, .litYears, .lit2Map, .lit2Lesson(id), .lit2Ex(id)] + case .lit3Map: + return [.czechMap, .litYears, .lit3Map] + case .lit3Lesson(let id): + return [.czechMap, .litYears, .lit3Map, .lit3Lesson(id)] + case .lit3Ex(let id): + return [.czechMap, .litYears, .lit3Map, .lit3Lesson(id), .lit3Ex(id)] + case .lit4Map: + return [.czechMap, .litYears, .lit4Map] + case .lit4Lesson(let id): + return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id)] + case .lit4Ex(let id): + return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id), .lit4Ex(id)] case .czechMap: return [.czechMap] case .mluvnice: @@ -181,6 +233,11 @@ func routeFromPage(_ page: String) -> Route? { case "on2map": return .on2Map case "on3map": return .on3Map case "on4map": return .on4Map + case "lityears": return .litYears + case "litmap": return .litMap + case "lit2map": return .lit2Map + case "lit3map": return .lit3Map + case "lit4map": return .lit4Map case "czechmap": return .czechMap case "mluvnice": return .mluvnice case "readinglist": return .readingList @@ -224,6 +281,30 @@ 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: /lit4unit(\d+)/), let n = Int(m.1) { + return .lit4Lesson(n) + } + if let m = page.wholeMatch(of: /lit4ex(\d+)/), let n = Int(m.1) { + return .lit4Ex(n) + } + if let m = page.wholeMatch(of: /lit3unit(\d+)/), let n = Int(m.1) { + return .lit3Lesson(n) + } + if let m = page.wholeMatch(of: /lit3ex(\d+)/), let n = Int(m.1) { + return .lit3Ex(n) + } + if let m = page.wholeMatch(of: /lit2unit(\d+)/), let n = Int(m.1) { + return .lit2Lesson(n) + } + if let m = page.wholeMatch(of: /lit2ex(\d+)/), let n = Int(m.1) { + return .lit2Ex(n) + } + if let m = page.wholeMatch(of: /litunit(\d+)/), let n = Int(m.1) { + return .litLesson(n) + } + if let m = page.wholeMatch(of: /litex(\d+)/), let n = Int(m.1) { + return .litEx(n) + } if let m = page.wholeMatch(of: /on4unit(\d+)/), let n = Int(m.1) { return .on4Lesson(n) } diff --git a/ios/Graduately/UI/Exercises.swift b/ios/Graduately/UI/Exercises.swift index 4152463..11b2d80 100644 --- a/ios/Graduately/UI/Exercises.swift +++ b/ios/Graduately/UI/Exercises.swift @@ -149,6 +149,9 @@ private struct ChoiceEx: View { if revealed { if i < meanings.count { Meaning(text: vm.tr(meanings[i]), palette: p, visible: true) } if i < expls.count { Meaning(text: expls[i], palette: p, visible: true) } + if let expl = qs[i].strOrNull("expl") { + Meaning(text: expl, palette: p, visible: true) + } } Spacer().frame(height: 10) } diff --git a/ios/Graduately/UI/ExercisesMore.swift b/ios/Graduately/UI/ExercisesMore.swift index c41831d..a33db07 100644 --- a/ios/Graduately/UI/ExercisesMore.swift +++ b/ios/Graduately/UI/ExercisesMore.swift @@ -625,6 +625,39 @@ struct NetQuizScreen: View { } } +struct LitYearQuizScreen: View { + @ObservedObject var vm: AppModel + let year: Int + let id: Int + + var body: some View { + let lesson: J? = { + switch year { + case 2: return vm.content.lit2Lesson(id) + case 3: return vm.content.lit3Lesson(id) + case 4: return vm.content.lit4Lesson(id) + default: return vm.content.litLesson(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"))) { + switch year { + case 2: vm.markLit2(id) + case 3: vm.markLit3(id) + case 4: vm.markLit4(id) + default: vm.markLit(id) + } + } + } + } +} + struct OnQuizScreen: View { @ObservedObject var vm: AppModel let id: Int diff --git a/ios/Graduately/UI/Screens.swift b/ios/Graduately/UI/Screens.swift index 431c20d..c1c064b 100644 --- a/ios/Graduately/UI/Screens.swift +++ b/ios/Graduately/UI/Screens.swift @@ -696,8 +696,13 @@ private func subjectSum(_ vm: AppModel, _ s: J) -> ProgressSum { + vm.content.on3.filter { vm.progress.on3Done($0.int("id")) }.count + vm.content.on4.filter { vm.progress.on4Done($0.int("id")) }.count case "czechmap": - sum.totalEx = vm.content.mluvnice.count - sum.doneEx = vm.content.mluvnice.filter { vm.progress.mluvDone($0.int("id")) }.count + 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 + + vm.content.lit2.filter { vm.progress.lit2Done($0.int("id")) }.count + + vm.content.lit3.filter { vm.progress.lit3Done($0.int("id")) }.count + + vm.content.lit4.filter { vm.progress.lit4Done($0.int("id")) }.count + sum.totalEx = vm.content.mluvnice.count + litCount + sum.doneEx = vm.content.mluvnice.filter { vm.progress.mluvDone($0.int("id")) }.count + litDone default: break } @@ -899,6 +904,27 @@ private func buildSearch(_ vm: AppModel) -> [Hit] { add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "on4unit\(l.int("id"))", extra: "obcanka") add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "on4ex\(l.int("id"))") } + add(vm.tr("Literatura"), vm.tr("search_lesson"), "lityears", extra: "literatura") + add(vm.tr("lit_year1"), vm.tr("search_lesson"), "litmap", extra: "rocnik") + add(vm.tr("lit_year2"), vm.tr("search_lesson"), "lit2map", extra: "rocnik") + add(vm.tr("lit_year3"), vm.tr("search_lesson"), "lit3map", extra: "rocnik") + add(vm.tr("lit_year4"), vm.tr("search_lesson"), "lit4map", extra: "rocnik") + for l in vm.content.lit { + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "litunit\(l.int("id"))", extra: "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "litex\(l.int("id"))") + } + for l in vm.content.lit2 { + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit2unit\(l.int("id"))", extra: "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit2ex\(l.int("id"))") + } + for l in vm.content.lit3 { + add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit3unit\(l.int("id"))", extra: "literatura") + add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit3ex\(l.int("id"))") + } + for l in vm.content.lit4 { + 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("Mluvnice"), vm.tr("search_lesson"), "mluvnice") add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist") for b in vm.content.books { @@ -1404,6 +1430,47 @@ struct SlidesScreen: View { } } +struct LitYearsScreen: View { + @ObservedObject var vm: AppModel + + var body: some View { + #if os(macOS) + let years: [(String, String, Route)] = [ + ("lit_year1", "lit_sub", .litMap), + ("lit_year2", "lit2_sub", .lit2Map), + ("lit_year3", "lit3_sub", .lit3Map), + ("lit_year4", "lit4_sub", .lit4Map), + ] + MacFillGrid(count: years.count, minWidth: 260, minHeight: 180) { i in + NavigationLink(value: years[i].2) { + MacLinkCard(title: vm.tr(years[i].0), subtitle: vm.tr(years[i].1), badge: "\(i + 1).") + } + .buttonStyle(.plain) + } + .navigationTitle(vm.tr("Literatura")) + .navigationSubtitle(vm.tr("lit_years_sub")) + #else + List { + NavigationLink(value: Route.litMap) { + ListRowLabel(title: vm.tr("lit_year1"), subtitle: vm.tr("lit_sub")) + } + NavigationLink(value: Route.lit2Map) { + ListRowLabel(title: vm.tr("lit_year2"), subtitle: vm.tr("lit2_sub")) + } + NavigationLink(value: Route.lit3Map) { + ListRowLabel(title: vm.tr("lit_year3"), subtitle: vm.tr("lit3_sub")) + } + NavigationLink(value: Route.lit4Map) { + ListRowLabel(title: vm.tr("lit_year4"), subtitle: vm.tr("lit4_sub")) + } + } + .navigationTitle(vm.tr("Literatura")) + .navigationSubtitle(vm.tr("lit_years_sub")) + .appListStyle() + #endif + } +} + struct CzechMapScreen: View { @ObservedObject var vm: AppModel @@ -1422,19 +1489,23 @@ struct CzechMapScreen: View { } .buttonStyle(.plain) default: - MacLinkCard(title: vm.tr("Literatura"), systemImage: "book.closed", locked: true) + NavigationLink(value: Route.litYears) { + MacLinkCard(title: vm.tr("Literatura"), systemImage: "book.closed") + } + .buttonStyle(.plain) } } .navigationTitle(vm.tr("Český jazyk a literatura")) .navigationSubtitle(vm.tr("czech_sub")) #else List { - Label { - Text(vm.tr("Literatura")) - } icon: { - Image(systemName: "lock.fill") + NavigationLink(value: Route.litYears) { + Label { + Text(vm.tr("Literatura")) + } icon: { + Image(systemName: "book.closed") + } } - .foregroundStyle(.secondary) NavigationLink(value: Route.mluvnice) { Label { Text(vm.tr("Mluvnice")) @@ -1994,6 +2065,92 @@ struct RouteDestination: View { On4QuizScreen(vm: vm, id: id) case .czechMap: CzechMapScreen(vm: vm) + case .litYears: + LitYearsScreen(vm: vm) + case .litMap: + LessonListScreen( + vm: vm, + title: vm.tr("lit_year1"), + subtitle: vm.tr("lit_sub"), + rows: vm.content.lit.map { l in + let id = l.int("id") + return LessonRow( + id: "l\(id)", + title: vm.tr(l.str("titleKey")), + done: vm.progress.litDone(id), + destination: .litLesson(id) + ) + } + ) + case .litLesson(let id): + if let l = vm.content.litLesson(id) { + SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .litEx(id)) + } + case .litEx(let id): + LitYearQuizScreen(vm: vm, year: 1, id: id) + case .lit2Map: + LessonListScreen( + vm: vm, + title: vm.tr("lit_year2"), + subtitle: vm.tr("lit2_sub"), + rows: vm.content.lit2.map { l in + let id = l.int("id") + return LessonRow( + id: "l2\(id)", + title: vm.tr(l.str("titleKey")), + done: vm.progress.lit2Done(id), + destination: .lit2Lesson(id) + ) + } + ) + case .lit2Lesson(let id): + if let l = vm.content.lit2Lesson(id) { + SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .lit2Ex(id)) + } + case .lit2Ex(let id): + LitYearQuizScreen(vm: vm, year: 2, id: id) + case .lit3Map: + LessonListScreen( + vm: vm, + title: vm.tr("lit_year3"), + subtitle: vm.tr("lit3_sub"), + rows: vm.content.lit3.map { l in + let id = l.int("id") + return LessonRow( + id: "l3\(id)", + title: vm.tr(l.str("titleKey")), + done: vm.progress.lit3Done(id), + destination: .lit3Lesson(id) + ) + } + ) + case .lit3Lesson(let id): + if let l = vm.content.lit3Lesson(id) { + SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .lit3Ex(id)) + } + case .lit3Ex(let id): + LitYearQuizScreen(vm: vm, year: 3, id: id) + case .lit4Map: + LessonListScreen( + vm: vm, + title: vm.tr("lit_year4"), + subtitle: vm.tr("lit4_sub"), + rows: vm.content.lit4.map { l in + let id = l.int("id") + return LessonRow( + id: "l4\(id)", + title: vm.tr(l.str("titleKey")), + done: vm.progress.lit4Done(id), + destination: .lit4Lesson(id) + ) + } + ) + case .lit4Lesson(let id): + if let l = vm.content.lit4Lesson(id) { + SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .lit4Ex(id)) + } + case .lit4Ex(let id): + LitYearQuizScreen(vm: vm, year: 4, id: id) case .mluvnice: LessonListScreen( vm: vm, diff --git a/scripts/extract-android-content.py b/scripts/extract-android-content.py index 02711da..9a111d9 100644 --- a/scripts/extract-android-content.py +++ b/scripts/extract-android-content.py @@ -291,8 +291,8 @@ def find_arrays(src: str) -> dict[str, tuple[str, list]]: val, _ = parse_list(toks, 0) fn = func_at(pos_brace) key = f"{fn}.{name}" if fn and name in { - "slides", "qs", "about", "world", "people", "terms", "persons", - "nouns", "ans", + "slides", "qs", "hints", "about", "world", "people", "terms", + "persons", "nouns", "ans", } else name # Prefer the first global, overwrite locals with prefixed names. if key in found and not key.startswith(fn or "\0"): @@ -1084,6 +1084,32 @@ def main() -> int: "quiz": qs, }) + def lit_pack(prefix): + lessons = [] + for i in range(1, 9): + fn_u = f"build_{prefix}_unit{i}_page" + fn_e = f"build_{prefix}_unit{i}_exercise_page" + quiz = choice_items(A(f"{fn_e}.qs")) + hints = str_list(A(f"{fn_e}.hints")) if f"{fn_e}.hints" in arrays else [] + for qi, q in enumerate(quiz): + if qi < len(hints) and hints[qi]: + q["expl"] = hints[qi] + lessons.append({ + "id": i, + "titleKey": f"{prefix}_unit{i}", + "subKey": f"{prefix}_unit{i}_sub", + "exTitleKey": f"{prefix}_ex{i}_title", + "quizHeadKey": f"{prefix}_quiz{i}_head", + "slides": slides_items(A(f"{fn_u}.slides")), + "quiz": quiz, + }) + return lessons + + lit_lessons = lit_pack("lit") + lit2_lessons = lit_pack("lit2") + lit3_lessons = lit_pack("lit3") + lit4_lessons = lit_pack("lit4") + on_lessons = [] for i in range(1, 18): on_lessons.append({ @@ -1551,6 +1577,10 @@ def main() -> int: }, "hw": hw_lessons, "on": on_lessons, + "lit": lit_lessons, + "lit2": lit2_lessons, + "lit3": lit3_lessons, + "lit4": lit4_lessons, "on2": on2_lessons, "on3": on3_lessons, "on4": on4_lessons, @@ -1589,6 +1619,7 @@ def main() -> int: print(f" net quizzes: {sum(1 for L in net_lessons if L['quiz'])}") print(f" hw lessons: {sum(1 for L in hw_lessons if L['slides'])}") print(f" on lessons: {sum(1 for L in on_lessons if L['slides'])}") + print(f" lit lessons: {sum(1 for L in lit_lessons + lit2_lessons + lit3_lessons + lit4_lessons if L['slides'])}") print(f" on2 lessons: {sum(1 for L in on2_lessons if L['slides'])}") print(f" on3 lessons: {sum(1 for L in on3_lessons if L['slides'])}") print(f" on4 lessons: {sum(1 for L in on4_lessons if L['slides'])}") @@ -1645,6 +1676,17 @@ def main() -> int: missing.append(f"on4{L['id']} slides") if not L["quiz"]: missing.append(f"on4{L['id']} quiz") + for label, block in ( + ("lit", lit_lessons), ("lit2", lit2_lessons), + ("lit3", lit3_lessons), ("lit4", lit4_lessons), + ): + for L in block: + if not L["slides"]: + missing.append(f"{label}{L['id']} slides") + if len(L["quiz"]) < 4: + missing.append(f"{label}{L['id']} quiz") + if not all(q.get("expl") for q in L["quiz"]): + missing.append(f"{label}{L['id']} expl") for m in mluvnice: if m["type"] in ("typed", "reveal") and not m.get("items"): missing.append(f"mluv{m['id']}") diff --git a/src/czech.c b/src/czech.c index 59507bb..49991f8 100644 --- a/src/czech.c +++ b/src/czech.c @@ -134,20 +134,15 @@ GtkWidget *build_czechmap_page(void) { cz_rail = rail; for (int i = 0; i < CZ_NODES; i++) { - /* Literatura has no lessons yet; keep the node visible but locked. */ - gboolean locked = (i == 0); - GtkWidget *btn = cz_make_node(i, locked); + GtkWidget *btn = cz_make_node(i, FALSE); GtkWidget *name = gtk_label_new(NULL); + const char *target = (i == 0) ? "lityears" + : (i == 1) ? "mluvnice" + : "readinglist"; - if (i == 2) { - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup("readinglist"), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } else if (i == 1) { - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup("mluvnice"), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } + g_object_set_data_full(G_OBJECT(btn), "target", + g_strdup(target), g_free); + g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); i18n_bind(name, cz_keys[i], 0); gtk_widget_set_size_request(name, (int)CZ_LABEL_W, -1); @@ -156,8 +151,6 @@ GtkWidget *build_czechmap_page(void) { gtk_label_set_wrap(GTK_LABEL(name), TRUE); gtk_widget_add_css_class(name, "unit-name"); gtk_widget_add_css_class(name, "cz-label"); - if (locked) - gtk_widget_add_css_class(name, "unit-name-locked"); gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0); diff --git a/src/graduately.h b/src/graduately.h index 1b3f08b..264e614 100644 --- a/src/graduately.h +++ b/src/graduately.h @@ -55,6 +55,10 @@ extern char *app_progress_on3; extern char *app_progress_on4; extern char *app_progress_mluvnice; extern char *app_progress_cetba; +extern char *app_progress_lit; +extern char *app_progress_lit2; +extern char *app_progress_lit3; +extern char *app_progress_lit4; #define PROGRESS_DIR app_progress_dir #define PROGRESS_U1 app_progress_u1 #define PROGRESS_U2 app_progress_u2 @@ -131,6 +135,7 @@ extern char *app_progress_cetba; #define ON3_LESSONS 16 #define ON4_UNITS 16 #define ON4_LESSONS 16 +#define LIT_N 8 #define HW_SLIDES 3 #define HW2_SLIDES 6 #define HW3_SLIDES 2 @@ -901,6 +906,29 @@ void on4_lessons_apply_lang(void); GtkWidget *build_on4map_page(void); void add_on4_pages(GtkStack *stack); void czech_rail_theme_reset(void); +void lit_load_progress(void); +void lit_rail_theme_reset(void); +void lit_lessons_apply_lang(void); +void progress_for_lit(ProgressSum *out); +GtkWidget *lit_unit_page(int year, NetLesson *L, const char *title_key, + const char *sub_key, const NetSlide *slides, + guint n_slides); +GtkWidget *lit_mcq_page(int year, int lesson_id, const char *back_page, + const char *title_key, const char *heading_key, + const ChoiceQ *qs, const char **hints, int n); +GtkWidget *build_lityears_page(void); +GtkWidget *build_litmap_page(void); +GtkWidget *build_lit2map_page(void); +GtkWidget *build_lit3map_page(void); +GtkWidget *build_lit4map_page(void); +void add_lit_pages(GtkStack *stack); +void add_lit2_pages(GtkStack *stack); +void add_lit3_pages(GtkStack *stack); +void add_lit4_pages(GtkStack *stack); +extern NetLesson lit_lessons[LIT_N]; +extern NetLesson lit2_lessons[LIT_N]; +extern NetLesson lit3_lessons[LIT_N]; +extern NetLesson lit4_lessons[LIT_N]; void hw_lessons_apply_lang(void); GtkWidget *build_hwyears_page(void); GtkWidget *build_hwmap_page(void); diff --git a/src/i18n.c b/src/i18n.c index 412d672..117a2c4 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -1098,6 +1098,212 @@ const TrEntry tr_ui[] = { {"on4_ex16_title", "Kvíz: hodnoty", "Quiz: values"}, {"on4_quiz16_head", "Kvíz k hodnotám", "Quiz on values"}, + {"lit_years_sub", "Literatura podle osnov středních škol. Vyberte ročník.", + "Literature from the secondary-school syllabus. Pick a year."}, + {"lit_year1", "1. ročník", "Year 1"}, + {"lit_year2", "2. ročník", "Year 2"}, + {"lit_year3", "3. ročník", "Year 3"}, + {"lit_year4", "4. ročník", "Year 4"}, + {"lit_sub", "Od literární teorie po osvícenství.", + "From literary theory to the Enlightenment."}, + {"lit2_sub", "Od národního obrození k moderně.", + "From the National Revival to the modern movement."}, + {"lit3_sub", "První polovina 20. století.", + "The first half of the 20th century."}, + {"lit4_sub", "Od roku 1945 k interpretaci textu.", + "From 1945 to reading a text."}, + {"lit_unit1", "Základy literární teorie", "Basics of literary theory"}, + {"lit_unit1_sub", "Druhy, žánry, verš a obrazná pojmenování.", + "Genres, verse and figurative language."}, + {"lit_ex1_title", "Kvíz: literární teorie", "Quiz: literary theory"}, + {"lit_quiz1_head", "Ověřte si základy literární teorie", + "Check the basics of literary theory"}, + {"lit_unit2", "Starověké literatury", "Ancient literatures"}, + {"lit_unit2_sub", "Orient a Bible jako pramen evropské kultury.", + "The ancient East and the Bible."}, + {"lit_ex2_title", "Kvíz: starověk", "Quiz: antiquity"}, + {"lit_quiz2_head", "Ověřte si starověké literatury", + "Check the ancient literatures"}, + {"lit_unit3", "Antická literatura", "Classical literature"}, + {"lit_unit3_sub", "Řecký epos a drama, římská klasika.", + "Greek epic and drama, Roman classics."}, + {"lit_ex3_title", "Kvíz: antika", "Quiz: classical antiquity"}, + {"lit_quiz3_head", "Ověřte si antickou literaturu", + "Check classical literature"}, + {"lit_unit4", "Středověká literatura", "Medieval literature"}, + {"lit_unit4_sub", "Hrdinská epika, rytířská tvorba a Dante.", + "Heroic epic, courtly literature and Dante."}, + {"lit_ex4_title", "Kvíz: středověk", "Quiz: the Middle Ages"}, + {"lit_quiz4_head", "Ověřte si středověkou literaturu", + "Check medieval literature"}, + {"lit_unit5", "Česká literatura do husitství", "Early Czech literature"}, + {"lit_unit5_sub", "Staroslověnština, latina, čeština a husitství.", + "Old Church Slavonic, Latin, Czech and the Hussites."}, + {"lit_ex5_title", "Kvíz: počátky české literatury", + "Quiz: early Czech literature"}, + {"lit_quiz5_head", "Ověřte si literaturu do husitství", + "Check early Czech literature"}, + {"lit_unit6", "Humanismus a renesance", "Humanism and the Renaissance"}, + {"lit_unit6_sub", "Od Petrarky a Shakespeara k Bibli kralické.", + "From Petrarch and Shakespeare to the Kralice Bible."}, + {"lit_ex6_title", "Kvíz: renesance", "Quiz: the Renaissance"}, + {"lit_quiz6_head", "Ověřte si humanismus a renesanci", + "Check humanism and the Renaissance"}, + {"lit_unit7", "Baroko", "The Baroque"}, + {"lit_unit7_sub", "Kontrast, Bridel a Komenský.", + "Contrast, Bridel and Comenius."}, + {"lit_ex7_title", "Kvíz: baroko", "Quiz: the Baroque"}, + {"lit_quiz7_head", "Ověřte si barokní literaturu", + "Check Baroque literature"}, + {"lit_unit8", "Klasicismus a osvícenství", "Classicism and the Enlightenment"}, + {"lit_unit8_sub", "Pravidlo, rozum a preromantický cit.", + "Rules, reason and pre-Romantic feeling."}, + {"lit_ex8_title", "Kvíz: klasicismus", "Quiz: Classicism"}, + {"lit_quiz8_head", "Ověřte si klasicismus a osvícenství", + "Check Classicism and the Enlightenment"}, + {"lit2_unit1", "Národní obrození", "The Czech National Revival"}, + {"lit2_unit1_sub", "Obrana češtiny a Jungmannova generace.", + "Defending Czech and Jungmann's generation."}, + {"lit2_ex1_title", "Kvíz: národní obrození", "Quiz: the National Revival"}, + {"lit2_quiz1_head", "Ověřte si národní obrození", + "Check the National Revival"}, + {"lit2_unit2", "Světový romantismus", "Romanticism abroad"}, + {"lit2_unit2_sub", "Byron, Hugo, Puškin a Poe.", + "Byron, Hugo, Pushkin and Poe."}, + {"lit2_ex2_title", "Kvíz: světový romantismus", "Quiz: Romanticism abroad"}, + {"lit2_quiz2_head", "Ověřte si světový romantismus", + "Check Romanticism abroad"}, + {"lit2_unit3", "Český romantismus", "Czech Romanticism"}, + {"lit2_unit3_sub", "Mácha, Erben, Tyl, Němcová a Havlíček.", + "Mácha, Erben, Tyl, Němcová and Havlíček."}, + {"lit2_ex3_title", "Kvíz: český romantismus", "Quiz: Czech Romanticism"}, + {"lit2_quiz3_head", "Ověřte si český romantismus", + "Check Czech Romanticism"}, + {"lit2_unit4", "Realismus a naturalismus", "Realism and naturalism"}, + {"lit2_unit4_sub", "Balzac, Flaubert, Dickens, Tolstoj a Dostojevskij.", + "Balzac, Flaubert, Dickens, Tolstoy and Dostoevsky."}, + {"lit2_ex4_title", "Kvíz: realismus", "Quiz: realism"}, + {"lit2_quiz4_head", "Ověřte si realismus a naturalismus", + "Check realism and naturalism"}, + {"lit2_unit5", "Májovci", "The Máj generation"}, + {"lit2_unit5_sub", "Almanach Máj, Neruda, Hálek a Světlá.", + "The Máj almanac, Neruda, Hálek and Světlá."}, + {"lit2_ex5_title", "Kvíz: májovci", "Quiz: the Máj generation"}, + {"lit2_quiz5_head", "Ověřte si májovce", "Check the Máj generation"}, + {"lit2_unit6", "Ruchovci a lumírovci", "Ruchovci and lumírovci"}, + {"lit2_unit6_sub", "Čech, Vrchlický, Sládek a Zeyer.", + "Čech, Vrchlický, Sládek and Zeyer."}, + {"lit2_ex6_title", "Kvíz: ruchovci a lumírovci", "Quiz: ruchovci and lumírovci"}, + {"lit2_quiz6_head", "Ověřte si ruchovce a lumírovce", + "Check ruchovci and lumírovci"}, + {"lit2_unit7", "Česká próza 19. století", "Czech prose of the 19th century"}, + {"lit2_unit7_sub", "Rais, Jirásek a Maryša.", + "Rais, Jirásek and Maryša."}, + {"lit2_ex7_title", "Kvíz: český realismus", "Quiz: Czech realism"}, + {"lit2_quiz7_head", "Ověřte si českou prózu 19. století", + "Check Czech prose of the 19th century"}, + {"lit2_unit8", "Moderna a buřiči", "The modern movement and the rebels"}, + {"lit2_unit8_sub", "Baudelaire, česká moderna, Šrámek a Bezruč.", + "Baudelaire, the Czech modern movement, Šrámek and Bezruč."}, + {"lit2_ex8_title", "Kvíz: moderna", "Quiz: the modern movement"}, + {"lit2_quiz8_head", "Ověřte si modernu a buřiče", + "Check the modern movement and the rebels"}, + {"lit3_unit1", "Světová avantgarda", "The world avant-garde"}, + {"lit3_unit1_sub", "Futurismus, surrealismus a Apollinaire.", + "Futurism, surrealism and Apollinaire."}, + {"lit3_ex1_title", "Kvíz: avantgarda", "Quiz: the avant-garde"}, + {"lit3_quiz1_head", "Ověřte si světovou avantgardu", + "Check the world avant-garde"}, + {"lit3_unit2", "Světová próza mezi válkami", "World prose between the wars"}, + {"lit3_unit2_sub", "Ztracená generace, Kafka a experiment.", + "The Lost Generation, Kafka and experiment."}, + {"lit3_ex2_title", "Kvíz: meziválečná próza", "Quiz: interwar prose"}, + {"lit3_quiz2_head", "Ověřte si světovou prózu mezi válkami", + "Check world prose between the wars"}, + {"lit3_unit3", "Světové drama do roku 1945", "World drama to 1945"}, + {"lit3_unit3_sub", "Shaw, Pirandello a Brecht.", + "Shaw, Pirandello and Brecht."}, + {"lit3_ex3_title", "Kvíz: světové drama", "Quiz: world drama"}, + {"lit3_quiz3_head", "Ověřte si drama první poloviny století", + "Check drama of the early 20th century"}, + {"lit3_unit4", "První válka v české literatuře", "The First World War in Czech literature"}, + {"lit3_unit4_sub", "Hašek, legie a Wolker.", + "Hašek, the legions and Wolker."}, + {"lit3_ex4_title", "Kvíz: první válka", "Quiz: the First World War"}, + {"lit3_quiz4_head", "Ověřte si literaturu první války", + "Check literature of the First World War"}, + {"lit3_unit5", "Česká poezie mezi válkami", "Czech poetry between the wars"}, + {"lit3_unit5_sub", "Poetismus, surrealismus, Halas a Holan.", + "Poetism, surrealism, Halas and Holan."}, + {"lit3_ex5_title", "Kvíz: meziválečná poezie", "Quiz: interwar poetry"}, + {"lit3_quiz5_head", "Ověřte si českou poezii 1918–1938", + "Check Czech poetry of 1918–1938"}, + {"lit3_unit6", "Demokratický proud", "The democratic current"}, + {"lit3_unit6_sub", "Čapek, Vančura, Poláček a Olbracht.", + "Čapek, Vančura, Poláček and Olbracht."}, + {"lit3_ex6_title", "Kvíz: demokratický proud", "Quiz: the democratic current"}, + {"lit3_quiz6_head", "Ověřte si meziválečnou demokratickou prózu", + "Check interwar democratic prose"}, + {"lit3_unit7", "Psychologická a katolická próza", "Psychological and Catholic prose"}, + {"lit3_unit7_sub", "Havlíček, Durych a ruralismus.", + "Havlíček, Durych and ruralism."}, + {"lit3_ex7_title", "Kvíz: další próza", "Quiz: other prose"}, + {"lit3_quiz7_head", "Ověřte si psychologickou a katolickou prózu", + "Check psychological and Catholic prose"}, + {"lit3_unit8", "Literatura za okupace", "Literature under the occupation"}, + {"lit3_unit8_sub", "Orten a Skupina 42.", + "Orten and Group 42."}, + {"lit3_ex8_title", "Kvíz: okupace", "Quiz: the occupation"}, + {"lit3_quiz8_head", "Ověřte si literaturu za okupace", + "Check literature under the occupation"}, + {"lit4_unit1", "Světová próza po roce 1945", "World prose after 1945"}, + {"lit4_unit1_sub", "Orwell, Camus, Márquez a Solženicyn.", + "Orwell, Camus, Márquez and Solzhenitsyn."}, + {"lit4_ex1_title", "Kvíz: poválečná próza", "Quiz: postwar prose"}, + {"lit4_quiz1_head", "Ověřte si světovou prózu po roce 1945", + "Check world prose after 1945"}, + {"lit4_unit2", "Drama a postmoderna", "Drama and postmodernism"}, + {"lit4_unit2_sub", "Beckett, Dürrenmatt a Eco.", + "Beckett, Dürrenmatt and Eco."}, + {"lit4_ex2_title", "Kvíz: drama a postmoderna", "Quiz: drama and postmodernism"}, + {"lit4_quiz2_head", "Ověřte si absurdní drama a postmodernu", + "Check absurdist drama and postmodernism"}, + {"lit4_unit3", "Česká literatura 1945–1956", "Czech literature 1945–1956"}, + {"lit4_unit3_sub", "Krátká svoboda a budovatelský román.", + "A brief freedom and the construction novel."}, + {"lit4_ex3_title", "Kvíz: léta 1945–1956", "Quiz: 1945–1956"}, + {"lit4_quiz3_head", "Ověřte si literaturu let 1945–1956", + "Check literature of 1945–1956"}, + {"lit4_unit4", "Česká literatura 60. let", "Czech literature of the 1960s"}, + {"lit4_unit4_sub", "Hrabal, Kundera, Škvorecký a Fuks.", + "Hrabal, Kundera, Škvorecký and Fuks."}, + {"lit4_ex4_title", "Kvíz: 60. léta", "Quiz: the 1960s"}, + {"lit4_quiz4_head", "Ověřte si literaturu 60. let", + "Check the literature of the 1960s"}, + {"lit4_unit5", "Normalizace", "Normalization"}, + {"lit4_unit5_sub", "Oficiální tvorba, samizdat a exil.", + "Official writing, samizdat and exile."}, + {"lit4_ex5_title", "Kvíz: normalizace", "Quiz: Normalization"}, + {"lit4_quiz5_head", "Ověřte si tři proudy normalizace", + "Check the three currents of Normalization"}, + {"lit4_unit6", "Poezie a drama po roce 1945", "Poetry and drama after 1945"}, + {"lit4_unit6_sub", "Seifert, Havel a autorské divadlo.", + "Seifert, Havel and authorial theatre."}, + {"lit4_ex6_title", "Kvíz: poezie a drama", "Quiz: poetry and drama"}, + {"lit4_quiz6_head", "Ověřte si poválečnou poezii a drama", + "Check postwar poetry and drama"}, + {"lit4_unit7", "Literatura po roce 1989", "Literature after 1989"}, + {"lit4_unit7_sub", "Konec cenzury, Viewegh a Topol.", + "The end of censorship, Viewegh and Topol."}, + {"lit4_ex7_title", "Kvíz: literatura po roce 1989", "Quiz: literature after 1989"}, + {"lit4_quiz7_head", "Ověřte si literaturu po roce 1989", + "Check literature after 1989"}, + {"lit4_unit8", "Interpretace textu", "Interpreting a text"}, + {"lit4_unit8_sub", "Druh, jazyk, kontext a vlastní soud.", + "Genre, language, context and your own judgement."}, + {"lit4_ex8_title", "Kvíz: interpretace", "Quiz: interpretation"}, + {"lit4_quiz8_head", "Ověřte si postup rozboru textu", + "Check how to read a text"}, {"czech_sub", "Vyberte oblast a začněte procvičovat.", "Pick an area and start practicing."}, {"Literatura", "Literatura", "Literature"}, @@ -2125,6 +2331,7 @@ void on_lessons_apply_lang(void); void on2_lessons_apply_lang(void); void on3_lessons_apply_lang(void); void on4_lessons_apply_lang(void); +void lit_lessons_apply_lang(void); void net_rail_theme_reset(void); void apply_language(void) { @@ -2143,5 +2350,6 @@ void apply_language(void) { on2_lessons_apply_lang(); on3_lessons_apply_lang(); on4_lessons_apply_lang(); + lit_lessons_apply_lang(); search_apply_lang(); } diff --git a/src/lit_year1.c b/src/lit_year1.c new file mode 100644 index 0000000..603779f --- /dev/null +++ b/src/lit_year1.c @@ -0,0 +1,614 @@ +#include "graduately.h" + +/* Year 1: literary theory, antiquity, the Middle Ages, Renaissance, + * Baroque, Classicism and the Enlightenment. */ + +NetLesson lit_lessons[LIT_N] = { + { .n_slides = 3, .unit_page = "litunit1", .ex_page = "litex1" }, + { .n_slides = 3, .unit_page = "litunit2", .ex_page = "litex2" }, + { .n_slides = 3, .unit_page = "litunit3", .ex_page = "litex3" }, + { .n_slides = 3, .unit_page = "litunit4", .ex_page = "litex4" }, + { .n_slides = 3, .unit_page = "litunit5", .ex_page = "litex5" }, + { .n_slides = 3, .unit_page = "litunit6", .ex_page = "litex6" }, + { .n_slides = 3, .unit_page = "litunit7", .ex_page = "litex7" }, + { .n_slides = 3, .unit_page = "litunit8", .ex_page = "litex8" }, +}; + +static GtkWidget *build_lit_unit1_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Úvod", "Literatura jako umění slova", + "Tip: nejdřív druh a žánr, potom jazyk a dobový kontext.", + { + "Literatura sděluje zážitek uměleckým jazykem, nejen holou informaci.", + "Od publicistiky ji odlišuje estetická funkce a práce s obrazností.", + "Má i funkci poznávací, výchovnou a zábavnou.", + "Ve škole se sleduje vývoj v kulturních a historických souvislostech.", + NULL, + }, + }, + { + "2 / 3 • Druhy", "Lyrika, epika a drama", + "Tip: žánr je užší typ uvnitř literárního druhu.", + { + "Lyrika vyjadřuje niterný zážitek, epika vypráví příběh.", + "Drama je určeno k jevištnímu provedení a stojí na dialogu.", + "Epika: epos, román, povídka, novela, bajka. Lyrika: píseň, óda, elegie, sonet, balada.", + "Drama: tragédie, komedie, činohra. Vypravěč bývá v ich-formě, nebo er-formě.", + NULL, + }, + }, + { + "3 / 3 • Jazyk", "Verš, tropy a figury", + "Tip: metafora pojmenuje podobnost přímo, přirovnání použije jako.", + { + "Rým je sdružený (AABB), střídavý (ABAB), obkročný (ABBA) nebo přerývaný.", + "Volný verš se neváže pravidelným rýmem ani stopou.", + "Stopy: trochej, jamb a daktyl. Tropy: metafora, metonymie, personifikace, symbol, alegorie.", + "Figury: anafora, epifora, gradace, inverze, oxymóron a apostrofa.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[0], "lit_unit1", "lit_unit1_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit1_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Které jsou tři literární druhy?", + {"Lyrika, epika a drama", "Román, povídka a novela", + "Metafora, metonymie a symbol", "Baroko, romantismus a realismus"}, + 4, 0}, + {"Co je metafora?", + {"Přímé přirovnání se slovem jako", + "Pojmenování na základě podobnosti", + "Opakování slov na začátku veršů", "Báseň bez rýmu"}, + 4, 1}, + {"Který rým má schéma ABAB?", + {"Sdružený", "Obkročný", "Střídavý", "Přerývaný"}, + 4, 2}, + {"Co znamená ich-forma?", + {"Vyprávění v první osobě", "Vyprávění v třetí osobě", + "Drama beze slov", "Volný verš"}, + 4, 0}, + }; + static const char *hints[] = { + "Druh je základní členění, žánr je užší typ uvnitř druhu.", + "Přirovnání používá jako, metafora podobnost pojmenuje přímo.", + "Sdružený je AABB, obkročný ABBA, střídavý ABAB.", + "Ich-forma je já, er-forma je on nebo ona.", + }; + + return lit_mcq_page(0, 0, "litunit1", "lit_ex1_title", "lit_quiz1_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit2_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Orient", "Nejstarší písemnictví", + "Tip: Epos o Gilgamešovi je nejstarší dochovaný epos.", + { + "Mezopotámie zanechala Epos o Gilgamešovi, příběh o přátelství a hledání nesmrtelnosti.", + "Egypt známe z Knihy mrtvých, hymnů a milostné lyriky.", + "Indie má Védy, eposy Mahábhárata a Rámájana a divadelní hry Kálidásovy.", + "Čínská Kniha písní sbírá lidovou i obřadní lyriku.", + NULL, + }, + }, + { + "2 / 3 • Bible", "Hebrejská a křesťanská tradice", + "Tip: Bible je pramen motivů celé evropské kultury.", + { + "Starý zákon tvoří Tóra, historické a prorocké knihy, žalmy a mudrosloví.", + "Kazatel, Job a Píseň písní patří k nejčtenějším starozákonním knihám.", + "Nový zákon přináší evangelia, Skutky, epištoly a Zjevení.", + "Biblické postavy a obrazy se vracejí v literatuře všech pozdějších epoch.", + NULL, + }, + }, + { + "3 / 3 • Paměť", "Co si z orientu odnést", + "Tip: u eposu sledujte hrdinu, cestu a střet s osudem.", + { + "Společná témata jsou stvoření, potopa, zákon, láska a smrt.", + "Texty často vznikaly ústně a teprve později byly zapsány.", + "Anonymita a náboženský výklad světa převažují nad autorským já.", + "Na maturitě stačí zařadit dílo do kultury a říct, čím ovlivnilo Evropu.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[1], "lit_unit2", "lit_unit2_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit2_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Odkud pochází Epos o Gilgamešovi?", + {"Ze starého Egypta", "Z Mezopotámie", "Z antického Říma", "Ze středověké Francie"}, + 4, 1}, + {"Které knihy patří k indické epice?", + {"Ilias a Odyssea", "Mahábhárata a Rámájana", + "Aeneis a Proměny", "Božská komedie a Dekameron"}, + 4, 1}, + {"Co tvoří jádro Starého zákona?", + {"Čtyři evangelia", "Tóra a další knihy hebrejské bible", + "Korán", "Védy"}, + 4, 1}, + {"Proč se Bible probírá v literatuře?", + {"Je to učebnice zeměpisu", + "Je pramenem motivů evropské kultury", + "Vznikla v národním obrození", + "Patří k absurdnímu dramatu"}, + 4, 1}, + }; + static const char *hints[] = { + "Gilgameš je nejstarší dochovaný epos, zapsaný klínovým písmem.", + "Mahábhárata a Rámájana jsou velké indické eposy.", + "Starý zákon je hebrejská bible, Nový zákon evangelia a epištoly.", + "Biblické obrazy se vracejí od středověku po současnost.", + }; + + return lit_mcq_page(0, 1, "litunit2", "lit_ex2_title", "lit_quiz2_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit3_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Řecko", "Homér a attické drama", + "Tip: katarze je očištění diváka soucitem a bázní.", + { + "Homérova Ilias a Odyssea jsou vrchol řeckého eposu, veršovaný hexametrem.", + "Lyriku představují Sapfó, Anakreón a Pindaros.", + "Tragédie: Aischylos, Sofoklés (Král Oidipus, Antigona) a Eurípidés (Médeia).", + "Aristofanés psal komedie. Ideál kalokagathia spojoval krásu a dobro.", + NULL, + }, + }, + { + "2 / 3 • Řím", "Vergilius, Ovidius, Horatius", + "Tip: Aeneis vědomě navazuje na Homéra a zakládá římský mýtus.", + { + "Vergiliova Aeneis vypráví o útěku z Tróje a založení římského rodu.", + "Ovidiovy Proměny shrnují antické mýty, Umění milovat je milostný návod.", + "Horatius proslul ódami a myšlenkou zlaté střední cesty.", + "Římská literatura přejímá řecké vzory a předává je středověké Evropě.", + NULL, + }, + }, + { + "3 / 3 • Pojmy", "Co si z antiky pamatovat", + "Tip: u tragédie hledejte vinu, osud a poznání.", + { + "Epos začíná často in medias res a vzývá Múzu.", + "Tragický hrdina naráží na osud; divák prožívá katarzi.", + "Mýtus vysvětluje svět příběhem bohů a hrdinů.", + "Antika je stálý zdroj námětů pro renesanci, klasicismus i pozdější doby.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[2], "lit_unit3", "lit_unit3_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit3_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Iliadu a Odysseu?", + {"Sofoklés", "Homér", "Vergilius", "Ovidius"}, + 4, 1}, + {"Které dílo napsal Sofoklés?", + {"Médeia", "Král Oidipus", "Aeneis", "Proměny"}, + 4, 1}, + {"Co je katarze?", + {"Začátek eposu uprostřed děje", + "Očištění diváka soucitem a bázní", + "Římský název pro komedii", + "Volný verš bez stopy"}, + 4, 1}, + {"Kdo složil Aeneis?", + {"Horatius", "Homér", "Vergilius", "Aristofanés"}, + 4, 2}, + }; + static const char *hints[] = { + "Ilias a Odyssea jsou homérské eposy.", + "Sofoklés: Král Oidipus a Antigona. Médeia je Eurípidés.", + "Pojem katarze vychází z Aristotelovy Poetiky.", + "Aeneis je římský epos Vergiliův, Proměny napsal Ovidius.", + }; + + return lit_mcq_page(0, 2, "litunit3", "lit_ex3_title", "lit_quiz3_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit4_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Doba", "Středověký pohled na svět", + "Tip: texty bývají anonymní a často nábožensky alegorické.", + { + "Středověk vykládá svět křesťansky: pozemský život je cestou ke spáse.", + "Převažuje latina, postupně se prosazují národní jazyky.", + "Autor často ustupuje, dílo má sloužit víře, poučení nebo oslavě hrdiny.", + "Vedle učené tvorby žije ústní lidová slovesnost.", + NULL, + }, + }, + { + "2 / 3 • Žánry", "Hrdinská, rytířská a městská literatura", + "Tip: Dante uzavírá středověk a otevírá cestu k renesanci.", + { + "Hrdinská epika: Píseň o Rolandovi, Píseň o Nibelunzích, Beowulf.", + "Rytířská epika a dvorská lyrika: artušovské romány, Tristan a Isolda, trubadúři.", + "Náboženská literatura: legendy, hymny, exempla a duchovní drama.", + "Městská satira a Danteho Božská komedie, psaná tercínou.", + NULL, + }, + }, + { + "3 / 3 • Paměť", "Jak středověk číst", + "Tip: alegorie říká jednu věc a míní jinou, hlubší.", + { + "Hrdina ztělesňuje čest, věrnost, víru nebo rytířskou lásku.", + "Symbol a alegorie jsou důležitější než psychologická kresba.", + "Božská komedie provádí poutníka Peklem, Očistcem a Rájem.", + "Středověké látky se vracejí v romantismu i v moderní kultuře.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[3], "lit_unit4", "lit_unit4_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit4_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Které dílo patří k hrdinské epice?", + {"Dekameron", "Píseň o Rolandovi", "Hamlet", "Lakomec"}, + 4, 1}, + {"Čím je typický středověký text?", + {"Důrazem na individuální autorské já", + "Náboženským výkladem a častou anonymitou", + "Volným veršem avantgardy", + "Naturalistickým popisem dědičnosti"}, + 4, 1}, + {"Kdo napsal Božskou komedii?", + {"Francesco Petrarca", "Dante Alighieri", + "Giovanni Boccaccio", "William Shakespeare"}, + 4, 1}, + {"Jakou strofou je psána Božská komedie?", + {"Sonetem", "Tercínou", "Blankversem", "Hexametrem"}, + 4, 1}, + }; + static const char *hints[] = { + "Píseň o Rolandovi je francouzská chanson de geste.", + "Středověk klade víru a poučení nad autorskou originalitu.", + "Dante, Petrarca a Boccaccio jsou tři velcí Italové, Božská komedie je Dantova.", + "Tercína je trojverší, které Dante v komedii používá.", + }; + + return lit_mcq_page(0, 3, "litunit4", "lit_ex4_title", "lit_quiz4_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit5_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Počátky", "Staroslověnština a latina", + "Tip: rok 863 je příchod Konstantina a Metoděje na Velkou Moravu.", + { + "Konstantin a Metoděj přinesli staroslověnské písmo a překlady bohoslužebných textů.", + "K památkám patří Proglas, Život Konstantinův a Metodějův a Kyjevské listy.", + "Po vyhnání slovanské liturgie přebírá vzdělanost latina.", + "Kosmova kronika je nejstarší česká kronika, psaná latinsky.", + NULL, + }, + }, + { + "2 / 3 • Čeština", "Literatura 14. století", + "Tip: Dalimil píše česky a z hlediska české šlechty.", + { + "Dalimilova kronika je první veršovaná kronika v češtině.", + "Alexandreida přenáší antický příběh o Alexandrovi do rytířského světa.", + "Mastičkář je nejstarší české drama, Hradecký rukopis sbírá legendy a satiru.", + "Doba Karla IV. posiluje češtinu vedle latiny a němčiny.", + NULL, + }, + }, + { + "3 / 3 • Husitství", "Hus, píseň a Chelčický", + "Tip: husitství je vrchol starší české literatury v národním jazyce.", + { + "Jan Hus kritizuje církev v českých kázáních a latinském spise O církvi.", + "Jistebnický kancionál uchoval píseň Ktož jsú boží bojovníci.", + "Petr Chelčický v Sieti viery odmítá násilí a spojení víry s mocí.", + "Husitská čeština zjednodušuje pravopis a posiluje srozumitelnost.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[4], "lit_unit5", "lit_unit5_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit5_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy přišli Konstantin a Metoděj na Velkou Moravu?", + {"Roku 863", "Roku 1415", "Roku 1348", "Roku 1620"}, + 4, 0}, + {"Která kronika je první v češtině?", + {"Kosmova kronika", "Dalimilova kronika", + "Hájkova kronika", "Vita Caroli"}, + 4, 1}, + {"Kterou píseň uchoval Jistebnický kancionál?", + {"Kde domov můj", "Ktož jsú boží bojovníci", + "Ach synku, synku", "Hej, Slované"}, + 4, 1}, + {"Čím je Petr Chelčický?", + {"Autorem renesančních sonetů", + "Myslitelem, který odmítá násilí a spojení víry s mocí", + "Barokním kazatelem protireformace", + "Obrozenským jazykovědcem"}, + 4, 1}, + }; + static const char *hints[] = { + "863 je cyrilometodějská misie, 1415 upálení Husa.", + "Kosmas psal latinsky, Dalimil česky.", + "Ktož jsú boží bojovníci je husitská bojová píseň.", + "Sieť viery pravé je Chelčického hlavní spis.", + }; + + return lit_mcq_page(0, 4, "litunit5", "lit_ex5_title", "lit_quiz5_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit6_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Doba", "Člověk se vrací do středu", + "Tip: humanismus staví na antice, renesance na smyslovém světě.", + { + "Humanismus obnovuje zájem o antiku, jazyk a vzdělání člověka.", + "Renesance oslavuje pozemský život, individualitu a smyslovou krásu.", + "Itálie udává tón: Petrarcův sonet a Boccacciův Dekameron.", + "Proti středověkému teocentrismu stojí zájem o člověka a přírodu.", + NULL, + }, + }, + { + "2 / 3 • Evropa", "Od Cervantese k Shakespearovi", + "Tip: Hamlet je renesanční hrdina, který pochybuje a zkoumá.", + { + "Francie: Rabelais (Gargantua a Pantagruel) a Montaignovy Eseje.", + "Španělsko: Cervantesův Důmyslný rytíř don Quijote de la Mancha.", + "Anglie: Shakespeare, tragédie Hamlet, Romeo a Julie, Macbeth, Othello a komedie.", + "Sonet má 14 veršů a pevné schéma; Shakespeare ho užívá i v milostné lyrice.", + NULL, + }, + }, + { + "3 / 3 • Čechy", "Veleslavín a Bible kralická", + "Tip: Bible kralická je vrchol humanistické češtiny.", + { + "Jednota bratrská vydává Bibli kralickou, vzor spisovného jazyka.", + "Daniel Adam z Veleslavína podporuje tisk, překlady a vzdělanost.", + "Jan Blahoslav pečuje o jazyk a bratrský zpěvník.", + "Český humanismus končí porážkou stavovského povstání a pobělohorskou změnou.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[5], "lit_unit6", "lit_unit6_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit6_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo je autorem Dekameronu?", + {"Dante Alighieri", "Giovanni Boccaccio", + "Francesco Petrarca", "Miguel de Cervantes"}, + 4, 1}, + {"Které dílo napsal Shakespeare?", + {"Don Quijote", "Hamlet", "Gargantua a Pantagruel", "Božská komedie"}, + 4, 1}, + {"Co je sonet?", + {"Báseň o 14 verších s pevnou stavbou", + "Středověká hrdinská píseň", + "Dramatická jednota času", + "Barokní kázání"}, + 4, 0}, + {"Která kniha je vrcholem humanistické češtiny?", + {"Kosmova kronika", "Bible kralická", "Labyrint světa", "Máj"}, + 4, 1}, + }; + static const char *hints[] = { + "Petrarca je sonet, Boccaccio Dekameron, Dante Božská komedie.", + "Hamlet, Romeo a Julie, Macbeth a Othello jsou Shakespearovy tragédie.", + "Sonet má 14 veršů, obvykle dvě čtyřverší a dvě trojverší.", + "Bibli kralickou vydala Jednota bratrská na přelomu 16. a 17. století.", + }; + + return lit_mcq_page(0, 5, "litunit6", "lit_ex6_title", "lit_quiz6_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit7_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Styl", "Kontrast a napětí", + "Tip: baroko miluje protiklad těla a duše, světa a věčnosti.", + { + "Baroko vzniká v napětí reformace a protireformace.", + "Vyhledává kontrast, nadsázku, emblém a smyslovou okázalost.", + "Častý je motiv marnosti, smrti a touhy po Bohu.", + "Ve světě sem patří Calderónův Život je sen a Miltonův Ztracený ráj.", + NULL, + }, + }, + { + "2 / 3 • Čechy", "Pobělohorská tvorba", + "Tip: po roce 1620 se dělí domácí katolická tvorba a exil.", + { + "Bedřich Bridel v básni Co Bůh? Člověk? staví nicotu člověka proti Bohu.", + "Bohuslav Balbín brání v latině český jazyk a dějiny.", + "Lidová a pololidová tvorba, kramářské písně a legendy udržují češtinu.", + "Oficiální kultura je katolická, mnoho vzdělanců odchází do exilu.", + NULL, + }, + }, + { + "3 / 3 • Komenský", "Labyrint světa a ráj srdce", + "Tip: Komenský je vrchol českého baroka i evropského pedagogického myšlení.", + { + "Jan Amos Komenský, poslední biskup Jednoty bratrské, píše v exilu.", + "Labyrint světa a ráj srdce je alegorické putování za smyslem života.", + "Informatorium školy mateřské a Orbis pictus zakládají moderní pedagogiku.", + "Kšaft umírající matky Jednoty bratrské je odkaz národu a jazyku.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[6], "lit_unit7", "lit_unit7_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit7_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Který rys vystihuje baroko?", + {"Klidná vyváženost a tři jednoty", + "Kontrast, nadsázka a napětí těla a duše", + "Popis všedního dne bez obraznosti", + "Odmítání náboženství"}, + 4, 1}, + {"Kdo napsal Co Bůh? Člověk?", + {"Jan Amos Komenský", "Bedřich Bridel", + "Bohuslav Balbín", "Daniel Adam z Veleslavína"}, + 4, 1}, + {"O čem je Labyrint světa a ráj srdce?", + {"O alegorickém putování za smyslem života", + "O válce s mloky", + "O národním obrození", + "O životě Švejka"}, + 4, 0}, + {"Kam patří Komenského pedagogické spisy?", + {"K poetismu", "K baroku a počátkům moderní pedagogiky", + "K májovcům", "K existencialismu"}, + 4, 1}, + }; + static const char *hints[] = { + "Baroko pracuje s protikladem, světlem a stínem, tělem a věčností.", + "Bridel je autor básně Co Bůh? Člověk?, Komenský napsal Labyrint.", + "Poutník prochází marným světem a nalézá klid v srdci u Boha.", + "Informatorium a Orbis pictus jsou Komenského učební spisy.", + }; + + return lit_mcq_page(0, 6, "litunit7", "lit_ex7_title", "lit_quiz7_head", + qs, hints, 4); +} + +static GtkWidget *build_lit_unit8_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Klasicismus", "Rozum a pravidlo", + "Tip: tři jednoty jsou jednota času, místa a děje.", + { + "Klasicismus 17. století navazuje na antiku a žádá kázeň, harmonii a pravidla.", + "Vyvrcholil ve Francii: Corneille, Racine a Molièrovy komedie.", + "Molièrův Lakomec a Tartuffe zesměšňují lidskou vadu jako typ.", + "La Fontaine převyprávěl bajky, Boileau sepsal pravidla básnictví.", + NULL, + }, + }, + { + "2 / 3 • Osvícenství", "Rozum má měnit společnost", + "Tip: Candide se vysmívá lehké víře, že žijeme v nejlepším z světů.", + { + "Osvícenství věří rozumu, vzdělání, toleranci a kritice předsudků.", + "Voltairův Candide a Swiftovy Gulliverovy cesty jsou satirické prózy.", + "Defoeův Robinson Crusoe oslavuje práci a praktický rozum.", + "Encyklopedisté včetně Diderota chtějí zpřístupnit vědění.", + NULL, + }, + }, + { + "3 / 3 • Cit", "Preromantismus a cesta k obrození", + "Tip: Werther otevírá literaturu citovému jednotlivci.", + { + "Preromantismus staví cit, přírodu a středověk proti chladnému rozumu.", + "Goethovo Utrpení mladého Werthera a Faust spojují cit i filozofii.", + "Schillerovy Loupežníci hájí svobodu proti útisku.", + "V Čechách na osvícenskou učenost naváže národní obrození.", + NULL, + }, + }, + }; + + return lit_unit_page(0, &lit_lessons[7], "lit_unit8", "lit_unit8_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit_unit8_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co jsou tři jednoty klasicistního dramatu?", + {"Jednota času, místa a děje", + "Jednota autora, hrdiny a čtenáře", + "Jednota rýmu, stopy a sloky", + "Jednota lyriky, epiky a dramatu"}, + 4, 0}, + {"Kdo napsal Lakomce?", + {"William Shakespeare", "Molière", "Johann Wolfgang Goethe", "Voltaire"}, + 4, 1}, + {"Které dílo je osvícenská satira?", + {"Kytice", "Candide", "Máj", "Babička"}, + 4, 1}, + {"Čím preromantismus překonává klasicismus?", + {"Důrazem na cit, přírodu a individuální prožitek", + "Přísnějšími pravidly rýmu", + "Návratem výhradně k latině", + "Odmítnutím divadla"}, + 4, 0}, + }; + static const char *hints[] = { + "Klasicistní tragédie se má odehrát v jednom dni, na jednom místě a v jedné linii.", + "Molière je autorem Lakomce a Tartuffa.", + "Candide napsal Voltaire, Gulliverovy cesty Swift.", + "Werther a Schillerovi Loupežníci už staví cit proti pravidlu.", + }; + + return lit_mcq_page(0, 7, "litunit8", "lit_ex8_title", "lit_quiz8_head", + qs, hints, 4); +} + +void add_lit_pages(GtkStack *stack) { + typedef GtkWidget *(*LitBuilder)(void); + static const struct { + const char *unit_name; + const char *ex_name; + LitBuilder build_unit; + LitBuilder build_ex; + } pages[] = { + {"litunit1", "litex1", build_lit_unit1_page, build_lit_unit1_exercise_page}, + {"litunit2", "litex2", build_lit_unit2_page, build_lit_unit2_exercise_page}, + {"litunit3", "litex3", build_lit_unit3_page, build_lit_unit3_exercise_page}, + {"litunit4", "litex4", build_lit_unit4_page, build_lit_unit4_exercise_page}, + {"litunit5", "litex5", build_lit_unit5_page, build_lit_unit5_exercise_page}, + {"litunit6", "litex6", build_lit_unit6_page, build_lit_unit6_exercise_page}, + {"litunit7", "litex7", build_lit_unit7_page, build_lit_unit7_exercise_page}, + {"litunit8", "litex8", build_lit_unit8_page, build_lit_unit8_exercise_page}, + }; + + for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { + gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); + gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); + } +} diff --git a/src/lit_year2.c b/src/lit_year2.c new file mode 100644 index 0000000..af0f2b4 --- /dev/null +++ b/src/lit_year2.c @@ -0,0 +1,611 @@ +#include "graduately.h" + +/* Year 2: National Revival, Romanticism, Realism, the Máj generation, + * ruchovci and lumírovci, Czech realism, the modern movement. */ + +NetLesson lit2_lessons[LIT_N] = { + { .n_slides = 3, .unit_page = "lit2unit1", .ex_page = "lit2ex1" }, + { .n_slides = 3, .unit_page = "lit2unit2", .ex_page = "lit2ex2" }, + { .n_slides = 3, .unit_page = "lit2unit3", .ex_page = "lit2ex3" }, + { .n_slides = 3, .unit_page = "lit2unit4", .ex_page = "lit2ex4" }, + { .n_slides = 3, .unit_page = "lit2unit5", .ex_page = "lit2ex5" }, + { .n_slides = 3, .unit_page = "lit2unit6", .ex_page = "lit2ex6" }, + { .n_slides = 3, .unit_page = "lit2unit7", .ex_page = "lit2ex7" }, + { .n_slides = 3, .unit_page = "lit2unit8", .ex_page = "lit2ex8" }, +}; + +static GtkWidget *build_lit2_unit1_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Smysl", "Proč obrození vzniklo", + "Tip: obrození zachraňuje češtinu jako jazyk vzdělanosti a národa.", + { + "Na konci 18. století je čeština hlavně jazykem venkova a kuchyně.", + "Osvícenství a herderovská myšlenka národa dávají podnět k obraně jazyka.", + "Cíl je vrátit češtinu do vědy, školy, divadla a krásné literatury.", + "Obrození se obvykle dělí na fázi obrannou a ofenzivní.", + NULL, + }, + }, + { + "2 / 3 • Obrana", "Dobrovský a první generace", + "Tip: Dobrovský češtinu vědecky popisuje, ale o její budoucnosti pochybuje.", + { + "Josef Dobrovský píše Zevrubnou mluvnici a zkoumá staroslověnštinu.", + "Václav Thám a Kramerius vydávají české knihy a noviny pro lid.", + "Vzniká české divadlo, Bouda a snaha hrát v národním jazyce.", + "První fáze jazyk brání a popisuje, ještě ho plně nerozvíjí v umění.", + NULL, + }, + }, + { + "3 / 3 • Útok", "Jungmann, Kollár, Čelakovský", + "Tip: Rukopisy královédvorský a zelenohorský měly dodat národu starou epiku.", + { + "Josef Jungmann vytváří česko-německý slovník a překládá z evropských literatur.", + "František Palacký píše dějiny jako příběh národa.", + "Kollárova Slávy dcera a Čelakovského Ohlasy spojují slovanskou myšlenku s lidovou písní.", + "Rukopisy z let 1817 a 1818 literaturu na čas ovlivnily, později byly odhaleny jako padělky.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[0], "lit2_unit1", "lit2_unit1_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit1_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Jaký byl hlavní cíl národního obrození?", + {"Nahradit češtinu latinou", + "Obnovit češtinu jako jazyk kultury a národa", + "Zavést romantický román podle Francie", + "Zrušit divadlo"}, + 4, 1}, + {"Čím je Josef Dobrovský?", + {"Autorem Máje", "Jazykovědcem obranné fáze", + "Lumírovcem", "Autorem Bible kralické"}, + 4, 1}, + {"Kdo sestavil velký česko-německý slovník?", + {"Josef Jungmann", "Karel Hynek Mácha", + "Jan Neruda", "Jaroslav Vrchlický"}, + 4, 0}, + {"Co jsou Rukopisy královédvorský a zelenohorský?", + {"Díla Kosmy", "Padělky, které měly dokázat starobylost české epiky", + "Husitské kroniky", "Barokní kancionály"}, + 4, 1}, + }; + static const char *hints[] = { + "Obrození brání a potom rozvíjí národní jazyk.", + "Dobrovský patří k obranné fázi, Jungmann k ofenzivní.", + "Jungmannův slovník a překlady otevírají češtinu vysoké literatuře.", + "RKZ vznikly 1817 a 1818 a později byly rozpoznány jako podvrhy.", + }; + + return lit_mcq_page(1, 0, "lit2unit1", "lit2_ex1_title", "lit2_quiz1_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit2_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Postoj", "Jedinec proti světu", + "Tip: romantik hledá v minulosti, přírodě a výjimečném hrdinovi to, co současnost nedává.", + { + "Romantismus staví cit, obraznost a svobodu jednotlivce proti pravidlům klasicismu.", + "Hrdina je výjimečný, často vyvržený, a střetává se se společností.", + "Oblíbené je středověk, lidová slovesnost, exotika a tajemno.", + "Rozpor mezi snem a skutečností je základní romantické napětí.", + NULL, + }, + }, + { + "2 / 3 • Evropa", "Byron, Hugo, Puškin", + "Tip: Byronův hrdina je unavený, hrdý a v rozporu se světem.", + { + "Anglie: Byron, Shelley, Scottovy historické romány a jezerní básníci.", + "Francie: Victor Hugo, Chrám Matky Boží v Paříži a Bídníci, předmluva ke Cromwellovi.", + "Německo: bratři Grimmové, Novalis a Heinrich Heine.", + "Rusko: Puškinův Evžen Oněgin a Lermontov. Polsko: Mickiewicz.", + NULL, + }, + }, + { + "3 / 3 • Amerika", "Poe a romantické tajemno", + "Tip: Poe stojí u hororu, detektivky i teorie básně.", + { + "Edgar Allan Poe píše Havrana, hrůzostrašné povídky a detektivní záhady.", + "Romantismus otevírá i gotický román a téma dvojnictví.", + "Historický román učí číst dějiny jako osud národa.", + "Tyto vzory silně působí na český romantismus v čele s Máchou.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[1], "lit2_unit2", "lit2_unit2_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit2_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je pro romantismus typické?", + {"Tři jednoty a rozumová kázeň", + "Cit, rozpor jedince se společností a zájem o minulost", + "Přesný popis všední práce", + "Odmítnutí obraznosti"}, + 4, 1}, + {"Kdo napsal Evžena Oněgina?", + {"Victor Hugo", "Alexandr Sergejevič Puškin", + "George Gordon Byron", "Edgar Allan Poe"}, + 4, 1}, + {"Které dílo patří Victoru Hugovi?", + {"Bídníci", "Lakomec", "Candide", "Král Oidipus"}, + 4, 0}, + {"Čím je Edgar Allan Poe?", + {"Autorem realistického románu o venkově", + "Romantikem hororu, tajemna a detektivní povídky", + "Klasicistním dramatikem", + "Autorem husitské kroniky"}, + 4, 1}, + }; + static const char *hints[] = { + "Romantický hrdina stojí proti obyčejnému světu.", + "Evžen Oněgin je veršovaný román Puškinův.", + "Hugo napsal Bídníky a Chrám Matky Boží v Paříži.", + "Havran a povídky tajemna jsou Poeova romantická tvorba.", + }; + + return lit_mcq_page(1, 1, "lit2unit2", "lit2_ex2_title", "lit2_quiz2_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit3_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Máj", "Karel Hynek Mácha", + "Tip: Máj vyšel 1836 a doba mu vytýkala, že není dost vlastenecký.", + { + "Máj je lyrickoepická skladba o vině, času a rozporu snu se skutečností.", + "Vilém zabije svůdce milenky a neví, že zabil vlastního otce.", + "Příroda je krásná a lhostejná k lidskému utrpení.", + "Báseň je psána jambem a patří k vrcholům české poezie.", + NULL, + }, + }, + { + "2 / 3 • Balada", "Erben, Tyl a Němcová", + "Tip: v Kytici trestá osud vinu, často vinu rodičů na dětech.", + { + "Karel Jaromír Erben vydal 1853 Kytici, soubor balad z lidové víry.", + "Josef Kajetán Tyl píše Strakonického dudáka a hru Fidlovačka s písní Kde domov můj.", + "Božena Němcová v Babičce staví ideál lidskosti a venkovského řádu.", + "Její povídky, třeba Divá Bára, hájí právo ženy na vlastní cestu.", + NULL, + }, + }, + { + "3 / 3 • Satira", "Havlíček a vyvrcholení obrození", + "Tip: Havlíček už romantický patos ironizuje a měří ho politikou.", + { + "Karel Havlíček Borovský píše epigramy, Tyrolské elegie a Křest svatého Vladimíra.", + "Satira míří na absolutismus, církevní moc a národní pózu.", + "Třetí fáze obrození splývá s romantismem a politickým ruchem roku 1848.", + "Mácha, Erben, Tyl, Němcová a Havlíček jsou jádro českého romantismu.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[2], "lit2_unit3", "lit2_unit3_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit3_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy vyšel Máchův Máj?", + {"Roku 1836", "Roku 1853", "Roku 1858", "Roku 1895"}, + 4, 0}, + {"O čem jsou Erbenovy balady v Kytici?", + {"O budování továren", "O vině a trestu podle lidové víry", + "O legionářích", "O absurdním čekání"}, + 4, 1}, + {"Kde zazní píseň Kde domov můj?", + {"V Máji", "Ve Fidlovačce Josefa Kajetána Tyla", + "V Babičce", "V Labyrintu světa"}, + 4, 1}, + {"Které dílo napsal Karel Havlíček Borovský?", + {"Tyrolské elegie", "Povídky malostranské", + "Psohlavci", "R.U.R."}, + 4, 0}, + }; + static const char *hints[] = { + "Máj 1836, Kytice 1853, almanach Máj 1858.", + "Erbenova balada spojuje lidový příběh s mravním řádem.", + "Tylova Fidlovačka obsahuje píseň, z níž vznikla hymna.", + "Havlíček: epigramy, Tyrolské elegie, Křest svatého Vladimíra.", + }; + + return lit_mcq_page(1, 2, "lit2unit3", "lit2_ex3_title", "lit2_quiz3_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit4_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Metoda", "Vidět společnost takovou, jaká je", + "Tip: realismus typizuje, naturalismus přidává dědičnost a prostředí.", + { + "Realismus popisuje současnost, společenské vrstvy a všední konflikty.", + "Postava je typ: nese rysy své doby, třídy a prostředí.", + "Vypravěč bývá střízlivý a dává prostor detailu.", + "Naturalismus jde dál: člověka určuje dědičnost, pudy a hmotné podmínky.", + NULL, + }, + }, + { + "2 / 3 • Francie a Anglie", "Od Balzaca k Zolovi", + "Tip: Paní Bovaryová ukazuje střet romantického snu s provincií.", + { + "Honoré de Balzac v Lidské komedii mapuje francouzskou společnost.", + "Stendhalův Červený a černý sleduje ctižádost v porevoluční Francii.", + "Flaubertova Paní Bovaryová je vrchol psychologického realismu.", + "Zola (Zabiják) je naturalista. Dickens (Oliver Twist) kritizuje bídu průmyslové Anglie.", + NULL, + }, + }, + { + "3 / 3 • Rusko", "Tolstoj, Dostojevskij, Čechov", + "Tip: Dostojevskij zkoumá vinu svědomí, Tolstoj široký obraz doby.", + { + "Nikolaj Gogol spojuje satiru a grotesku, Revizor je komedie o strachu z moci.", + "Lev Tolstoj píše Vojnu a mír a Annu Kareninu.", + "Fjodor Michajlovič Dostojevskij ve Zločinu a trestu řeší vinu a trest svědomí.", + "Anton Pavlovič Čechov zklidňuje drama i povídku do zdánlivě obyčejného života.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[3], "lit2_unit4", "lit2_unit4_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit4_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Čím se realismus liší od romantismu?", + {"Hledá výjimečného hrdinu mimo společnost", + "Zobrazuje současnou společnost a typické postavy", + "Drží se tří jednot klasicismu", + "Píše jen duchovní legendy"}, + 4, 1}, + {"Kdo je autorem Paní Bovaryové?", + {"Émile Zola", "Gustave Flaubert", "Charles Dickens", "Lev Tolstoj"}, + 4, 1}, + {"Které dílo napsal Dostojevskij?", + {"Zločin a trest", "Oliver Twist", "Evžen Oněgin", "Bídníci"}, + 4, 0}, + {"Co zdůrazňuje naturalismus?", + {"Jen šťastný konec pohádky", + "Vliv dědičnosti, pudů a prostředí", + "Pravidla antické tragédie", + "Slovanskou vzájemnost"}, + 4, 1}, + }; + static const char *hints[] = { + "Realistický hrdina je typ své vrstvy a doby.", + "Flaubert napsal Paní Bovaryovou, Zola je naturalista.", + "Zločin a trest je román o vině Raskolnikova.", + "Zola chápe člověka jako určeného tělem a prostředím.", + }; + + return lit_mcq_page(1, 3, "lit2unit4", "lit2_ex4_title", "lit2_quiz4_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit5_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Program", "Almanach Máj 1858", + "Tip: májovci chtějí literaturu světovou, pravdivou a současnou.", + { + "Mladá generace se hlásí k Máchovi a odmítá vlasteneckou frázi.", + "Almanach Máj žádá umění otevřené Evropě a skutečnému životu.", + "K okruhu patří Neruda, Hálek, Světlá a Pfleger.", + "Generace reaguje na Bachův absolutismus a politické zklamání.", + NULL, + }, + }, + { + "2 / 3 • Neruda", "Poezie, fejeton a Malá Strana", + "Tip: Povídky malostranské jsou galerie typů, ne idyla.", + { + "Jan Neruda píše Hřbitovní kvítí, Knihy veršů, Písně kosmické a Balady a romance.", + "Povídky malostranské zachycují pražskou čtvrť s ironií i soucitem.", + "Fejeton v Národních listech je Nerudova škola pohledu na den.", + "Balady a romance spojují legendu, lidový tón a moderní skepsi.", + NULL, + }, + }, + { + "3 / 3 • Vedle něj", "Hálek, Světlá, Arbes", + "Tip: Arbesovo romaneto je napínavý příběh s racionálním vysvětlením.", + { + "Vítězslav Hálek je lyrik májovců, autor Večerních písní.", + "Karolina Světlá píše Vesnický román a prosazuje ženskou vzdělanost.", + "Jakub Arbes vytváří romaneto, třeba Newtonův mozek.", + "Májovci otevírají cestu pozdějšímu realismu.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[4], "lit2_unit5", "lit2_unit5_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit5_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy vyšel almanach Máj?", + {"Roku 1836", "Roku 1858", "Roku 1868", "Roku 1895"}, + 4, 1}, + {"Kdo napsal Povídky malostranské?", + {"Jan Neruda", "Božena Němcová", "Alois Jirásek", "Karel Čapek"}, + 4, 0}, + {"Co je romaneto?", + {"Lidová balada", "Napínavý příběh s racionálním jádrem", + "Klasicistní tragédie", "Husitská píseň"}, + 4, 1}, + {"Jaký program měli májovci?", + {"Návrat výhradně k latině", + "Literatura světová, pravdivá a současná", + "Jen oslavné ódy na panovníka", + "Odmítnutí Máje"}, + 4, 1}, + }; + static const char *hints[] = { + "Almanach Máj je 1858, Máchův Máj je 1836, Ruch 1868.", + "Neruda v nich kreslí typy z Malé Strany.", + "Romaneto je žánr Jakuba Arbesa.", + "Májovci navazují na Máchu a chtějí umění bez fráze.", + }; + + return lit_mcq_page(1, 4, "lit2unit5", "lit2_ex5_title", "lit2_quiz5_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit6_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Spor", "Dvě odpovědi na smysl literatury", + "Tip: ruchovci brání národní tradici, lumírovci otevírají okno do Evropy.", + { + "Po májovcích se generace rozchází v tom, čemu má literatura sloužit.", + "Ruchovci kolem almanachu Ruch 1868 zdůrazňují národ a domácí látky.", + "Lumírovci kolem časopisu Lumír chtějí světovost a dokonalou formu.", + "Spor není osobní hádka, ale dvě představy o úkolu českého umění.", + NULL, + }, + }, + { + "2 / 3 • Ruch", "Svatopluk Čech", + "Tip: Písně otroka jsou politická alegorie nesvobody.", + { + "Svatopluk Čech píše Písně otroka, Evropy a satiru o panu Broučkovi.", + "Eliška Krásnohorská hájí srozumitelnost a národní úkol poezie.", + "Ruchovci navazují na obrozenskou představu básníka jako mluvčího národa.", + "Forma bývá rétorická, téma často vlastenecké a slovanské.", + NULL, + }, + }, + { + "3 / 3 • Lumír", "Vrchlický, Sládek, Zeyer", + "Tip: Vrchlický přináší do češtiny formy i látky z celé Evropy.", + { + "Jaroslav Vrchlický je mimořádně plodný lyrik, epik i dramatik, autor Noci na Karlštejně.", + "Josef Václav Sládek píše intimní a venkovskou lyriku a překládá.", + "Julius Zeyer čerpá z mýtů a legend, Radúz a Mahulena je pohádkové drama.", + "Lumírovci připravují půdu pro českou modernu.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[5], "lit2_unit6", "lit2_unit6_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit6_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Čím se lumírovci liší od ruchovců?", + {"Odmítají veškerou poezii", + "Kladou důraz na světovost a uměleckou formu", + "Píšou jen latinsky", + "Patří k baroku"}, + 4, 1}, + {"Kdo napsal Písně otroka?", + {"Svatopluk Čech", "Jaroslav Vrchlický", "Jan Neruda", "Karel Hynek Mácha"}, + 4, 0}, + {"Které drama napsal Vrchlický?", + {"Maryša", "Noc na Karlštejně", "Lakomec", "Audience"}, + 4, 1}, + {"Kam patří Julius Zeyer?", + {"K májovcům", "K lumírovcům", "K proletářské poezii", "K samizdatu"}, + 4, 1}, + }; + static const char *hints[] = { + "Lumír znamená otevření české literatury Evropě.", + "Svatopluk Čech je hlavní básník ruchovců.", + "Noc na Karlštejně je veršovaná komedie Vrchlického.", + "Zeyer, Vrchlický a Sládek tvoří jádro lumírovců.", + }; + + return lit_mcq_page(1, 5, "lit2unit6", "lit2_ex6_title", "lit2_quiz6_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit7_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Venkov", "Realistická próza", + "Tip: venkovský realismus neidealizuje, ukazuje bídu, víru i krutost zvyku.", + { + "Český realismus se obrací k venkovu, městu i historii.", + "Karel Václav Rais v Kalibově zločinu sleduje chudobu a vinu.", + "Teréza Nováková a Ignát Herrmann přidávají region a město.", + "Postava je určena prostředím, majetkem a mravem obce.", + NULL, + }, + }, + { + "2 / 3 • Historie", "Jirásek a historická próza", + "Tip: Jirásek vykládá dějiny jako posilu národního vědomí.", + { + "Alois Jirásek píše Psohlavce, Temno, F. L. Věka a Staré pověsti české.", + "Zikmund Winter přidává kulturněhistorický detail městského života.", + "Historická próza navazuje na Palackého pojetí českých dějin.", + "Na jevišti ji doplňuje drama z venkova a z dějin.", + NULL, + }, + }, + { + "3 / 3 • Drama", "Maryša a naturalismus", + "Tip: Maryša je tragédie nevolené svatby a bezmoci ženy.", + { + "Alois a Vilém Mrštíkové napsali Maryšu, hru o vynuceném sňatku.", + "Gabriela Preissová v Gazdině robě otevírá ženský osud na vesnici.", + "Naturalismus u nás zastupuje Karel Matěj Čapek-Chod.", + "Konec století už připravuje modernu, symbol a individuální senzibilitu.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[6], "lit2_unit7", "lit2_unit7_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit7_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Kalibův zločin?", + {"Karel Václav Rais", "Alois Jirásek", "Jan Neruda", "Julius Zeyer"}, + 4, 0}, + {"Které dílo patří Aloisi Jiráskovi?", + {"Temno", "Máj", "Babička", "R.U.R."}, + 4, 0}, + {"O čem je Maryša?", + {"O kosmických písních", + "O vynuceném sňatku a tragédii venkovské ženy", + "O cestě do Itálie", + "O robotovi"}, + 4, 1}, + {"Kam patří historická próza Jiráska a Wintra?", + {"K českému realismu druhé poloviny 19. století", + "K antice", "K poetismu", "K literatuře po roce 1989"}, + 4, 0}, + }; + static const char *hints[] = { + "Rais je představitel venkovského realismu.", + "Temno, Psohlavci a Staré pověsti české jsou Jiráskovy.", + "Maryšu napsali bratři Mrštíkové.", + "Historický román tu slouží i národní paměti.", + }; + + return lit_mcq_page(1, 6, "lit2unit7", "lit2_ex7_title", "lit2_quiz7_head", + qs, hints, 4); +} + +static GtkWidget *build_lit2_unit8_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Evropa", "Prokletí básníci a dekadence", + "Tip: Baudelairovy Květy zla otevírají moderní městskou obraznost.", + { + "Konec století hledá nový jazyk: symbol, náladu, smyslovost a skepsi.", + "Charles Baudelaire, Paul Verlaine a Arthur Rimbaud jsou prokletí básníci.", + "Oscar Wilde v Obrazu Doriana Graye spojuje krásu, morálku a rozklad.", + "Symbol nesděluje věc přímo, nýbrž ji naznačuje.", + NULL, + }, + }, + { + "2 / 3 • Čechy", "Česká moderna", + "Tip: Manifest české moderny vyšel roku 1895.", + { + "Manifest žádá individualitu, kritičnost a konec vlastenecké rutiny.", + "K modernistům patří Antonín Sova, Otokar Březina a Karel Hlaváček.", + "Jiří Karásek ze Lvovic reprezentuje dekadenci, Josef Svatopluk Machar skepsi a satiru.", + "Impresionismus v básni zachycuje prchavý dojem, symbolismus skrytý smysl.", + NULL, + }, + }, + { + "3 / 3 • Buřiči", "Generace anarchistů", + "Tip: buřiči spojují vzdor, erotiku a soucit se sociálním dnem.", + { + "Fráňa Šrámek píše Stříbrný vítr a drama Měsíc nad řekou.", + "Viktor Dyk je autorem Krysaře a vzdorné politické lyriky.", + "Petr Bezruč ve Slezských písních mluví hlasem utiskovaného regionu.", + "S modernou končí 19. století a otevírá se literatura století dvacátého.", + NULL, + }, + }, + }; + + return lit_unit_page(1, &lit2_lessons[7], "lit2_unit8", "lit2_unit8_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit2_unit8_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy vyšel Manifest české moderny?", + {"Roku 1858", "Roku 1895", "Roku 1918", "Roku 1948"}, + 4, 1}, + {"Kdo napsal Květy zla?", + {"Charles Baudelaire", "Oscar Wilde", "Antonín Sova", "Jan Neruda"}, + 4, 0}, + {"Které dílo napsal Viktor Dyk?", + {"Krysař", "Babička", "Maryša", "Edison"}, + 4, 0}, + {"Čím jsou Slezské písně Petra Bezruče?", + {"Oslavou pražského salonu", + "Hlasem sociálního a národního útisku ve Slezsku", + "Barokní legendou", + "Antickým eposem"}, + 4, 1}, + }; + static const char *hints[] = { + "1895 je programový rok české moderny.", + "Baudelaire je ústřední prokletý básník.", + "Krysař je Dykova novela o moci a pomstě.", + "Bezruč mluví za chudý a utlačovaný kraj.", + }; + + return lit_mcq_page(1, 7, "lit2unit8", "lit2_ex8_title", "lit2_quiz8_head", + qs, hints, 4); +} + +void add_lit2_pages(GtkStack *stack) { + typedef GtkWidget *(*LitBuilder)(void); + static const struct { + const char *unit_name; + const char *ex_name; + LitBuilder build_unit; + LitBuilder build_ex; + } pages[] = { + {"lit2unit1", "lit2ex1", build_lit2_unit1_page, build_lit2_unit1_exercise_page}, + {"lit2unit2", "lit2ex2", build_lit2_unit2_page, build_lit2_unit2_exercise_page}, + {"lit2unit3", "lit2ex3", build_lit2_unit3_page, build_lit2_unit3_exercise_page}, + {"lit2unit4", "lit2ex4", build_lit2_unit4_page, build_lit2_unit4_exercise_page}, + {"lit2unit5", "lit2ex5", build_lit2_unit5_page, build_lit2_unit5_exercise_page}, + {"lit2unit6", "lit2ex6", build_lit2_unit6_page, build_lit2_unit6_exercise_page}, + {"lit2unit7", "lit2ex7", build_lit2_unit7_page, build_lit2_unit7_exercise_page}, + {"lit2unit8", "lit2ex8", build_lit2_unit8_page, build_lit2_unit8_exercise_page}, + }; + + for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { + gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); + gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); + } +} diff --git a/src/lit_year3.c b/src/lit_year3.c new file mode 100644 index 0000000..bdd30dd --- /dev/null +++ b/src/lit_year3.c @@ -0,0 +1,616 @@ +#include "graduately.h" + +/* Year 3: the first half of the 20th century, world and Czech. */ + +NetLesson lit3_lessons[LIT_N] = { + { .n_slides = 3, .unit_page = "lit3unit1", .ex_page = "lit3ex1" }, + { .n_slides = 3, .unit_page = "lit3unit2", .ex_page = "lit3ex2" }, + { .n_slides = 3, .unit_page = "lit3unit3", .ex_page = "lit3ex3" }, + { .n_slides = 3, .unit_page = "lit3unit4", .ex_page = "lit3ex4" }, + { .n_slides = 3, .unit_page = "lit3unit5", .ex_page = "lit3ex5" }, + { .n_slides = 3, .unit_page = "lit3unit6", .ex_page = "lit3ex6" }, + { .n_slides = 3, .unit_page = "lit3unit7", .ex_page = "lit3ex7" }, + { .n_slides = 3, .unit_page = "lit3unit8", .ex_page = "lit3ex8" }, +}; + +static GtkWidget *build_lit3_unit1_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Zlom", "Umění po roce 1900", + "Tip: avantgarda chce tvořit budoucnost, ne jen zdobit přítomnost.", + { + "Nové směry odmítají popisnou iluzi 19. století.", + "Futurismus oslavuje rychlost, stroj a rozchod s muzeem.", + "Expresionismus křičí vnitřní úzkost, dadaismus se vysmívá smyslu války.", + "Surrealismus, vedený Bretonem, čerpá ze snu a nevědomí.", + NULL, + }, + }, + { + "2 / 3 • Báseň", "Apollinaire a pásmo", + "Tip: Pásmo ruší pravidelnou sloku a skládá báseň z volných obrazů.", + { + "Guillaume Apollinaire píše Pásmo a dává jméno kubismu i novému lyrismu.", + "Báseň může být bez interpunkce, jako proud vjemů velkoměsta.", + "Vladimir Majakovskij spojuje futurismus s politickým gestem.", + "Volný verš a asociace se stávají běžným nástrojem moderny.", + NULL, + }, + }, + { + "3 / 3 • Smysl", "Proč avantgardu znát", + "Tip: český poetismus a surrealismus z těchto podnětů přímo vyrůstají.", + { + "Avantgarda je mezinárodní a časopisy i manifesty putují přes hranice.", + "Umění se chápe jako experiment, ne jako hotový vzor.", + "Válka 1914–1918 tyto směry radikalizuje.", + "Bez avantgardy nelze číst Nezvala, Seiferta ani evropskou poezii 20. století.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[0], "lit3_unit1", "lit3_unit1_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit1_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co chce avantgarda?", + {"Vrátit se k třem jednotám", + "Experimentovat a tvořit nové umění", + "Psát jen historické romány", + "Obnovit latinskou kroniku"}, + 4, 1}, + {"Kdo napsal Pásmo?", + {"Guillaume Apollinaire", "Franz Kafka", + "Ernest Hemingway", "Karel Čapek"}, + 4, 0}, + {"Odkud čerpá surrealismus?", + {"Z úředního jazyka", "Ze snu a nevědomí", + "Z antické jednoty času", "Z kramářské písně"}, + 4, 1}, + {"Který směr oslavuje rychlost a stroj?", + {"Klasicismus", "Futurismus", "Venkovský realismus", "Baroko"}, + 4, 1}, + }; + static const char *hints[] = { + "Avantgarda je programová moderna počátku 20. století.", + "Apollinairovo Pásmo je vzor moderní volné básně.", + "Bretonův surrealismus navazuje na Freudovo nevědomí.", + "Futurismus vyhlašuje Marinetti, v Rusku Majakovskij.", + }; + + return lit_mcq_page(2, 0, "lit3unit1", "lit3_ex1_title", "lit3_quiz1_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit2_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Válka", "Ztracená generace a Remarque", + "Tip: ztracená generace jsou autoři, které první válka připravila o iluze.", + { + "Ernest Hemingway píše Sbohem, armádo a později Stařec a moře.", + "Francis Scott Fitzgerald zachycuje Velkého Gatsbyho a lesk i prázdnotu úspěchu.", + "Erich Maria Remarque v románu Na západní frontě klid ukazuje zákop očima vojáka.", + "John Steinbeck přidává sociální prózu, třeba O myších a lidech.", + NULL, + }, + }, + { + "2 / 3 • Experiment", "Kafka, Joyce, Proust", + "Tip: Proměna začíná tím, že se člověk probudí jako hmyz, a nikdo se nad tím nepozastaví dost.", + { + "Franz Kafka v Proměně a Procesu zobrazuje úzkost a nepřehlednou moc.", + "James Joyce v Odysseovi rozbíjí tradiční vyprávění proudem vědomí.", + "Marcel Proust staví román na paměti a čase.", + "Moderní próza už nespoléhá na vševědoucího vypravěče a lineární děj.", + NULL, + }, + }, + { + "3 / 3 • Varování", "Antiutopie a svědomí", + "Tip: antiutopie ukazuje společnost, která štěstí vynucuje a svobodu ruší.", + { + "Aldous Huxley v Konci civilizace líčí svět řízený technikou a konzumem.", + "Thomas Mann v Kouzelném vrchu spojuje nemoc, čas a evropskou krizi.", + "Michail Bulgakov v Mistrovi a Markétce hájí umění proti násilné moci.", + "Tyto prózy připravují poválečné antiutopie Orwella a Bradburyho.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[1], "lit3_unit2", "lit3_unit2_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit2_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo patří ke ztracené generaci?", + {"Homér", "Ernest Hemingway", "Dante Alighieri", "Molière"}, + 4, 1}, + {"Které dílo napsal Franz Kafka?", + {"Proměna", "Babička", "Evžen Oněgin", "Maryša"}, + 4, 0}, + {"O čem je Remarquův román Na západní frontě klid?", + {"O salonu 18. století", + "O zážitku vojáka v první světové válce", + "O husitském zpěvu", + "O národním obrození"}, + 4, 1}, + {"Co je proud vědomí?", + {"Lidová balada", + "Záznam vnitřní řeči a vjemů bez tradičního děje", + "Klasicistní prolog", + "Barokní kázání"}, + 4, 1}, + }; + static const char *hints[] = { + "Hemingway, Fitzgerald a další píšou po první válce o ztrátě jistot.", + "Proměna a Proces jsou Kafkovy klíčové prózy.", + "Remarque bourá představu války jako hrdinského dobrodružství.", + "Proud vědomí užívá Joyce a další modernisté.", + }; + + return lit_mcq_page(2, 1, "lit3unit2", "lit3_ex2_title", "lit3_quiz2_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit3_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Jeviště", "Drama se rozchází s iluzí", + "Tip: epické divadlo Brechtovo chce, aby divák přemýšlel, ne jen prožíval.", + { + "Moderní drama opouští měšťanskou konverzaci jako jediný vzor.", + "George Bernard Shaw spojuje komedii s myšlenkou a kritikou.", + "Luigi Pirandello tematizuje, že člověk hraje role a pravda se tříští.", + "Expresionistické drama křičí úzkost rozbitého světa.", + NULL, + }, + }, + { + "2 / 3 • Brecht", "Epické divadlo", + "Tip: zcizovací efekt brání divákovi, aby se v postavě jen rozplynul.", + { + "Bertolt Brecht píše Matku Kuráž a Kavkazský křídový kruh.", + "Písně, komentář a přerušení děje nutí zaujmout postoj.", + "Divadlo má být politické a rozumové, ne jen dojemné.", + "Brecht silně ovlivnil české divadlo druhé poloviny století.", + NULL, + }, + }, + { + "3 / 3 • Amerika", "O'Neill a počátek absurdity", + "Tip: absurdní drama v plné podobě přijde až po druhé válce.", + { + "Eugene O'Neill přináší do Ameriky psychologické a tragické drama.", + "Meziválečné jeviště zkouší masku, sbor i sen.", + "Po roce 1945 na to naváže Beckett a Ionesco.", + "Na maturitu patří Shaw, Pirandello a Brecht jako tři různé moderní cesty.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[2], "lit3_unit3", "lit3_unit3_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit3_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co je epické divadlo?", + {"Divadlo, které chce diváka dojmout až k slzám a nic víc", + "Brechtovo divadlo, které nutí přemýšlet a zaujímat postoj", + "Středověký mysterijní cyklus", + "Opera bez textu"}, + 4, 1}, + {"Kdo napsal Matku Kuráž?", + {"Bertolt Brecht", "William Shakespeare", + "Molière", "Václav Havel"}, + 4, 0}, + {"Čím se Pirandello zabývá?", + {"Husitskou písní", "Tím, že člověk hraje role a skutečnost se tříští", + "Venkovským realismem", "Eposem o Gilgamešovi"}, + 4, 1}, + {"Kdy se plně rozvine absurdní drama?", + {"V antice", "Až po druhé světové válce", + "V národním obrození", "Ve 14. století"}, + 4, 1}, + }; + static const char *hints[] = { + "Zcizovací efekt je hlavní nástroj Brechtova epického divadla.", + "Matka Kuráž je brechtovská hra o válce a obchodu.", + "Pirandello patří k moderně, která pochybuje o jedné pravdě postavy.", + "Beckettovo Čekání na Godota je 1952, tedy po válce.", + }; + + return lit_mcq_page(2, 2, "lit3unit3", "lit3_ex3_title", "lit3_quiz3_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit4_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Švejk", "Jaroslav Hašek", + "Tip: Švejk není jen vtip, je to obrana malého člověka proti mašinerii.", + { + "Osudy dobrého vojáka Švejka za světové války vyšly 1921–1923.", + "Hašek zesměšňuje rakouskou armádu, úřad a velkou frázi.", + "Švejk poslouchá tak doslova, až rozkaz ztrácí smysl.", + "Román zůstal nedokončený a přesto se stal světovým.", + NULL, + }, + }, + { + "2 / 3 • Legie", "Válka a legionářská próza", + "Tip: legionářská literatura vypráví anabázi československých legií.", + { + "Rudolf Medek a Josef Kopta píšou o legiích v Rusku.", + "Válka vstupuje i do Vančurova Pole orná a válečná.", + "Proti hrdinské legendě stojí Haškova groteska.", + "Oba póly, patos i výsměch, patří k české paměti první války.", + NULL, + }, + }, + { + "3 / 3 • Poezie", "Wolker a proletářská poezie", + "Tip: Wolker chce, aby báseň sloužila chudým a byla srozumitelná.", + { + "Jiří Wolker vydává Host do domu a Těžkou hodinu.", + "Balady, třeba Balada o nenarozeném dítěti, spojují sociální téma s lidovým tónem.", + "Proletářská poezie věří kolektivu a změně světa.", + "Devětsil, založený 1920, z ní brzy přejde k poetismu.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[3], "lit3_unit4", "lit3_unit4_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit4_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Osudy dobrého vojáka Švejka?", + {"Jaroslav Hašek", "Karel Čapek", "Jiří Wolker", "Viktor Dyk"}, + 4, 0}, + {"Jak Švejk vzdoruje armádě?", + {"Hrdinským útokem v čele legií", + "Doslovnou poslušností, která rozkaz zesměšní", + "Útěkem do exilu po roce 1968", + "Psaním manifestu moderny"}, + 4, 1}, + {"Které sbírky napsal Jiří Wolker?", + {"Host do domu a Těžká hodina", "Kytice a Máj", + "Květy zla a Havran", "Edison a Pásmo"}, + 4, 0}, + {"Co je Devětsil?", + {"Barokní řád", "Umělecký svaz založený roku 1920", + "Husitská píseň", "Nakladatelství exilu v Torontu"}, + 4, 1}, + }; + static const char *hints[] = { + "Švejk je Haškův nedokončený román z první války.", + "Groteskní poslušnost je Švejkova zbraň.", + "Wolker je hlavní básník proletářské poezie.", + "Z Devětsilu vyroste poetismus.", + }; + + return lit_mcq_page(2, 3, "lit3unit4", "lit3_ex4_title", "lit3_quiz4_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit5_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Poetismus", "Radost, město a asociace", + "Tip: poetismus je český směr, teoretikem je Karel Teige.", + { + "Poetismus chce báseň jako hru obrazů, cestu a oslavu moderního života.", + "Vítězslav Nezval píše Podivuhodného kouzelníka a Edison.", + "Jaroslav Seifert debutuje Na vlnách TSF a zůstane u konkrétního, smyslového verše.", + "Konstantin Biebl přidává exotiku a později smutek.", + NULL, + }, + }, + { + "2 / 3 • Surrealismus", "Sen a úzkost", + "Tip: Nezvalův Absolutní hrobař už není radostný poetismus.", + { + "Ve 30. letech část poetistů přechází k surrealismu.", + "Skupina surrealistů v ČSR vzniká 1934 kolem Nezvala.", + "Obraz se stává snovějším a úzkostnějším.", + "Vedle toho roste meditativní poezie, která avantgardu přijímá jen zčásti.", + NULL, + }, + }, + { + "3 / 3 • Jiný hlas", "Halas, Holan, Zahradníček", + "Tip: Halasova Torzo naděje je odpověď na Mnichov, ne na karneval města.", + { + "František Halas píše temnou, zhuštěnou lyriku a Torzo naděje.", + "Vladimír Holan je básník meditace a později svědectví.", + "Jan Zahradníček představuje spirituální a katolickou poezii.", + "Meziválečná poezie tedy není jen Devětsil: má i pól víry a úzkosti.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[4], "lit3_unit5", "lit3_unit5_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit5_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo je teoretikem poetismu?", + {"Karel Teige", "Josef Dobrovský", "Jan Hus", "Bertolt Brecht"}, + 4, 0}, + {"Kterou skladbu napsal Vítězslav Nezval?", + {"Edison", "Máj", "Kytice", "Babička"}, + 4, 0}, + {"Kdy vznikla Skupina surrealistů v ČSR?", + {"Roku 1858", "Roku 1934", "Roku 863", "Roku 1989"}, + 4, 1}, + {"Čím je Halasovo Torzo naděje?", + {"Poetistickou oslavou velkoměsta", + "Básnickou odpovědí na ohrožení republiky", + "Legionářským románem", + "Klasicistní komedií"}, + 4, 1}, + }; + static const char *hints[] = { + "Teige formuluje poetismus jako umění života.", + "Edison je Nezvalova pásmová báseň o vynálezci a noci.", + "1934 je rok českého surrealistického seskupení.", + "Torzo naděje reaguje na krizi konce 30. let.", + }; + + return lit_mcq_page(2, 4, "lit3unit5", "lit3_ex5_title", "lit3_quiz5_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit6_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Čapek", "Demokratický proud", + "Tip: Čapek brání obyčejného člověka a varuje před mocí, která se vymkne.", + { + "Karel Čapek píše R.U.R., kde zazní slovo robot, Krakatit a Válku s mloky.", + "Bílá nemoc a Matka jsou dramata o válce a odpovědnosti.", + "Hordubal, Povětroň a Obyčejný život jsou noetická trilogie: pravda není jedna.", + "Povídky z jedné a druhé kapsy a fejetony drží lidský rozměr.", + NULL, + }, + }, + { + "2 / 3 • Vančura", "Jazyk jako událost", + "Tip: Vančura píše obrazně a vědomě proti všednímu novinovému stylu.", + { + "Vladislav Vančura je autorem Rozmarného léta a Markéty Lazarové.", + "Jeho věta je rytmická, metaforická a často archaicky zbarvená.", + "Patří k levicové avantgardě, ale není schematický.", + "Vedle něj stojí reportážní a novinářská próza meziválečné demokracie.", + NULL, + }, + }, + { + "3 / 3 • Smích", "Poláček, Olbracht a další", + "Tip: Bylo nás pět je dětská perspektiva, která odhaluje svět dospělých.", + { + "Karel Poláček píše Bylo nás pět a Muže v offsidu.", + "Ivan Olbracht: Nikola Šuhaj loupežník a Golet v údolí.", + "Eduard Bass a Karel Poláček představují humoristickou a novinářskou linii.", + "Demokratický proud věří republice, rozumu a občanské slušnosti.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[5], "lit3_unit6", "lit3_unit6_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit6_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Ve kterém díle zazní slovo robot?", + {"V R.U.R. Karla Čapka", "V Máji", "V Kytici", "V Švejkovi"}, + 4, 0}, + {"Kdo napsal Rozmarné léto?", + {"Vladislav Vančura", "Jaroslav Hašek", "Božena Němcová", "Alois Jirásek"}, + 4, 0}, + {"Kterou knihu napsal Karel Poláček?", + {"Bylo nás pět", "Temno", "Labyrint světa", "Krysař"}, + 4, 0}, + {"O čem varuje Válka s mloky?", + {"O nebezpečí moci, která využije lidskou chtivost", + "O pravidlech sonetu", + "O příchodu věrozvěstů", + "O barokním emblému"}, + 4, 0}, + }; + static const char *hints[] = { + "Slovo robot vymyslel Josef Čapek, svět je zná z dramatu R.U.R.", + "Rozmarné léto a Markéta Lazarová jsou Vančurovy prózy.", + "Poláček je autor Bylo nás pět a Mužů v offsidu.", + "Mloci jsou podobenství o civilizaci, která si vypěstuje zhoubu.", + }; + + return lit_mcq_page(2, 5, "lit3unit6", "lit3_ex6_title", "lit3_quiz6_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit7_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Duše", "Psychologická próza", + "Tip: psychologická próza sleduje vnitřní motiv, ne jen vnější děj.", + { + "Jaroslav Havlíček píše Petrolejové lampy a Neviditelného.", + "Jarmila Glazarová v Adventu zobrazuje krutost a závislost na vesnici.", + "Egon Hostovský a Václav Řezáč přidávají úzkost a mravní selhání.", + "Člověk tu není typ vrstvy, ale spleť nutkání a vin.", + NULL, + }, + }, + { + "2 / 3 • Víra", "Katolický proud", + "Tip: katolická literatura není jen pobožnost, je to svébytný umělecký názor.", + { + "Jaroslav Durych píše historický román Bloudění.", + "Jakub Deml tvoří deníkovou a spirituální prózu.", + "Jan Čep a Jan Zahradníček drží venkov a víru jako řád.", + "Proud stojí vedle avantgardy a často s ní polemizuje.", + NULL, + }, + }, + { + "3 / 3 • Venkov", "Ruralismus", + "Tip: ruralismus idealizuje venkov jako zdroj řádu proti městu.", + { + "Ruralisté, třeba Josef Knap a František Křelina, brání selskou tradici.", + "Liší se od kritického realismu, který vesnici nešetřil.", + "Ve 30. letech je to vlivný, dnes diskutovaný proud.", + "Maturita má umět tyto proudy rozlišit, ne je slepit v jednu meziválečnou prózu.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[6], "lit3_unit7", "lit3_unit7_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit7_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Petrolejové lampy?", + {"Jaroslav Havlíček", "Karel Čapek", "Ivan Olbracht", "Jiří Wolker"}, + 4, 0}, + {"Kam patří Jaroslav Durych?", + {"Ke katolickému proudu", "K poetismu", + "Ke ztracené generaci", "K ruchovcům"}, + 4, 0}, + {"Co zdůrazňuje ruralismus?", + {"Velkoměstský kaleidoskop", + "Venkov a selský řád", + "Antickou tragédii", + "Absenci děje"}, + 4, 1}, + {"Čím se psychologická próza zabývá především?", + {"Vnitřním motivem a vinou postavy", + "Překladem antických eposů", + "Pravidly klasicistního verše", + "Kronikou Velké Moravy"}, + 4, 0}, + }; + static const char *hints[] = { + "Havlíček je autor Petrolejových lamp a Neviditelného.", + "Durychovo Bloudění je historický román katolického proudu.", + "Ruralismus staví vesnici proti rozkladnému městu.", + "Děj je tu hlavně cesta do nitra.", + }; + + return lit_mcq_page(2, 6, "lit3unit7", "lit3_ex7_title", "lit3_quiz7_head", + qs, hints, 4); +} + +static GtkWidget *build_lit3_unit8_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Okupace", "Literatura za protektorátu", + "Tip: po roce 1939 mizí svobodný tisk a řada autorů píše do šuplíku nebo umírá.", + { + "Německá okupace zavírá českou kulturu do cenzury a perzekuce.", + "Mladí básníci kolem Jiřího Ortena píšou elegii a deník ohroženého života.", + "Ortenovy sbírky, třeba Ohnice, vycházejí pod cizím jménem.", + "Halas, Holan a Seifert reagují na válku zhuštěným veršem.", + NULL, + }, + }, + { + "2 / 3 • Skupina", "Skupina 42", + "Tip: Skupina 42 bere město, periferii a civilní řeč, ne snový symbol.", + { + "Skupina 42 vzniká za války a programově se dívá na civilizaci města.", + "Patří k ní Josef Kainar, Jiří Kolář, Ivan Blatný a teoretik Jindřich Chalupecký.", + "Báseň i próza zaznamenávají banalitu, která je pod tlakem dějin přízračná.", + "Skupina působí i po válce, než ji politický režim umlčí.", + NULL, + }, + }, + { + "3 / 3 • Svědectví", "Co se o válce píše hned a co později", + "Tip: velké prózy o šoa často vzniknou až po roce 1945.", + { + "Za války vzniká poezie, deník a ilegální text, ne velký románový odstup.", + "Julius Fučík píše Reportáž psanou na oprátce ve vězení.", + "Lustig, Fuks, Hrabal nebo Otčenášek válku zpracují až v dalších desetiletích.", + "Na maturitu oddělte dobu vzniku od doby, o které dílo vypráví.", + NULL, + }, + }, + }; + + return lit_unit_page(2, &lit3_lessons[7], "lit3_unit8", "lit3_unit8_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit3_unit8_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo je básník Ohnice?", + {"Jiří Orten", "Jaroslav Seifert", "Vítězslav Nezval", "Petr Bezruč"}, + 4, 0}, + {"Čím se vyznačuje Skupina 42?", + {"Návratem ke klasicistní tragédii", + "Civilním pohledem na město a periferii", + "Venkovským ruralismem", + "Psaním jen v latině"}, + 4, 1}, + {"Kdo patří ke Skupině 42?", + {"Josef Kainar a Jiří Kolář", "Karel Hynek Mácha a Karel Jaromír Erben", + "Homér a Vergilius", "Jungmann a Dobrovský"}, + 4, 0}, + {"Proč velké romány o válce často nejsou z let okupace?", + {"Protože za cenzury a bez odstupu vznikala spíš poezie, deník a svědectví", + "Protože se o válce nesmělo psát ani po roce 1945", + "Protože próza vznikla až ve středověku", + "Protože autoři neznali téma města"}, + 4, 0}, + }; + static const char *hints[] = { + "Orten publikoval za okupace pod pseudonymem a zahynul roku 1941.", + "Program Skupiny 42 formuluje civilizační a městský pohled.", + "Kainar, Kolář a Blatný jsou její básníci.", + "Lustig, Fuks a další válečné prózy jsou poválečné.", + }; + + return lit_mcq_page(2, 7, "lit3unit8", "lit3_ex8_title", "lit3_quiz8_head", + qs, hints, 4); +} + +void add_lit3_pages(GtkStack *stack) { + typedef GtkWidget *(*LitBuilder)(void); + static const struct { + const char *unit_name; + const char *ex_name; + LitBuilder build_unit; + LitBuilder build_ex; + } pages[] = { + {"lit3unit1", "lit3ex1", build_lit3_unit1_page, build_lit3_unit1_exercise_page}, + {"lit3unit2", "lit3ex2", build_lit3_unit2_page, build_lit3_unit2_exercise_page}, + {"lit3unit3", "lit3ex3", build_lit3_unit3_page, build_lit3_unit3_exercise_page}, + {"lit3unit4", "lit3ex4", build_lit3_unit4_page, build_lit3_unit4_exercise_page}, + {"lit3unit5", "lit3ex5", build_lit3_unit5_page, build_lit3_unit5_exercise_page}, + {"lit3unit6", "lit3ex6", build_lit3_unit6_page, build_lit3_unit6_exercise_page}, + {"lit3unit7", "lit3ex7", build_lit3_unit7_page, build_lit3_unit7_exercise_page}, + {"lit3unit8", "lit3ex8", build_lit3_unit8_page, build_lit3_unit8_exercise_page}, + }; + + for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { + gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); + gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); + } +} diff --git a/src/lit_year4.c b/src/lit_year4.c new file mode 100644 index 0000000..ac167da --- /dev/null +++ b/src/lit_year4.c @@ -0,0 +1,631 @@ +#include "graduately.h" + +/* Year 4: literature after 1945, Czech writing under censorship and after + * 1989, and how to interpret a text at the school-leaving exam. */ + +NetLesson lit4_lessons[LIT_N] = { + { .n_slides = 3, .unit_page = "lit4unit1", .ex_page = "lit4ex1" }, + { .n_slides = 3, .unit_page = "lit4unit2", .ex_page = "lit4ex2" }, + { .n_slides = 3, .unit_page = "lit4unit3", .ex_page = "lit4ex3" }, + { .n_slides = 3, .unit_page = "lit4unit4", .ex_page = "lit4ex4" }, + { .n_slides = 3, .unit_page = "lit4unit5", .ex_page = "lit4ex5" }, + { .n_slides = 3, .unit_page = "lit4unit6", .ex_page = "lit4ex6" }, + { .n_slides = 3, .unit_page = "lit4unit7", .ex_page = "lit4ex7" }, + { .n_slides = 3, .unit_page = "lit4unit8", .ex_page = "lit4ex8" }, +}; + +static GtkWidget *build_lit4_unit1_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Po válce", "Svět, který už nevěří velkým frázím", + "Tip: antiutopie varuje před státem, který ovládne pravdu i soukromí.", + { + "Druhá světová válka a totalitní režimy mění téma viny, moci a paměti.", + "George Orwell píše Farmu zvířat a román 1984.", + "Ray Bradbury v 451 stupních Fahrenheita brání knihu proti cenzuře.", + "William Golding v Pánu much ukazuje, jak rychle se zboří civilizovaný řád.", + NULL, + }, + }, + { + "2 / 3 • Hlasy", "Existencialismus, beatnici a magický realismus", + "Tip: existencialismus říká, že člověk je svoboda a musí volit bez hotové opory.", + { + "Albert Camus píše Cizince a Mor, Jean-Paul Sartre Nevolnost.", + "Jack Kerouac v románu Na cestě dává hlas beat generation.", + "Gabriel García Márquez ve Sto rocích samoty mísí skutečnost a zázrak.", + "Jorge Luis Borges staví povídku jako filozofickou hru s nekonečnem.", + NULL, + }, + }, + { + "3 / 3 • Východ", "Svědectví o nesvobodě", + "Tip: Solženicyn a Bulgakov se čtou jako literatura i jako svědectví.", + { + "Alexandr Solženicyn v Jednom dni Ivana Děnisoviče otevírá téma lágru.", + "Michail Bulgakov hájí v Mistrovi a Markétce umění proti strachu.", + "Joseph Heller v Hlavě XXII zesměšňuje válečnou byrokracii.", + "Poválečná próza tedy není jeden styl, ale několik odpovědí na stejné století.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[0], "lit4_unit1", "lit4_unit1_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit1_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal román 1984?", + {"George Orwell", "Ray Bradbury", "Albert Camus", "Umberto Eco"}, + 4, 0}, + {"O čem je 451 stupňů Fahrenheita?", + {"O cenzuře a pálení knih", "O národním obrození", + "O antickém osudu", "O husitské písni"}, + 4, 0}, + {"Který román patří Gabrielu Garcíovi Márquezovi?", + {"Sto roků samoty", "Babička", "Evžen Oněgin", "R.U.R."}, + 4, 0}, + {"Co je existencialismus v próze Camuse a Sartra?", + {"Víra, že osud je předem dán bohy", + "Důraz na svobodu volby, absurditu a odpovědnost", + "Návrat ke třem jednotám", + "Popis venkova bez psychologie"}, + 4, 1}, + }; + static const char *hints[] = { + "Orwell: Farma zvířat a 1984. Bradbury: 451 stupňů Fahrenheita.", + "Hasiči u Bradburyho knihy pálí, lidé je zachraňují tím, že je umějí zpaměti.", + "Sto roků samoty je základní román magického realismu.", + "Cizinec a Mor jsou Camusovy, Nevolnost Sartrova.", + }; + + return lit_mcq_page(3, 0, "lit4unit1", "lit4_ex1_title", "lit4_quiz1_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit2_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Absurdita", "Čekání, které nekončí", + "Tip: v absurdním dramatu se děj neuzavře, protože svět sám nedává smysl.", + { + "Samuel Beckett v Čekání na Godota nechává dva tuláky čekat na někoho, kdo nepřijde.", + "Eugene Ionesco v Plešaté zpěvačce rozkládá obyčejnou řeč.", + "Postavy jednají, ale jejich jednání cíl nenaplní.", + "Smích a hrůza tu nejsou oddělené.", + NULL, + }, + }, + { + "2 / 3 • Myšlenka", "Sartre, Dürrenmatt a podobenství", + "Tip: Návštěva staré dámy je podobenství o tom, zač je město ochotné prodat spravedlnost.", + { + "Sartrovy Mouchy a S vyloučením veřejnosti jsou existencialistická dramata.", + "Friedrich Dürrenmatt píše Návštěvu staré dámy a Fyziky.", + "Podobenství dovoluje mluvit o vině, aniž hra kopíruje noviny.", + "Divadlo po roce 1945 často soudí diváka spolu s postavou.", + NULL, + }, + }, + { + "3 / 3 • Postmoderna", "Hra s tím, co už bylo napsáno", + "Tip: postmoderna cituje starší texty a nedůvěřuje jedinému velkému výkladu.", + { + "Umberto Eco v Jménu růže spojuje detektivku, středověk a učenou hru.", + "Intertextualita znamená, že dílo vědomě navazuje na jiná díla.", + "Vypravěč může být nespolehlivý a závěr otevřený.", + "Na maturitě postmoderu poznáte podle ironie, citace a pochybnosti o jedné pravdě.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[1], "lit4_unit2", "lit4_unit2_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit2_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Čekání na Godota?", + {"Samuel Beckett", "Molière", "William Shakespeare", "Karel Čapek"}, + 4, 0}, + {"Co je typické pro absurdní drama?", + {"Jasný hrdinský konec", + "Jednání, které nevede k smysluplnému završení", + "Dodržení tří jednot", + "Jen historický námět z antiky"}, + 4, 1}, + {"Kdo napsal Návštěvu staré dámy?", + {"Friedrich Dürrenmatt", "Bertolt Brecht", + "Václav Havel", "Victor Hugo"}, + 4, 0}, + {"Čím se vyznačuje Jméno růže?", + {"Je to barokní kázání", + "Postmoderní román, který spojuje detektivku a středověk", + "Proletářská balada", + "Klasicistní tragédie"}, + 4, 1}, + }; + static const char *hints[] = { + "Beckettovo Čekání na Godota je základní absurdní drama.", + "Godot nepřijde a čekání se opakuje.", + "Dürrenmattova hra zkoumá, za co obec prodá svědomí.", + "Eco pracuje s citací, ironií a učenou hrou.", + }; + + return lit_mcq_page(3, 1, "lit4unit2", "lit4_ex2_title", "lit4_quiz2_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit3_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • 1945–1948", "Krátká svoboda", + "Tip: mezi květnem 1945 a únorem 1948 ještě vedle sebe žijí různé směry.", + { + "Po válce se vracejí zakázaní autoři a vycházejí odložené rukopisy.", + "Skupina 42 ještě působí, katolická literatura má poslední veřejný prostor.", + "Zároveň sílí požadavek, aby umění sloužilo nové moci.", + "Únor 1948 tento spor rozhodne politicky.", + NULL, + }, + }, + { + "2 / 3 • Schematismus", "Budovatelský román", + "Tip: schematická postava nemá pochybnost, protože dějiny už mají vyhráno.", + { + "Na počátku 50. let vládne socialistický realismus a budovatelský román.", + "Hrdina je dělník nebo funkcionář, konflikt je mezi pokrokem a zpátečníkem.", + "Jazyk je průhledný, závěr optimistický, kritika režimu nemožná.", + "Mnoho autorů starších generací mlčí, překládá, nebo píše do zásuvky.", + NULL, + }, + }, + { + "3 / 3 • 1956", "První trhlina", + "Tip: rok 1956 je kritika kultu osobnosti a počátek opatrného uvolnění.", + { + "II. sjezd spisovatelů a světové události narušují jistotu schématu.", + "Časopis Květen a poezie všedního dne vracejí do verše obyčejný život.", + "Ještě to není svoboda 60. let, ale konec nejtvrdšího schématu.", + "Na maturitu odlište budovatelský román od literatury, která přišla po něm.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[2], "lit4_unit3", "lit4_unit3_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit3_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co se v české literatuře děje po únoru 1948?", + {"Návrat ke klasicismu", + "Nástup socialistického realismu a budovatelského románu", + "Vznik poetismu", + "Konec cenzury"}, + 4, 1}, + {"Čím je schematická postava?", + {"Má jednoznačnou politickou roli a nepochybuje", + "Je romantický vyvrženec", + "Je vypravěč v ich-formě antického eposu", + "Je autor Bible kralické"}, + 4, 0}, + {"Co znamená rok 1956 pro českou literaturu?", + {"Založení Devětsilu", + "Kritiku kultu osobnosti a první uvolnění schématu", + "Příchod Konstantina a Metoděje", + "Vydání Máje"}, + 4, 1}, + {"Kdy končí krátké poválečné období otevřenější kultury?", + {"Únorem 1948", "Manifestem české moderny", + "Almanachem Máj", "Rokem 863"}, + 4, 0}, + }; + static const char *hints[] = { + "Budovatelský román je oficiální žánr počátku 50. let.", + "Schéma dělí postavy na kladné a záporné podle vztahu k režimu.", + "1956 oslabuje kult osobnosti, svoboda 60. let přijde později.", + "Únor 1948 je politický zlom, po němž mizí nezávislé proudy z veřejné scény.", + }; + + return lit_mcq_page(3, 2, "lit4unit3", "lit4_ex3_title", "lit4_quiz3_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit4_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Uvolnění", "Léta, kdy se smělo víc", + "Tip: 60. léta nejsou bez cenzury, ale cenzura polevila a experiment se vrátil.", + { + "Literatura znovu zkouší formu, ironii a tabuizovaná témata.", + "Válka, stalinismus i soukromí se dají pojmenovat otevřeněji.", + "Vrcholí to Pražským jarem 1968 a končí srpnovou okupací.", + "Mnoho knih, které tehdy vznikly, později vyjde jen v samizdatu nebo v exilu.", + NULL, + }, + }, + { + "2 / 3 • Próza", "Hrabal, Kundera, Škvorecký", + "Tip: pábitel je Hrabalův vypravěč, který skutečnost přetaví v proud řeči.", + { + "Bohumil Hrabal píše Pábitelé, Ostře sledované vlaky a Taneční hodiny.", + "Milan Kundera vydává Směšné lásky a Žert.", + "Josef Škvorecký v Zbabělcích vypráví konec války očima mladíka.", + "Arnošt Lustig a Ladislav Fuks vracejí téma šoa: Modlitba pro Kateřinu Horovitzovou, Spalovač mrtvol.", + NULL, + }, + }, + { + "3 / 3 • Kritika", "Vaculík, Páral a meze svobody", + "Tip: Žert ukazuje, jak jedna věta a jeden režim zničí život.", + { + "Ludvík Vaculík píše Sekyru a později Dva tisíce slov.", + "Vladimír Páral zachycuje konzumní stereotyp.", + "Divadlo a film 60. let jdou s literaturou ruku v ruce.", + "Okupace 1968 tuto vlnu utne a rozdělí autory na oficiální, samizdat a exil.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[3], "lit4_unit4", "lit4_unit4_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit4_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdo napsal Ostře sledované vlaky?", + {"Bohumil Hrabal", "Milan Kundera", "Josef Škvorecký", "Ladislav Fuks"}, + 4, 0}, + {"Který román napsal Milan Kundera v 60. letech?", + {"Žert", "Babička", "Temno", "1984"}, + 4, 0}, + {"O čem jsou Zbabělci Josefa Škvoreckého?", + {"O konci války v českém městě očima mladíka", + "O barokním exilu Komenského", + "O antickém osudu", + "O národním obrození"}, + 4, 0}, + {"Kdo napsal Spalovače mrtvol?", + {"Ladislav Fuks", "Jiří Wolker", "Karel Jaromír Erben", "Victor Hugo"}, + 4, 0}, + }; + static const char *hints[] = { + "Hrabal: Ostře sledované vlaky, Pábitelé, později Obsluhoval jsem anglického krále.", + "Žert je Kunderův román o trestu za vtip.", + "Zbabělci vyšli na konci 50. let a patří k uvolnění.", + "Fuksův Spalovač mrtvol ukazuje, jak se obyčejný člověk stane nástrojem zla.", + }; + + return lit_mcq_page(3, 3, "lit4unit4", "lit4_ex4_title", "lit4_quiz4_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit5_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Tři proudy", "Normalizace", + "Tip: po roce 1968 se česká literatura dělí na oficiální, samizdatovou a exilovou.", + { + "Normalizace vyřazuje nepohodlné autory z nakladatelství, novin i zaměstnání.", + "Oficiální scéna tiskne jen to, co projde cenzurou.", + "Samizdat opisuje rukopisy, známá je Vaculíkova Edice Petlice.", + "Exil vydává v cizině, Škvoreckého nakladatelství 68 Publishers vzniká v Torontu.", + NULL, + }, + }, + { + "2 / 3 • Autoři", "Kdo kam patří", + "Tip: jeden autor může v různých letech stát na různých stranách této hranice.", + { + "V exilu publikují Kundera, Škvorecký, Pavel Kohout a další.", + "V samizdatu píšou Václav Havel, Ludvík Vaculík, Ivan Klíma a Jiří Gruša.", + "Hrabal po nucených úpravách zčásti vychází oficiálně a zároveň koluje v opisech.", + "Underground, Egon Bondy a Ivan Jirous, stojí mimo oficiální kulturu zcela.", + NULL, + }, + }, + { + "3 / 3 • Charta", "Literatura a občanský postoj", + "Tip: Charta 77 není román, ale bez ní nelze normalizaci vysvětlit.", + { + "Charta 77 žádá dodržování práv, která stát sám podepsal.", + "Mnoho signatářů jsou spisovatelé a zakázaní autoři.", + "Čtení samizdatu je v té době čin, ne jen záliba.", + "Na maturitu vždy řekněte, v kterém z tří proudů dílo vyšlo.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[4], "lit4_unit5", "lit4_unit5_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit5_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Jak se dělí česká literatura v normalizaci?", + {"Na lyriku, epiku a drama", + "Na oficiální tvorbu, samizdat a exil", + "Na ruchovce a lumírovce", + "Na antiku a středověk"}, + 4, 1}, + {"Co je Edice Petlice?", + {"Samizdatová edice Ludvíka Vaculíka", + "Oficiální nakladatelství 50. let", + "Barokní tiskárna", + "Almanach májovců"}, + 4, 0}, + {"Kde působilo nakladatelství 68 Publishers?", + {"V Torontu", "V Praze jako oficiální dům", + "Na Velké Moravě", "V Národním divadle"}, + 4, 0}, + {"Kdo patří k undergroundu normalizace?", + {"Egon Bondy a Ivan Jirous", "Josef Dobrovský a Josef Jungmann", + "Homér a Sofoklés", "Božena Němcová a Karel Jaromír Erben"}, + 4, 0}, + }; + static const char *hints[] = { + "Tři okruhy publikování jsou základní schéma učebnic.", + "Petlici řídil Vaculík, opisy šly z ruky do ruky.", + "68 Publishers založili Škvorecký a Zdena Salivarová.", + "Underground odmítá oficiální kulturu i její kompromisy.", + }; + + return lit_mcq_page(3, 4, "lit4unit5", "lit4_ex5_title", "lit4_quiz5_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit6_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Verš", "Poezie po roce 1945", + "Tip: Seifert dostal Nobelovu cenu roku 1984, v době, kdy doma nebyl režimní básník.", + { + "Jaroslav Seifert píše po válce intimní a paměťovou lyriku, Morový sloup vychází v samizdatu.", + "Jan Skácel a Miroslav Holub představují dvě polohy: něhu a věcnou metaforu.", + "Oficiální poezie 50. let je agitační, později se vrací civilní tón.", + "Písničkáři Karel Kryl, Jaromír Nohavica a Vladimír Merta nesou verš mimo knižní cenzuru.", + NULL, + }, + }, + { + "2 / 3 • Havel", "Drama, které mluví o moci řeči", + "Tip: Zahradní slavnost ukazuje, jak fráze pohltí člověka.", + { + "Václav Havel debutuje Zahradní slavností a Vyrozuměním.", + "Audience, Vernisáž a Protest jsou jednoaktovky o přizpůsobení.", + "Havel navazuje na absurdní drama, ale dá mu konkrétní českou situaci.", + "Hry kolují v samizdatu a hrají se v cizině, doma dlouho ne.", + NULL, + }, + }, + { + "3 / 3 • Jeviště", "Semafor, Cimrman a autorské divadlo", + "Tip: Divadlo Járy Cimrmana si vymyslelo génia, aby se smělo smát dějinám.", + { + "Malá divadla 60. let, Semafor a další, vracela jevišti písničku a improvizaci.", + "Zdeněk Svěrák a Ladislav Smoljak vytvářejí hry o Járovi Cimrmanovi.", + "České nebe později shrne národní mýty s nadsázkou.", + "Poezie a drama této doby často říkají víc mezi řádky než v hesle.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[5], "lit4_unit6", "lit4_unit6_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit6_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Kdy dostal Jaroslav Seifert Nobelovu cenu?", + {"Roku 1895", "Roku 1984", "Roku 1836", "Roku 1415"}, + 4, 1}, + {"Kterou hru napsal Václav Havel?", + {"Zahradní slavnost", "Maryša", "Lakomec", "Noc na Karlštejně"}, + 4, 0}, + {"Co jsou Audience a Vernisáž?", + {"Havlovy jednoaktovky o přizpůsobení", + "Erbenovy balady", + "Legionářské romány", + "Klasicistní tragédie"}, + 4, 0}, + {"Kdo vytvořil Divadlo Járy Cimrmana?", + {"Zdeněk Svěrák a Ladislav Smoljak", + "Karel a Josef Čapkovi", + "Alois a Vilém Mrštíkové", + "Vítězslav Nezval a Karel Teige"}, + 4, 0}, + }; + static const char *hints[] = { + "Nobelova cena za literaturu 1984 patří Seifertovi.", + "Zahradní slavnost je Havlova první velká hra.", + "Audience se odehrává v pivovaře a ukazuje tlak na zakázaného spisovatele.", + "Cimrman je mystifikace, která paroduje národní dějiny.", + }; + + return lit_mcq_page(3, 5, "lit4unit6", "lit4_ex6_title", "lit4_quiz6_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit7_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • 1989", "Konec cenzury", + "Tip: po listopadu se najednou tiskne to, co čtyřicet let chodilo v opisech.", + { + "Samizdat a exil se vracejí do knihkupectví.", + "Čtenář dohání Kundera, Škvoreckého, Havla i zapadlé básníky.", + "Zároveň vzniká trh: kniha se musí i prodat.", + "Literatura ztrácí roli jediného místa, kde se říkala pravda.", + NULL, + }, + }, + { + "2 / 3 • Próza", "Viewegh, Topol a další", + "Tip: Báječná léta pod psa jsou generační vzpomínka na normalizaci, napsaná už svobodně.", + { + "Michal Viewegh v Báječných letech pod psa spojuje rodinnou kroniku a humor.", + "Jáchym Topol v Sestře píše syrovým, téměř mluveným jazykem o podzemí a svobodě.", + "Michal Ajvaz, Miloš Urban a Petra Hůlová ukazují, jak se próza rozběhla do různých směrů.", + "Autobiografie, groteska i náročný experiment stojí vedle sebe.", + NULL, + }, + }, + { + "3 / 3 • Dnešek", "Co z toho plyne pro školu", + "Tip: současný text se čte stejně poctivě jako klasika: druh, jazyk, kontext.", + { + "Po roce 1989 už nelze mluvit o jednom oficiálním stylu.", + "Poezie žije i mimo velká nakladatelství, na čteních a na webu.", + "Drama se vrací na scény, které čtyřicet let nesměly hrát zakázané hry.", + "Maturita žádá, abyste současnost uměli zařadit, ne jen převyprávět.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[6], "lit4_unit7", "lit4_unit7_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit7_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Co se s literaturou stalo po roce 1989?", + {"Cenzura zesílila", + "Skončila cenzura a vrátily se samizdat a exil", + "Zanikla veškerá próza", + "Povinně se psal jen budovatelský román"}, + 4, 1}, + {"Kdo napsal Báječná léta pod psa?", + {"Michal Viewegh", "Bohumil Hrabal", "Karel Hynek Mácha", "Jan Neruda"}, + 4, 0}, + {"Který román napsal Jáchym Topol?", + {"Sestra", "Babička", "Máj", "Král Oidipus"}, + 4, 0}, + {"Proč literatura po roce 1989 ztratila výsadní politickou roli?", + {"Protože pravda se směla říkat i jinde než v opisech", + "Protože zanikl český jazyk", + "Protože se vrátila jen latina", + "Protože maturita literaturu zrušila"}, + 4, 0}, + }; + static const char *hints[] = { + "Listopad 1989 otevírá nakladatelství i archivy.", + "Vieweghova kniha je humoristická kronika normalizace.", + "Sestra je syrový román o svobodě po roce 1989.", + "Dokud byla cenzura, kniha často nahrazovala veřejnou debatu.", + }; + + return lit_mcq_page(3, 6, "lit4unit7", "lit4_ex7_title", "lit4_quiz7_head", + qs, hints, 4); +} + +static GtkWidget *build_lit4_unit8_page(void) { + static const NetSlide slides[] = { + { + "1 / 3 • Postup", "Jak číst text k maturitě", + "Tip: nejdřív řekněte, co text je, teprve potom, co si o něm myslíte.", + { + "Určete literární druh a žánr a dobu, do které text patří.", + "Pojmenujte téma a hlavní motivy, ne jen děj větu po větě.", + "U prózy si všimněte vypravěče, kompozice a postav.", + "U lyriky rozlište autora a lyrický subjekt.", + NULL, + }, + }, + { + "2 / 3 • Jazyk", "Čím text působí", + "Tip: jeden konkrétní prostředek, který umíte pojmenovat, je víc než obecná chvála.", + { + "Hledejte metaforu, přirovnání, symbol, kontrast nebo opakování.", + "U verše určete rým, stopu, nebo řekněte, že jde o volný verš.", + "Všimněte si slovníku: knižní, hovorový, biblický, ironický.", + "Kompozice může být chronologická, retrospektivní, nebo pásmo obrazů.", + NULL, + }, + }, + { + "3 / 3 • Kontext", "Text není ostrov", + "Tip: vlastní názor má stát na textu, ne místo něj.", + { + "Zařaďte ukázku k autorovi, směru a historické situaci.", + "Srovnání s jiným dílem ukáže, že látce rozumíte.", + "Řekněte, co text sděluje dnes, a opřete to o konkrétní místo.", + "Struktura odpovědi: zařazení, téma, jazyk, kontext, vlastní soud.", + NULL, + }, + }, + }; + + return lit_unit_page(3, &lit4_lessons[7], "lit4_unit8", "lit4_unit8_sub", + slides, G_N_ELEMENTS(slides)); +} + +static GtkWidget *build_lit4_unit8_exercise_page(void) { + static const ChoiceQ qs[] = { + {"Čím má začít rozbor textu?", + {"Určením druhu, žánru a doby", + "Převyprávěním celého dějepisu", + "Vlastním dojmem bez textu", + "Seznamem všech autorů století"}, + 4, 0}, + {"Koho nesmíme zaměnit v lyrice?", + {"Autora a lyrický subjekt", + "Nakladatele a tiskaře", + "Čtenáře a cenzora", + "Rým a stopu"}, + 4, 0}, + {"Co je volný verš?", + {"Verš vázaný povinným sdruženým rýmem", + "Verš bez pravidelného rýmu a stopy", + "Jen antický hexametr", + "Dramatická replika"}, + 4, 1}, + {"Jak má vypadat vlastní názor u maturity?", + {"Má nahradit rozbor", + "Má vycházet z konkrétního místa v textu", + "Má být co nejdelší bez argumentu", + "Má zůstat nevysloven"}, + 4, 1}, + }; + static const char *hints[] = { + "Zařazení je rám, bez kterého jazykový rozbor visí ve vzduchu.", + "Lyrický subjekt je hlas básně, ne automaticky občanský průkaz autora.", + "Volný verš je běžný od avantgardy po současnost.", + "Soud bez citace z textu maturita nepočítá jako rozbor.", + }; + + return lit_mcq_page(3, 7, "lit4unit8", "lit4_ex8_title", "lit4_quiz8_head", + qs, hints, 4); +} + +void add_lit4_pages(GtkStack *stack) { + typedef GtkWidget *(*LitBuilder)(void); + static const struct { + const char *unit_name; + const char *ex_name; + LitBuilder build_unit; + LitBuilder build_ex; + } pages[] = { + {"lit4unit1", "lit4ex1", build_lit4_unit1_page, build_lit4_unit1_exercise_page}, + {"lit4unit2", "lit4ex2", build_lit4_unit2_page, build_lit4_unit2_exercise_page}, + {"lit4unit3", "lit4ex3", build_lit4_unit3_page, build_lit4_unit3_exercise_page}, + {"lit4unit4", "lit4ex4", build_lit4_unit4_page, build_lit4_unit4_exercise_page}, + {"lit4unit5", "lit4ex5", build_lit4_unit5_page, build_lit4_unit5_exercise_page}, + {"lit4unit6", "lit4ex6", build_lit4_unit6_page, build_lit4_unit6_exercise_page}, + {"lit4unit7", "lit4ex7", build_lit4_unit7_page, build_lit4_unit7_exercise_page}, + {"lit4unit8", "lit4ex8", build_lit4_unit8_page, build_lit4_unit8_exercise_page}, + }; + + for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { + gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); + gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); + } +} diff --git a/src/literatura.c b/src/literatura.c new file mode 100644 index 0000000..57784dd --- /dev/null +++ b/src/literatura.c @@ -0,0 +1,947 @@ +#include "graduately.h" + +/* Literature for Český jazyk a literatura. + * Four years follow the chronology used in secondary-school syllabi + * (RVP G, literární komunikace, and RVP for vocational schools, + * estetické vzdělávání): antiquity through the present, then a lesson + * on interpreting a text. Each lesson is a short overview and a quiz. */ + +typedef struct { + const char *map_page; + const char *back_page; + const char *title_key; + const char *sub_key; + const char *unit_keys[LIT_N]; + char **progress_path; + NetLesson *lessons; + GtkWidget *scroll; + GtkWidget *fixed; + GtkWidget *rail; + GtkWidget *nodes[LIT_N]; + GtkWidget *labels[LIT_N]; + double cx[LIT_N]; + double cy[LIT_N]; + int cols; + int rows; + int cw; + int ch; + guint idle; + double last_avail; + int last_cols; + int last_rows; + int last_cw; + int last_ch; + cairo_surface_t *rail_cache; + int cache_w; + int cache_h; + int note_last_w; +} LitTrack; + +static LitTrack lit_tracks[4]; + +static void lit_ensure(void); + +static void lit_point(LitTrack *T, double t, double *ox, double *oy) { + int k = (int)t; + double u = t - (double)k; + double u2, u3; + double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; + + if (k < 0) { k = 0; u = 0.0; } + if (k >= LIT_N - 1) { k = LIT_N - 2; u = 1.0; } + + p1x = T->cx[k]; p1y = T->cy[k]; + p2x = T->cx[k + 1]; p2y = T->cy[k + 1]; + if (k - 1 >= 0) { p0x = T->cx[k - 1]; p0y = T->cy[k - 1]; } + else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } + if (k + 2 < LIT_N) { p3x = T->cx[k + 2]; p3y = T->cy[k + 2]; } + else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } + + u2 = u * u; + u3 = u2 * u; + *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u + + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 + + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); + *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u + + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 + + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); +} + +static void lit_path(LitTrack *T, cairo_t *cr, double t0, double t1) { + const double steps_per_unit = 24.0; + int n = (int)((t1 - t0) * steps_per_unit); + double x, y; + int s; + + if (n < 1) + n = 1; + lit_point(T, t0, &x, &y); + cairo_move_to(cr, x, y); + for (s = 1; s <= n; s++) { + lit_point(T, t0 + (t1 - t0) * (double)s / (double)n, &x, &y); + cairo_line_to(cr, x, y); + } +} + +static void lit_geometry(LitTrack *T, double avail) { + const double phase = 2.0 * G_PI * 1.7 / (double)(LIT_N - 1); + int rows; + int r, c, i; + + for (rows = 1; rows <= LIT_N; rows++) { + int cols = (LIT_N + rows - 1) / rows; + if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) + break; + } + if (rows > LIT_N) + rows = LIT_N; + T->rows = rows; + T->cols = (LIT_N + rows - 1) / rows; + if (T->cols < 1) + T->cols = 1; + T->cw = (int)(2.0 * ROAD_MX + (T->cols - 1) * PATH_SPAC); + T->ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); + + for (r = 0; r < rows; r++) { + int base = r * T->cols; + int len = MIN(T->cols, LIT_N - base); + int fwd = (r % 2) == 0; + for (c = 0; c < len; c++) { + int cc = fwd ? c : (T->cols - 1 - c); + i = base + c; + T->cx[i] = ROAD_MX + cc * PATH_SPAC; + T->cy[i] = ROAD_MY + r * ROAD_GAP + + ROAD_WAVE * sin((double)i * phase); + } + } +} + +static void lit_apply_layout(LitTrack *T) { + if (!T->fixed) + return; + if (T->cols == T->last_cols && T->rows == T->last_rows && + T->cw == T->last_cw && T->ch == T->last_ch) + return; + + T->last_cols = T->cols; + T->last_rows = T->rows; + T->last_cw = T->cw; + T->last_ch = T->ch; + if (T->rail_cache) { + cairo_surface_destroy(T->rail_cache); + T->rail_cache = NULL; + } + + for (int i = 0; i < LIT_N; i++) { + if (!T->nodes[i] || !T->labels[i]) + continue; + gtk_fixed_move(GTK_FIXED(T->fixed), T->nodes[i], + (int)(T->cx[i] - NODE_SIZE / 2.0), + (int)(T->cy[i] - NODE_SIZE / 2.0)); + gtk_fixed_move(GTK_FIXED(T->fixed), T->labels[i], + (int)(T->cx[i] - (PATH_SPAC - 20.0) / 2.0), + (int)(T->cy[i] + NODE_SIZE / 2.0 + 10.0)); + } + + gtk_widget_set_size_request(T->fixed, T->cw, T->ch); + gtk_widget_set_size_request(T->rail, T->cw, T->ch); + gtk_fixed_move(GTK_FIXED(T->fixed), T->rail, 0, 0); + gtk_widget_queue_draw(T->rail); +} + +static void lit_relayout(LitTrack *T) { + GtkAdjustment *hadj; + double avail; + + if (!T->scroll) + return; + hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(T->scroll)); + avail = gtk_adjustment_get_page_size(hadj); + if (avail < 1.0) + return; + if (fabs(avail - T->last_avail) < 1.0) + return; + T->last_avail = avail; + lit_geometry(T, avail); + lit_apply_layout(T); +} + +static gboolean lit_relayout_idle(gpointer data) { + LitTrack *T = data; + + T->idle = 0; + lit_relayout(T); + return G_SOURCE_REMOVE; +} + +static void lit_relayout_later(LitTrack *T) { + if (T->idle == 0) + T->idle = g_idle_add(lit_relayout_idle, T); +} + +static void lit_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, + gpointer data) { + (void)adj; + (void)ps; + lit_relayout_later(data); +} + +static void lit_render_rail(LitTrack *T, cairo_t *cr) { + const double t_end = (double)(LIT_N - 1); + const Rgb rail = color_from_hex(app_theme.rail); + const Rgb muted = color_from_hex(app_theme.subtext); + + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); + + cairo_new_path(cr); + lit_path(T, cr, 0.0, t_end); + cairo_set_line_width(cr, 12); + cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); + cairo_stroke(cr); + + cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); + cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); + cairo_new_path(cr); + lit_path(T, cr, 0.0, t_end); + cairo_stroke(cr); + cairo_set_dash(cr, NULL, 0, 0.0); +} + +static void lit_draw_rail(GtkDrawingArea *area, cairo_t *cr, + int width, int height, gpointer data) { + LitTrack *T = data; + cairo_t *rcr; + + (void)area; + (void)width; + (void)height; + + if (!T->rail_cache || T->cache_w != T->cw || T->cache_h != T->ch) { + if (T->rail_cache) + cairo_surface_destroy(T->rail_cache); + T->cache_w = T->cw > 0 ? T->cw : 1; + T->cache_h = T->ch > 0 ? T->ch : 1; + T->rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + T->cache_w, T->cache_h); + rcr = cairo_create(T->rail_cache); + lit_render_rail(T, rcr); + cairo_destroy(rcr); + } + + cairo_set_source_surface(cr, T->rail_cache, 0, 0); + cairo_paint(cr); +} + +void lit_rail_theme_reset(void) { + for (int y = 0; y < 4; y++) { + LitTrack *T = &lit_tracks[y]; + + if (T->rail_cache) { + cairo_surface_destroy(T->rail_cache); + T->rail_cache = NULL; + } + if (T->rail) + gtk_widget_queue_draw(T->rail); + } +} + +static void lit_save(LitTrack *T) { + GKeyFile *kf; + char *path; + gchar *data; + + if (!T->progress_path || !*T->progress_path) + return; + path = *T->progress_path; + kf = g_key_file_new(); + for (int i = 0; i < LIT_N; i++) { + gchar key[8]; + + g_snprintf(key, sizeof(key), "%d", i + 1); + g_key_file_set_boolean(kf, "done", key, T->lessons[i].done); + } + if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { + g_key_file_free(kf); + return; + } + data = g_key_file_to_data(kf, NULL, NULL); + g_key_file_free(kf); + if (data) { + GError *err = NULL; + + g_file_set_contents(path, data, -1, &err); + if (err) + g_error_free(err); + g_free(data); + } +} + +static void lit_load_one(LitTrack *T) { + GKeyFile *kf; + GError *err = NULL; + const char *path; + + if (!T->progress_path || !*T->progress_path) + return; + path = *T->progress_path; + kf = g_key_file_new(); + if (!g_key_file_load_from_file(kf, path, G_KEY_FILE_NONE, &err)) { + if (err) + g_error_free(err); + g_key_file_free(kf); + return; + } + for (int i = 0; i < LIT_N; i++) { + gchar key[8]; + + g_snprintf(key, sizeof(key), "%d", i + 1); + T->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); + } + g_key_file_free(kf); +} + +void lit_load_progress(void) { + lit_ensure(); + for (int y = 0; y < 4; y++) + lit_load_one(&lit_tracks[y]); +} + +static void lit_refresh(LitTrack *T) { + for (int i = 0; i < LIT_N; i++) { + GtkWidget *node = T->nodes[i]; + GtkWidget *icon = T->lessons[i].done_icon; + + if (!node) + continue; + if (T->lessons[i].done) { + gtk_widget_remove_css_class(node, "current"); + gtk_widget_add_css_class(node, "done"); + if (icon) + gtk_widget_set_visible(icon, TRUE); + } else { + gtk_widget_remove_css_class(node, "done"); + gtk_widget_add_css_class(node, "current"); + if (icon) + gtk_widget_set_visible(icon, FALSE); + } + } +} + +static void lit_mark_done(LitTrack *T, int lesson_id) { + if (lesson_id < 0 || lesson_id >= LIT_N) + return; + if (T->lessons[lesson_id].done) + return; + T->lessons[lesson_id].done = TRUE; + lit_save(T); + lit_refresh(T); + refresh_stats_ui(); +} + +void progress_for_lit(ProgressSum *out) { + if (!out) + return; + lit_ensure(); + for (int y = 0; y < 4; y++) { + LitTrack *T = &lit_tracks[y]; + + out->total_ex += LIT_N; + out->open_units += LIT_N; + for (int i = 0; i < LIT_N; i++) { + if (T->lessons[i].done) { + out->done_ex++; + out->done_units++; + } + } + } +} + +static void lit_open_unit(GtkButton *button, gpointer data) { + NetLesson *L = data; + + (void)button; + if (!L) + return; + L->idx = 0; + if (L->stack) { + char name[16]; + + g_snprintf(name, sizeof(name), "s%u", L->idx); + gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); + if (L->prev_btn) + gtk_widget_set_sensitive(L->prev_btn, FALSE); + if (L->next_btn) + gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); + } + gtk_stack_set_visible_child_name(main_stack, L->unit_page); +} + +static void lit_add_node(LitTrack *T, GtkFixed *fixed, int index) { + GtkWidget *card; + GtkWidget *vbox; + GtkWidget *number; + GtkWidget *icon; + GtkWidget *name; + char *text; + + card = gtk_button_new(); + gtk_widget_add_css_class(card, "unit-node"); + gtk_widget_add_css_class(card, "current"); + gtk_widget_set_can_focus(card, FALSE); + gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); + gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); + gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); + gtk_button_set_child(GTK_BUTTON(card), vbox); + + text = g_strdup_printf("%d", index + 1); + number = gtk_label_new(text); + g_free(text); + gtk_widget_add_css_class(number, "unit-number"); + gtk_box_append(GTK_BOX(vbox), number); + + icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); + gtk_widget_set_visible(icon, FALSE); + gtk_box_append(GTK_BOX(vbox), icon); + T->lessons[index].done_icon = icon; + g_signal_connect(card, "clicked", G_CALLBACK(lit_open_unit), + &T->lessons[index]); + + T->nodes[index] = card; + gtk_fixed_put(fixed, card, 0, 0); + + name = gtk_label_new(NULL); + i18n_bind(name, T->unit_keys[index], 0); + gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); + gtk_widget_set_halign(name, GTK_ALIGN_CENTER); + gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); + gtk_label_set_wrap(GTK_LABEL(name), TRUE); + gtk_label_set_max_width_chars(GTK_LABEL(name), 18); + gtk_widget_add_css_class(name, "unit-name"); + T->labels[index] = name; + gtk_fixed_put(fixed, name, 0, 0); +} + +static GtkWidget *lit_build_map(LitTrack *T) { + GtkWidget *page; + + lit_ensure(); + GtkWidget *scroll; + GtkWidget *wrap; + GtkWidget *fixed; + GtkWidget *rail; + GtkAdjustment *ha; + GtkAdjustment *va; + + T->last_avail = -1.0; + lit_geometry(T, 1000.0); + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_hexpand(page, TRUE); + gtk_widget_set_vexpand(page, TRUE); + gtk_widget_set_margin_start(page, 32); + gtk_widget_set_margin_end(page, 32); + gtk_widget_set_margin_top(page, 24); + gtk_widget_set_margin_bottom(page, 24); + + gtk_box_append(GTK_BOX(page), + top_bar(T->back_page, T->title_key, T->sub_key)); + + scroll = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(scroll, TRUE); + gtk_widget_set_margin_top(scroll, 14); + gtk_box_append(GTK_BOX(page), scroll); + T->scroll = scroll; + + wrap = gtk_center_box_new(); + gtk_widget_set_vexpand(wrap, TRUE); + gtk_widget_set_hexpand(wrap, TRUE); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); + + fixed = gtk_fixed_new(); + gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); + gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); + gtk_widget_set_size_request(fixed, T->cw, T->ch); + gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); + T->fixed = fixed; + + rail = gtk_drawing_area_new(); + gtk_widget_set_size_request(rail, T->cw, T->ch); + gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), lit_draw_rail, + T, NULL); + gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); + T->rail = rail; + + for (int i = 0; i < LIT_N; i++) + lit_add_node(T, GTK_FIXED(fixed), i); + + ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); + va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); + g_signal_connect(ha, "notify::page-size", + G_CALLBACK(lit_adjust_notify), T); + g_signal_connect(va, "notify::page-size", + G_CALLBACK(lit_adjust_notify), T); + + lit_apply_layout(T); + lit_relayout_later(T); + lit_refresh(T); + return page; +} + +static GtkWidget *lit_year_button(int year, const char *target, + const char *title_key, const char *sub_key) { + GtkWidget *btn; + GtkWidget *row; + GtkWidget *num; + GtkWidget *texts; + GtkWidget *title; + GtkWidget *sub; + char *num_text; + + btn = gtk_button_new(); + gtk_widget_add_css_class(btn, "unit-node"); + gtk_widget_add_css_class(btn, "current"); + gtk_widget_set_can_focus(btn, FALSE); + gtk_widget_set_hexpand(btn, TRUE); + gtk_widget_set_size_request(btn, -1, 84); + + row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); + gtk_widget_set_halign(row, GTK_ALIGN_START); + gtk_widget_set_valign(row, GTK_ALIGN_CENTER); + gtk_widget_set_margin_start(row, 18); + gtk_widget_set_margin_end(row, 18); + gtk_button_set_child(GTK_BUTTON(btn), row); + + num_text = g_strdup_printf("%d", year); + num = gtk_label_new(num_text); + g_free(num_text); + gtk_widget_add_css_class(num, "unit-number"); + gtk_widget_set_valign(num, GTK_ALIGN_CENTER); + gtk_box_append(GTK_BOX(row), num); + + texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); + gtk_widget_set_halign(texts, GTK_ALIGN_START); + gtk_widget_set_hexpand(texts, TRUE); + gtk_box_append(GTK_BOX(row), texts); + + title = gtk_label_new(NULL); + i18n_bind(title, title_key, 0); + gtk_widget_set_halign(title, GTK_ALIGN_START); + gtk_widget_add_css_class(title, "unit-name"); + gtk_box_append(GTK_BOX(texts), title); + + sub = gtk_label_new(NULL); + i18n_bind(sub, sub_key, 0); + gtk_widget_set_halign(sub, GTK_ALIGN_START); + gtk_label_set_wrap(GTK_LABEL(sub), TRUE); + gtk_label_set_xalign(GTK_LABEL(sub), 0.0); + gtk_widget_add_css_class(sub, "hint"); + gtk_box_append(GTK_BOX(texts), sub); + + g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); + g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); + return btn; +} + +GtkWidget *build_lityears_page(void) { + GtkWidget *page; + GtkWidget *scroll; + GtkWidget *list; + static const char *targets[] = {"litmap", "lit2map", "lit3map", "lit4map"}; + static const char *titles[] = { + "lit_year1", "lit_year2", "lit_year3", "lit_year4", + }; + static const char *subs[] = {"lit_sub", "lit2_sub", "lit3_sub", "lit4_sub"}; + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_hexpand(page, TRUE); + gtk_widget_set_vexpand(page, TRUE); + gtk_widget_set_margin_start(page, 32); + gtk_widget_set_margin_end(page, 32); + gtk_widget_set_margin_top(page, 24); + gtk_widget_set_margin_bottom(page, 24); + + gtk_box_append(GTK_BOX(page), + top_bar("czechmap", "Literatura", "lit_years_sub")); + + scroll = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(scroll, TRUE); + gtk_widget_set_margin_top(scroll, 18); + gtk_box_append(GTK_BOX(page), scroll); + + list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); + gtk_widget_set_halign(list, GTK_ALIGN_CENTER); + gtk_widget_set_valign(list, GTK_ALIGN_CENTER); + gtk_widget_set_size_request(list, 420, -1); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); + + for (int y = 0; y < 4; y++) + gtk_box_append(GTK_BOX(list), + lit_year_button(y + 1, targets[y], titles[y], subs[y])); + return page; +} + +GtkWidget *build_litmap_page(void) { return lit_build_map(&lit_tracks[0]); } +GtkWidget *build_lit2map_page(void) { return lit_build_map(&lit_tracks[1]); } +GtkWidget *build_lit3map_page(void) { return lit_build_map(&lit_tracks[2]); } +GtkWidget *build_lit4map_page(void) { return lit_build_map(&lit_tracks[3]); } + +static void lit_slide_apply(NetLesson *L) { + char name[16]; + + if (!L || !L->stack) + return; + g_snprintf(name, sizeof(name), "s%u", L->idx); + gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); + if (L->prev_btn) { + gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); + gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); + } + if (L->next_btn) { + gtk_button_set_label( + GTK_BUTTON(L->next_btn), + L->idx + 1 >= L->n_slides ? tr("net_slide_start") + : tr("net_slide_next")); + } +} + +static void lit_slide_prev(GtkButton *button, gpointer data) { + NetLesson *L = data; + + (void)button; + if (!L || L->idx == 0) + return; + L->idx--; + lit_slide_apply(L); +} + +static void lit_slide_next(GtkButton *button, gpointer data) { + NetLesson *L = data; + + (void)button; + if (!L) + return; + if (L->idx + 1 < L->n_slides) { + L->idx++; + lit_slide_apply(L); + } else { + gtk_stack_set_visible_child_name(main_stack, L->ex_page); + } +} + +static void lit_rescale(LitTrack *T, int w) { + int body, head, kick; + + if (w < 160) + w = 160; + body = w / 46; + if (body < 14) body = 14; + if (body > 26) body = 26; + head = body + 14; + if (head > 46) head = 46; + kick = body - 3; + if (kick < 11) kick = 11; + for (int i = 0; i < LIT_N; i++) + net_rescale_lesson_notes(&T->lessons[i], body, head, kick); +} + +static gboolean lit_note_tick(GtkWidget *w, GdkFrameClock *clock, + gpointer data) { + LitTrack *T = data; + int width = gtk_widget_get_allocated_width(w); + + (void)clock; + if (width != T->note_last_w) { + T->note_last_w = width; + lit_rescale(T, width); + } + return G_SOURCE_CONTINUE; +} + +GtkWidget *lit_unit_page(int year, NetLesson *L, const char *title_key, + const char *sub_key, const NetSlide *slides, + guint n_slides) { + LitTrack *T; + + lit_ensure(); + T = &lit_tracks[year]; + GtkWidget *page; + GtkWidget *scroll; + GtkWidget *nav; + + net_lesson_notes_ensure(L); + net_notes_target = L; + L->n_slides = n_slides; + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_margin_start(page, 28); + gtk_widget_set_margin_end(page, 28); + gtk_widget_set_margin_top(page, 20); + gtk_widget_set_margin_bottom(page, 20); + + gtk_box_append(GTK_BOX(page), top_bar(T->map_page, title_key, sub_key)); + + scroll = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(scroll, TRUE); + gtk_widget_set_margin_top(scroll, 10); + gtk_box_append(GTK_BOX(page), scroll); + + L->stack = gtk_stack_new(); + gtk_stack_set_transition_type(GTK_STACK(L->stack), + GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); + + for (guint s = 0; s < n_slides; s++) { + GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget *card; + char name[16]; + + gtk_widget_set_vexpand(stage, TRUE); + g_snprintf(name, sizeof(name), "s%u", s); + gtk_stack_add_named(GTK_STACK(L->stack), stage, name); + + card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); + gtk_widget_add_css_class(card, "notes-card"); + gtk_widget_set_valign(card, GTK_ALIGN_CENTER); + gtk_box_append(GTK_BOX(stage), card); + + net_note_kicker(card, slides[s].kicker); + net_note_title(card, slides[s].title); + for (int i = 0; i < 8 && slides[s].line[i]; i++) + net_note_line(card, slides[s].line[i], FALSE); + if (slides[s].tip) + net_note_line(card, slides[s].tip, TRUE); + } + + gtk_widget_add_tick_callback(L->stack, lit_note_tick, T, NULL); + T->note_last_w = -1; + lit_rescale(T, 0); + net_notes_target = NULL; + + nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); + gtk_widget_set_margin_top(nav, 10); + gtk_box_append(GTK_BOX(page), nav); + + L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); + gtk_widget_add_css_class(L->prev_btn, "btn-primary"); + g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(lit_slide_prev), L); + gtk_box_append(GTK_BOX(nav), L->prev_btn); + + L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); + gtk_widget_add_css_class(L->next_btn, "btn-primary"); + g_signal_connect(L->next_btn, "clicked", G_CALLBACK(lit_slide_next), L); + gtk_box_append(GTK_BOX(nav), L->next_btn); + + L->idx = 0; + lit_slide_apply(L); + return page; +} + +void lit_lessons_apply_lang(void) { + lit_ensure(); + for (int y = 0; y < 4; y++) { + for (int i = 0; i < LIT_N; i++) + lit_slide_apply(&lit_tracks[y].lessons[i]); + } +} + +typedef struct { + const ChoiceQ *qs; + int n; + int n_opts; + LitTrack *track; + int lesson_id; + GtkWidget *feedback; + GtkToggleButton **toggles; + GtkWidget **hints; +} LitMcqCtx; + +static void lit_mcq_check(GtkButton *button, gpointer data) { + LitMcqCtx *ctx = data; + int ok = 0; + + (void)button; + for (int i = 0; i < ctx->n; i++) { + int active = -1; + + for (int o = 0; o < ctx->n_opts; o++) { + GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; + + gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); + gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); + if (gtk_toggle_button_get_active(tb)) + active = o; + } + if (active == ctx->qs[i].correct) { + ok++; + gtk_widget_add_css_class( + GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); + } else if (active >= 0) { + gtk_widget_add_css_class( + GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); + } + if (ctx->hints && ctx->hints[i]) + gtk_widget_set_visible(ctx->hints[i], TRUE); + } + if (ok == ctx->n) { + set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); + lit_mark_done(ctx->track, ctx->lesson_id); + } else { + set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); + } +} + +GtkWidget *lit_mcq_page(int year, int lesson_id, const char *back_page, + const char *title_key, const char *heading_key, + const ChoiceQ *qs, const char **hints, int n) { + GtkWidget *page; + GtkWidget *scroll; + GtkWidget *body; + GtkWidget *check; + GtkWidget *btns; + GtkWidget *head; + GtkWidget *intro; + LitMcqCtx *ctx = g_new0(LitMcqCtx, 1); + int n_opts = qs[0].n_options; + + lit_ensure(); + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_margin_start(page, 32); + gtk_widget_set_margin_end(page, 32); + gtk_widget_set_margin_top(page, 24); + gtk_widget_set_margin_bottom(page, 24); + + gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); + + scroll = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(scroll, TRUE); + gtk_widget_set_margin_top(scroll, 12); + gtk_box_append(GTK_BOX(page), scroll); + + body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); + gtk_widget_set_halign(body, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(body, TRUE); + gtk_widget_set_margin_start(body, 4); + gtk_widget_set_margin_end(body, 4); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); + + head = gtk_label_new(NULL); + i18n_bind(head, heading_key, 0); + gtk_widget_set_halign(head, GTK_ALIGN_START); + gtk_label_set_wrap(GTK_LABEL(head), TRUE); + gtk_widget_set_margin_top(head, 4); + gtk_widget_add_css_class(head, "quiz-heading"); + gtk_box_append(GTK_BOX(body), head); + + intro = gtk_label_new(NULL); + i18n_bind(intro, "net_quiz_intro", 0); + gtk_widget_set_halign(intro, GTK_ALIGN_START); + gtk_label_set_wrap(GTK_LABEL(intro), TRUE); + gtk_widget_add_css_class(intro, "quiz-intro"); + gtk_widget_set_margin_bottom(intro, 4); + gtk_box_append(GTK_BOX(body), intro); + + ctx->qs = qs; + ctx->n = n; + ctx->n_opts = n_opts; + ctx->track = &lit_tracks[year]; + ctx->lesson_id = lesson_id; + ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); + ctx->hints = g_new0(GtkWidget *, n); + + for (int i = 0; i < n; i++) { + GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], + &ctx->toggles[i * n_opts]); + + ctx->hints[i] = meaning_add(card, hints[i]); + } + + btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_widget_set_margin_top(btns, 8); + gtk_widget_set_margin_bottom(btns, 8); + gtk_box_append(GTK_BOX(body), btns); + + check = gtk_button_new(); + i18n_bind(check, "check", 1); + gtk_widget_add_css_class(check, "btn-primary"); + gtk_widget_set_halign(check, GTK_ALIGN_START); + gtk_box_append(GTK_BOX(btns), check); + g_signal_connect(check, "clicked", G_CALLBACK(lit_mcq_check), ctx); + + ctx->feedback = gtk_label_new(""); + gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); + gtk_box_append(GTK_BOX(body), ctx->feedback); + return page; +} + +static gboolean lit_ready; + +static void lit_tracks_init(void) { + static const char *keys0[] = { + "lit_unit1", "lit_unit2", "lit_unit3", "lit_unit4", + "lit_unit5", "lit_unit6", "lit_unit7", "lit_unit8", + }; + static const char *keys1[] = { + "lit2_unit1", "lit2_unit2", "lit2_unit3", "lit2_unit4", + "lit2_unit5", "lit2_unit6", "lit2_unit7", "lit2_unit8", + }; + static const char *keys2[] = { + "lit3_unit1", "lit3_unit2", "lit3_unit3", "lit3_unit4", + "lit3_unit5", "lit3_unit6", "lit3_unit7", "lit3_unit8", + }; + static const char *keys3[] = { + "lit4_unit1", "lit4_unit2", "lit4_unit3", "lit4_unit4", + "lit4_unit5", "lit4_unit6", "lit4_unit7", "lit4_unit8", + }; + static const char *const *all_keys[4] = {keys0, keys1, keys2, keys3}; + static const char *maps[] = {"litmap", "lit2map", "lit3map", "lit4map"}; + static const char *titles[] = { + "lit_year1", "lit_year2", "lit_year3", "lit_year4", + }; + static const char *subs[] = {"lit_sub", "lit2_sub", "lit3_sub", "lit4_sub"}; + NetLesson *lessons[4] = { + lit_lessons, lit2_lessons, lit3_lessons, lit4_lessons, + }; + char **paths[4] = { + &app_progress_lit, &app_progress_lit2, + &app_progress_lit3, &app_progress_lit4, + }; + + for (int y = 0; y < 4; y++) { + LitTrack *T = &lit_tracks[y]; + + T->map_page = maps[y]; + T->back_page = "lityears"; + T->title_key = titles[y]; + T->sub_key = subs[y]; + T->progress_path = paths[y]; + T->lessons = lessons[y]; + T->last_avail = -1.0; + T->last_cols = -1; + T->note_last_w = -1; + for (int i = 0; i < LIT_N; i++) + T->unit_keys[i] = all_keys[y][i]; + } +} + +static void lit_ensure(void) { + if (lit_ready) + return; + lit_ready = TRUE; + lit_tracks_init(); +} diff --git a/src/main.c b/src/main.c index 1d098b1..49f5f70 100644 --- a/src/main.c +++ b/src/main.c @@ -388,6 +388,10 @@ static gboolean run_smoke_test(gpointer data) { "netyears", "netmap", "hwyears", "hwmap", "onyears", "onmap", "on2map", "on3map", "on4map", "czechmap", + "lityears", "litmap", "lit2map", "lit3map", "lit4map", + "litunit1", "litex1", "litunit8", "litex8", + "lit2unit1", "lit2ex1", "lit3unit1", "lit3ex1", + "lit4unit1", "lit4ex1", "lit4unit8", "lit4ex8", "mluvnice", "readinglist", "cetba1984", "cetba1984quiz", "cetba1984dej", "cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej", @@ -522,6 +526,15 @@ void activate(GtkApplication *app, gpointer user_data) { gtk_stack_add_named(main_stack, build_on4map_page(), "on4map"); add_on4_pages(main_stack); gtk_stack_add_named(main_stack, build_czechmap_page(), "czechmap"); + gtk_stack_add_named(main_stack, build_lityears_page(), "lityears"); + gtk_stack_add_named(main_stack, build_litmap_page(), "litmap"); + add_lit_pages(main_stack); + gtk_stack_add_named(main_stack, build_lit2map_page(), "lit2map"); + add_lit2_pages(main_stack); + gtk_stack_add_named(main_stack, build_lit3map_page(), "lit3map"); + add_lit3_pages(main_stack); + gtk_stack_add_named(main_stack, build_lit4map_page(), "lit4map"); + add_lit4_pages(main_stack); gtk_stack_add_named(main_stack, build_mluvnice_page(), "mluvnice"); for (int n = 1; n <= 20; n++) { char name[16]; diff --git a/src/progress.c b/src/progress.c index 27ee5b4..c0059cf 100644 --- a/src/progress.c +++ b/src/progress.c @@ -58,6 +58,7 @@ void load_progress(void) { on2_load_progress(); on3_load_progress(); on4_load_progress(); + lit_load_progress(); } /* Redraw the exercise rails of every unit that already has a page. */ diff --git a/src/search.c b/src/search.c index f132658..8240e7c 100644 --- a/src/search.c +++ b/src/search.c @@ -237,7 +237,40 @@ static void catalog_rebuild(void) { catalog_add_key("Český jazyk a literatura", "search_subject", "czechmap", FALSE, 0, "cestina czech"); - catalog_add_key("Literatura", "search_lesson", "czechmap", TRUE, 1, NULL); + catalog_add_key("Literatura", "search_lesson", "lityears", FALSE, 1, + "literatura"); + catalog_add_key("lit_year1", "search_lesson", "litmap", FALSE, 1, "rocnik"); + catalog_add_key("lit_year2", "search_lesson", "lit2map", FALSE, 1, "rocnik"); + catalog_add_key("lit_year3", "search_lesson", "lit3map", FALSE, 1, "rocnik"); + catalog_add_key("lit_year4", "search_lesson", "lit4map", FALSE, 1, "rocnik"); + for (i = 1; i <= LIT_N; i++) { + g_snprintf(key, sizeof(key), "lit_unit%d", i); + g_snprintf(page, sizeof(page), "litunit%d", i); + catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); + g_snprintf(page, sizeof(page), "litex%d", i); + catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); + } + for (i = 1; i <= LIT_N; i++) { + g_snprintf(key, sizeof(key), "lit2_unit%d", i); + g_snprintf(page, sizeof(page), "lit2unit%d", i); + catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); + g_snprintf(page, sizeof(page), "lit2ex%d", i); + catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); + } + for (i = 1; i <= LIT_N; i++) { + g_snprintf(key, sizeof(key), "lit3_unit%d", i); + g_snprintf(page, sizeof(page), "lit3unit%d", i); + catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); + g_snprintf(page, sizeof(page), "lit3ex%d", i); + catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); + } + for (i = 1; i <= LIT_N; i++) { + g_snprintf(key, sizeof(key), "lit4_unit%d", i); + g_snprintf(page, sizeof(page), "lit4unit%d", i); + catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); + g_snprintf(page, sizeof(page), "lit4ex%d", i); + catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); + } catalog_add_key("Mluvnice", "search_lesson", "mluvnice", FALSE, 1, "gramatika grammar"); catalog_add_key("Maturitní četba", "search_book", "readinglist", FALSE, 1, diff --git a/src/stats.c b/src/stats.c index 6bc4db7..101b9ff 100644 --- a/src/stats.c +++ b/src/stats.c @@ -71,8 +71,10 @@ void refresh_stats_ui(void) { progress_for_hw(&all); else if (s == ON_SUBJ) progress_for_on(&all); - else if (s == CZ_SUBJ) + else if (s == CZ_SUBJ) { progress_for_mluvnice(&all); + progress_for_lit(&all); + } else progress_for_units(sub_unit_start[s], sub_unit_count[s], &all); } @@ -113,8 +115,10 @@ void refresh_stats_ui(void) { progress_for_hw(&sp); else if (s == ON_SUBJ) progress_for_on(&sp); - else if (s == CZ_SUBJ) + else if (s == CZ_SUBJ) { progress_for_mluvnice(&sp); + progress_for_lit(&sp); + } else progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp); if (has_content) { diff --git a/src/theme.c b/src/theme.c index d408229..746db2f 100644 --- a/src/theme.c +++ b/src/theme.c @@ -431,5 +431,6 @@ void apply_theme(void) { on3_rail_theme_reset(); on4_rail_theme_reset(); czech_rail_theme_reset(); + lit_rail_theme_reset(); book_rail_theme_reset(); } diff --git a/src/util.c b/src/util.c index db44391..847d7e3 100644 --- a/src/util.c +++ b/src/util.c @@ -26,6 +26,10 @@ char *app_progress_on3; char *app_progress_on4; char *app_progress_mluvnice; char *app_progress_cetba; +char *app_progress_lit; +char *app_progress_lit2; +char *app_progress_lit3; +char *app_progress_lit4; static char *dup_dirname(const char *path) { char *tmp = g_strdup(path); @@ -168,6 +172,10 @@ static void set_progress_paths(const char *write_root) { g_free(app_progress_on4); g_free(app_progress_mluvnice); g_free(app_progress_cetba); + g_free(app_progress_lit); + g_free(app_progress_lit2); + g_free(app_progress_lit3); + g_free(app_progress_lit4); app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL); app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL); @@ -182,6 +190,10 @@ static void set_progress_paths(const char *write_root) { app_progress_on4 = g_build_filename(app_progress_dir, "on4.conf", NULL); app_progress_mluvnice = g_build_filename(app_progress_dir, "mluvnice.conf", NULL); app_progress_cetba = g_build_filename(app_progress_dir, "cetba.conf", NULL); + app_progress_lit = g_build_filename(app_progress_dir, "lit.conf", NULL); + app_progress_lit2 = g_build_filename(app_progress_dir, "lit2.conf", NULL); + app_progress_lit3 = g_build_filename(app_progress_dir, "lit3.conf", NULL); + app_progress_lit4 = g_build_filename(app_progress_dir, "lit4.conf", NULL); } /* Resolve read-only asset root, chdir there, and point progress at a writable