mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Add chemistry and biology lessons for natural sciences.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
09312d8c93
commit
bd7ab09b1d
30 changed files with 2519 additions and 13 deletions
|
|
@ -69,6 +69,8 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
|
||||||
- **Český jazyk a literatura** — literatura (4 ročníky, 32 lekcí podle osnov
|
- **Český jazyk a literatura** — literatura (4 ročníky, 32 lekcí podle osnov
|
||||||
středních škol), mluvnice (20 cvičení) a maturitní četba
|
středních škol), mluvnice (20 cvičení) a maturitní četba
|
||||||
(82 knih: zápisky, kvíz, sestavení děje)
|
(82 knih: zápisky, kvíz, sestavení děje)
|
||||||
|
- **Základy přírodopisných věd** — chemie a biologie, v každé 8 lekcí
|
||||||
|
(od atomu a buňky po biochemii a ekologii) s výkladem a kvízem
|
||||||
- **Občanská nauka** — 1. ročník, 17 lekcí (člověk v lidském společenství);
|
- **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);
|
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)
|
4. ročník, 16 lekcí (hospodářství, svět a filozofie)
|
||||||
|
|
@ -78,7 +80,7 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
|
||||||
### Použití
|
### Použití
|
||||||
|
|
||||||
1. **Pokračuj** otevře mapu předmětů.
|
1. **Pokračuj** otevře mapu předmětů.
|
||||||
2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka, váhy) vede na učební cestu.
|
2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka, váhy, baňka) vede na učební cestu.
|
||||||
3. Uzly cvičení / lekcí otevřou obsah; zamčené nic nedělají.
|
3. Uzly cvičení / lekcí otevřou obsah; zamčené nic nedělají.
|
||||||
4. **Hledat** (lupa), **Statistiky** (graf) a **Nastavení** (ozubené kolo) jsou vpravo nahoře.
|
4. **Hledat** (lupa), **Statistiky** (graf) a **Nastavení** (ozubené kolo) jsou vpravo nahoře.
|
||||||
|
|
||||||
|
|
@ -266,6 +268,8 @@ Intel Mac, another architecture, or hacking on the code →
|
||||||
- **Czech language** — literature (4 years, 32 lessons from the secondary-school
|
- **Czech language** — literature (4 years, 32 lessons from the secondary-school
|
||||||
syllabus), grammar (20 exercises) and required reading
|
syllabus), grammar (20 exercises) and required reading
|
||||||
(82 books: notes, quiz, plot ordering)
|
(82 books: notes, quiz, plot ordering)
|
||||||
|
- **Natural sciences** — chemistry and biology, eight lessons each
|
||||||
|
(from the atom and the cell to biochemistry and ecology), with an overview and a quiz
|
||||||
- **Civics** — year 1, 17 lessons (the individual and society);
|
- **Civics** — year 1, 17 lessons (the individual and society);
|
||||||
year 2, 16 lessons (the citizen in a democratic state);
|
year 2, 16 lessons (the citizen in a democratic state);
|
||||||
year 3, 16 lessons (the individual and the law);
|
year 3, 16 lessons (the individual and the law);
|
||||||
|
|
@ -276,7 +280,7 @@ Intel Mac, another architecture, or hacking on the code →
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
1. **Continue** opens the subject map.
|
1. **Continue** opens the subject map.
|
||||||
2. An open subject (flag, Wi‑Fi, chip, Czech flag, scales) opens its path.
|
2. An open subject (flag, Wi‑Fi, chip, Czech flag, scales, flask) opens its path.
|
||||||
3. Exercise / lesson nodes open content; locked nodes do nothing.
|
3. Exercise / lesson nodes open content; locked nodes do nothing.
|
||||||
4. **Search** (magnifier), **Statistics** (chart) and **Settings** (gear) sit in the top-right.
|
4. **Search** (magnifier), **Statistics** (chart) and **Settings** (gear) sit in the top-right.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,16 @@ class AppViewModel(app: Application) : AndroidViewModel(app) {
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markChem(id: Int) {
|
||||||
|
progress.markChem(id)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun markBio(id: Int) {
|
||||||
|
progress.markBio(id)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
fun markMluv(n: Int) {
|
fun markMluv(n: Int) {
|
||||||
progress.markMluv(n)
|
progress.markMluv(n)
|
||||||
refresh()
|
refresh()
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ import org.maturita.maturita.ui.LessonListScreen
|
||||||
import org.maturita.maturita.ui.LitYearsScreen
|
import org.maturita.maturita.ui.LitYearsScreen
|
||||||
import org.maturita.maturita.ui.LessonRow
|
import org.maturita.maturita.ui.LessonRow
|
||||||
import org.maturita.maturita.ui.LitQuizScreen
|
import org.maturita.maturita.ui.LitQuizScreen
|
||||||
|
import org.maturita.maturita.ui.SciMapScreen
|
||||||
|
import org.maturita.maturita.ui.SciQuizScreen
|
||||||
import org.maturita.maturita.ui.MluvExercise
|
import org.maturita.maturita.ui.MluvExercise
|
||||||
import org.maturita.maturita.ui.NetQuizScreen
|
import org.maturita.maturita.ui.NetQuizScreen
|
||||||
import org.maturita.maturita.ui.NetYearsScreen
|
import org.maturita.maturita.ui.NetYearsScreen
|
||||||
|
|
@ -346,6 +348,35 @@ private fun MaturitaAppBody(vm: AppViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Route.Lit4Ex -> LitQuizScreen(vm, 4, r.id)
|
is Route.Lit4Ex -> LitQuizScreen(vm, 4, r.id)
|
||||||
|
Route.SciMap -> SciMapScreen(vm)
|
||||||
|
Route.ChemMap -> LessonListScreen(
|
||||||
|
vm, vm.tr("Chemie"), vm.tr("chem_sub"),
|
||||||
|
vm.content.chem.map { l ->
|
||||||
|
val id = l.int("id")
|
||||||
|
LessonRow(vm.tr(l.str("titleKey")), vm.progress.chemDone(id), Route.ChemLesson(id))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is Route.ChemLesson -> {
|
||||||
|
val l = vm.content.chemLesson(r.id)
|
||||||
|
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||||
|
vm.replace(Route.ChemEx(r.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Route.ChemEx -> SciQuizScreen(vm, "chem", r.id)
|
||||||
|
Route.BioMap -> LessonListScreen(
|
||||||
|
vm, vm.tr("Biologie"), vm.tr("bio_sub"),
|
||||||
|
vm.content.bio.map { l ->
|
||||||
|
val id = l.int("id")
|
||||||
|
LessonRow(vm.tr(l.str("titleKey")), vm.progress.bioDone(id), Route.BioLesson(id))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is Route.BioLesson -> {
|
||||||
|
val l = vm.content.bioLesson(r.id)
|
||||||
|
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||||
|
vm.replace(Route.BioEx(r.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Route.BioEx -> SciQuizScreen(vm, "bio", r.id)
|
||||||
Route.CzechMap -> CzechMapScreen(vm)
|
Route.CzechMap -> CzechMapScreen(vm)
|
||||||
Route.Mluvnice -> LessonListScreen(
|
Route.Mluvnice -> LessonListScreen(
|
||||||
vm, vm.tr("Mluvnice"), vm.tr("mluv_sub"),
|
vm, vm.tr("Mluvnice"), vm.tr("mluv_sub"),
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,13 @@ sealed class Route(val page: String) {
|
||||||
data object Lit4Map : Route("lit4map")
|
data object Lit4Map : Route("lit4map")
|
||||||
data class Lit4Lesson(val id: Int) : Route("lit4unit$id")
|
data class Lit4Lesson(val id: Int) : Route("lit4unit$id")
|
||||||
data class Lit4Ex(val id: Int) : Route("lit4ex$id")
|
data class Lit4Ex(val id: Int) : Route("lit4ex$id")
|
||||||
|
data object SciMap : Route("scimap")
|
||||||
|
data object ChemMap : Route("chemmap")
|
||||||
|
data class ChemLesson(val id: Int) : Route("chemunit$id")
|
||||||
|
data class ChemEx(val id: Int) : Route("chemex$id")
|
||||||
|
data object BioMap : Route("biomap")
|
||||||
|
data class BioLesson(val id: Int) : Route("biounit$id")
|
||||||
|
data class BioEx(val id: Int) : Route("bioex$id")
|
||||||
data object CzechMap : Route("czechmap")
|
data object CzechMap : Route("czechmap")
|
||||||
data object Mluvnice : Route("mluvnice")
|
data object Mluvnice : Route("mluvnice")
|
||||||
data class MluvEx(val n: Int) : Route("mluve$n")
|
data class MluvEx(val n: Int) : Route("mluve$n")
|
||||||
|
|
@ -60,7 +67,8 @@ sealed class Route(val page: String) {
|
||||||
this is OnEx || this is On2Ex || this is On3Ex || this is On4Ex || this is MluvEx || this is BookQuiz || this is BookPlot ||
|
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 LitLesson || this is LitEx || this is Lit2Lesson || this is Lit2Ex ||
|
||||||
this is Lit3Lesson || this is Lit3Ex || this is Lit4Lesson || this is Lit4Ex
|
this is Lit3Lesson || this is Lit3Ex || this is Lit4Lesson || this is Lit4Ex ||
|
||||||
|
this is ChemLesson || this is ChemEx || this is BioLesson || this is BioEx
|
||||||
|
|
||||||
/** Full stack from the practice root to this screen, so back always goes up one level. */
|
/** Full stack from the practice root to this screen, so back always goes up one level. */
|
||||||
fun stack(): List<Route> = when (this) {
|
fun stack(): List<Route> = when (this) {
|
||||||
|
|
@ -105,6 +113,13 @@ sealed class Route(val page: String) {
|
||||||
Lit4Map -> listOf(Subjects, CzechMap, LitYears, Lit4Map)
|
Lit4Map -> listOf(Subjects, CzechMap, LitYears, Lit4Map)
|
||||||
is Lit4Lesson -> listOf(Subjects, CzechMap, LitYears, Lit4Map, this)
|
is Lit4Lesson -> listOf(Subjects, CzechMap, LitYears, Lit4Map, this)
|
||||||
is Lit4Ex -> listOf(Subjects, CzechMap, LitYears, Lit4Map, Lit4Lesson(id), this)
|
is Lit4Ex -> listOf(Subjects, CzechMap, LitYears, Lit4Map, Lit4Lesson(id), this)
|
||||||
|
SciMap -> listOf(Subjects, SciMap)
|
||||||
|
ChemMap -> listOf(Subjects, SciMap, ChemMap)
|
||||||
|
is ChemLesson -> listOf(Subjects, SciMap, ChemMap, this)
|
||||||
|
is ChemEx -> listOf(Subjects, SciMap, ChemMap, ChemLesson(id), this)
|
||||||
|
BioMap -> listOf(Subjects, SciMap, BioMap)
|
||||||
|
is BioLesson -> listOf(Subjects, SciMap, BioMap, this)
|
||||||
|
is BioEx -> listOf(Subjects, SciMap, BioMap, BioLesson(id), this)
|
||||||
CzechMap -> listOf(Subjects, CzechMap)
|
CzechMap -> listOf(Subjects, CzechMap)
|
||||||
Mluvnice -> listOf(Subjects, CzechMap, Mluvnice)
|
Mluvnice -> listOf(Subjects, CzechMap, Mluvnice)
|
||||||
is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this)
|
is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this)
|
||||||
|
|
@ -135,6 +150,9 @@ fun routeFromPage(page: String): Route? = when (page) {
|
||||||
"lit2map" -> Route.Lit2Map
|
"lit2map" -> Route.Lit2Map
|
||||||
"lit3map" -> Route.Lit3Map
|
"lit3map" -> Route.Lit3Map
|
||||||
"lit4map" -> Route.Lit4Map
|
"lit4map" -> Route.Lit4Map
|
||||||
|
"scimap" -> Route.SciMap
|
||||||
|
"chemmap" -> Route.ChemMap
|
||||||
|
"biomap" -> Route.BioMap
|
||||||
"czechmap" -> Route.CzechMap
|
"czechmap" -> Route.CzechMap
|
||||||
"mluvnice" -> Route.Mluvnice
|
"mluvnice" -> Route.Mluvnice
|
||||||
"readinglist" -> Route.ReadingList
|
"readinglist" -> Route.ReadingList
|
||||||
|
|
@ -166,6 +184,18 @@ fun routeFromPage(page: String): Route? = when (page) {
|
||||||
Regex("""hwex(\d+)""").matchEntire(page)?.let {
|
Regex("""hwex(\d+)""").matchEntire(page)?.let {
|
||||||
return Route.HwEx(it.groupValues[1].toInt())
|
return Route.HwEx(it.groupValues[1].toInt())
|
||||||
}
|
}
|
||||||
|
Regex("""chemunit(\d+)""").matchEntire(page)?.let {
|
||||||
|
return Route.ChemLesson(it.groupValues[1].toInt())
|
||||||
|
}
|
||||||
|
Regex("""chemex(\d+)""").matchEntire(page)?.let {
|
||||||
|
return Route.ChemEx(it.groupValues[1].toInt())
|
||||||
|
}
|
||||||
|
Regex("""biounit(\d+)""").matchEntire(page)?.let {
|
||||||
|
return Route.BioLesson(it.groupValues[1].toInt())
|
||||||
|
}
|
||||||
|
Regex("""bioex(\d+)""").matchEntire(page)?.let {
|
||||||
|
return Route.BioEx(it.groupValues[1].toInt())
|
||||||
|
}
|
||||||
Regex("""lit4unit(\d+)""").matchEntire(page)?.let {
|
Regex("""lit4unit(\d+)""").matchEntire(page)?.let {
|
||||||
return Route.Lit4Lesson(it.groupValues[1].toInt())
|
return Route.Lit4Lesson(it.groupValues[1].toInt())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ class Content(root: JSONObject) {
|
||||||
val lit2 = raw.arr("lit2")
|
val lit2 = raw.arr("lit2")
|
||||||
val lit3 = raw.arr("lit3")
|
val lit3 = raw.arr("lit3")
|
||||||
val lit4 = raw.arr("lit4")
|
val lit4 = raw.arr("lit4")
|
||||||
|
val chem = raw.arr("chem")
|
||||||
|
val bio = raw.arr("bio")
|
||||||
val mluvnice = raw.arr("mluvnice")
|
val mluvnice = raw.arr("mluvnice")
|
||||||
val books = raw.arr("books")
|
val books = raw.arr("books")
|
||||||
val changelog = raw.arr("changelog")
|
val changelog = raw.arr("changelog")
|
||||||
|
|
@ -52,6 +54,8 @@ class Content(root: JSONObject) {
|
||||||
fun lit2Lesson(id: Int) = lit2.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 lit3Lesson(id: Int) = lit3.firstOrNull { it.int("id") == id }
|
||||||
fun lit4Lesson(id: Int) = lit4.firstOrNull { it.int("id") == id }
|
fun lit4Lesson(id: Int) = lit4.firstOrNull { it.int("id") == id }
|
||||||
|
fun chemLesson(id: Int) = chem.firstOrNull { it.int("id") == id }
|
||||||
|
fun bioLesson(id: Int) = bio.firstOrNull { it.int("id") == id }
|
||||||
fun mluv(n: Int) = mluvnice.firstOrNull { it.int("id") == n }
|
fun mluv(n: Int) = mluvnice.firstOrNull { it.int("id") == n }
|
||||||
fun book(id: String) = books.firstOrNull { it.str("id") == id }
|
fun book(id: String) = books.firstOrNull { it.str("id") == id }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,11 @@ class ProgressStore(context: Context) {
|
||||||
fun lit4Done(id: Int) = prefs.getBoolean("lit4.$id", false)
|
fun lit4Done(id: Int) = prefs.getBoolean("lit4.$id", false)
|
||||||
fun markLit4(id: Int) { prefs.edit().putBoolean("lit4.$id", true).apply() }
|
fun markLit4(id: Int) { prefs.edit().putBoolean("lit4.$id", true).apply() }
|
||||||
|
|
||||||
|
fun chemDone(id: Int) = prefs.getBoolean("chem.$id", false)
|
||||||
|
fun markChem(id: Int) { prefs.edit().putBoolean("chem.$id", true).apply() }
|
||||||
|
fun bioDone(id: Int) = prefs.getBoolean("bio.$id", false)
|
||||||
|
fun markBio(id: Int) { prefs.edit().putBoolean("bio.$id", true).apply() }
|
||||||
|
|
||||||
fun mluvDone(n: Int) = prefs.getBoolean("mluv.$n", false)
|
fun mluvDone(n: Int) = prefs.getBoolean("mluv.$n", false)
|
||||||
fun markMluv(n: Int) { prefs.edit().putBoolean("mluv.$n", true).apply() }
|
fun markMluv(n: Int) { prefs.edit().putBoolean("mluv.$n", true).apply() }
|
||||||
|
|
||||||
|
|
@ -155,6 +160,22 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
|
||||||
sum.doneUnits += 1
|
sum.doneUnits += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
content.chem.forEach { l ->
|
||||||
|
sum.totalEx += 1
|
||||||
|
sum.openUnits += 1
|
||||||
|
if (p.chemDone(l.int("id"))) {
|
||||||
|
sum.doneEx += 1
|
||||||
|
sum.doneUnits += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content.bio.forEach { l ->
|
||||||
|
sum.totalEx += 1
|
||||||
|
sum.openUnits += 1
|
||||||
|
if (p.bioDone(l.int("id"))) {
|
||||||
|
sum.doneEx += 1
|
||||||
|
sum.doneUnits += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
sum.totalEx += content.mluvnice.size
|
sum.totalEx += content.mluvnice.size
|
||||||
sum.openUnits += 1
|
sum.openUnits += 1
|
||||||
val md = content.mluvnice.count { p.mluvDone(it.int("id")) }
|
val md = content.mluvnice.count { p.mluvDone(it.int("id")) }
|
||||||
|
|
|
||||||
|
|
@ -849,6 +849,20 @@ fun NetQuizScreen(vm: AppViewModel, id: Int) {
|
||||||
DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey"))) { vm.markNet(id) }
|
DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey"))) { vm.markNet(id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SciQuizScreen(vm: AppViewModel, area: String, id: Int) {
|
||||||
|
val lesson = (if (area == "bio") vm.content.bioLesson(id) else vm.content.chemLesson(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"))) {
|
||||||
|
if (area == "bio") vm.markBio(id) else vm.markChem(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LitQuizScreen(vm: AppViewModel, year: Int, id: Int) {
|
fun LitQuizScreen(vm: AppViewModel, year: Int, id: Int) {
|
||||||
val lesson = when (year) {
|
val lesson = when (year) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||||
import androidx.compose.material.icons.filled.Groups
|
import androidx.compose.material.icons.filled.Groups
|
||||||
import androidx.compose.material.icons.filled.Lock
|
import androidx.compose.material.icons.filled.Lock
|
||||||
import androidx.compose.material.icons.filled.Quiz
|
import androidx.compose.material.icons.filled.Quiz
|
||||||
|
import androidx.compose.material.icons.filled.Science
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.outlined.Lightbulb
|
import androidx.compose.material.icons.outlined.Lightbulb
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
|
@ -220,6 +221,7 @@ private fun SubjectIcon(icon: String, open: Boolean) {
|
||||||
"chip" -> ChipIcon(tint, 26.dp)
|
"chip" -> ChipIcon(tint, 26.dp)
|
||||||
"people" -> Icon(Icons.Filled.Groups, null, tint = tint, modifier = Modifier.size(26.dp))
|
"people" -> Icon(Icons.Filled.Groups, null, tint = tint, modifier = Modifier.size(26.dp))
|
||||||
"cz" -> CzechFlag(28.dp)
|
"cz" -> CzechFlag(28.dp)
|
||||||
|
"flask" -> Icon(Icons.Filled.Science, null, tint = tint, modifier = Modifier.size(26.dp))
|
||||||
else -> Icon(Icons.Filled.Lock, null, tint = tint)
|
else -> Icon(Icons.Filled.Lock, null, tint = tint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +309,11 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
|
||||||
vm.content.on3.count { vm.progress.on3Done(it.int("id")) } +
|
vm.content.on3.count { vm.progress.on3Done(it.int("id")) } +
|
||||||
vm.content.on4.count { vm.progress.on4Done(it.int("id")) }
|
vm.content.on4.count { vm.progress.on4Done(it.int("id")) }
|
||||||
}
|
}
|
||||||
|
"scimap" -> {
|
||||||
|
sum.totalEx = vm.content.chem.size + vm.content.bio.size
|
||||||
|
sum.doneEx = vm.content.chem.count { vm.progress.chemDone(it.int("id")) } +
|
||||||
|
vm.content.bio.count { vm.progress.bioDone(it.int("id")) }
|
||||||
|
}
|
||||||
"czechmap" -> {
|
"czechmap" -> {
|
||||||
val litDone = vm.content.lit.count { vm.progress.litDone(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.lit2.count { vm.progress.lit2Done(it.int("id")) } +
|
||||||
|
|
@ -540,6 +547,16 @@ private fun buildSearch(vm: AppViewModel): List<Hit> {
|
||||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit${l.int("id")}", extra = "literatura")
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit${l.int("id")}", extra = "literatura")
|
||||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex${l.int("id")}")
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex${l.int("id")}")
|
||||||
}
|
}
|
||||||
|
add(vm.tr("Chemie"), vm.tr("search_lesson"), "chemmap", extra = "chemie")
|
||||||
|
add(vm.tr("Biologie"), vm.tr("search_lesson"), "biomap", extra = "biologie")
|
||||||
|
vm.content.chem.forEach { l ->
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "chemunit${l.int("id")}", extra = "chemie")
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "chemex${l.int("id")}")
|
||||||
|
}
|
||||||
|
vm.content.bio.forEach { l ->
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "biounit${l.int("id")}", extra = "biologie")
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "bioex${l.int("id")}")
|
||||||
|
}
|
||||||
add(vm.tr("Mluvnice"), vm.tr("search_lesson"), "mluvnice")
|
add(vm.tr("Mluvnice"), vm.tr("search_lesson"), "mluvnice")
|
||||||
vm.content.mluvnice.forEach { m -> add(m.str("name"), vm.tr("Mluvnice"), "mluve${m.int("id")}") }
|
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")
|
add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist")
|
||||||
|
|
@ -666,6 +683,24 @@ fun LitYearsScreen(vm: AppViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SciMapScreen(vm: AppViewModel) {
|
||||||
|
DetailScaffold(vm, vm.tr("Základy Přírodopisných věd"), vm.tr("sci_sub")) { inner ->
|
||||||
|
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||||
|
item {
|
||||||
|
NavRow(
|
||||||
|
title = vm.tr("Chemie"),
|
||||||
|
subtitle = vm.tr("chem_sub"),
|
||||||
|
leading = { Icon(Icons.Filled.Science, null, tint = MaterialTheme.colorScheme.primary) },
|
||||||
|
) { vm.go(Route.ChemMap) }
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
NavRow(title = vm.tr("Biologie"), subtitle = vm.tr("bio_sub")) { vm.go(Route.BioMap) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CzechMapScreen(vm: AppViewModel) {
|
fun CzechMapScreen(vm: AppViewModel) {
|
||||||
DetailScaffold(vm, vm.tr("Český jazyk a literatura"), vm.tr("czech_sub")) { inner ->
|
DetailScaffold(vm, vm.tr("Český jazyk a literatura"), vm.tr("czech_sub")) { inner ->
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@
|
||||||
# en: bullet
|
# en: bullet
|
||||||
|
|
||||||
--- 2026-10-06
|
--- 2026-10-06
|
||||||
|
cs: Základy přírodopisných věd: chemie a biologie, v každé 8 lekcí podle osnov
|
||||||
|
cs: Každá lekce má výklad a kvíz se čtyřmi otázkami
|
||||||
|
en: Natural sciences: chemistry and biology, eight lessons each, from the syllabus
|
||||||
|
en: Every lesson has an overview and a four-question quiz
|
||||||
cs: Český jazyk: literatura ve čtyřech ročnících podle osnov středních škol
|
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
|
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: Czech: literature across four years, following the secondary-school syllabus
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,16 @@ final class AppModel: ObservableObject {
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func markChem(_ id: Int) {
|
||||||
|
progress.markChem(id)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func markBio(_ id: Int) {
|
||||||
|
progress.markBio(id)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func markMluv(_ n: Int) {
|
func markMluv(_ n: Int) {
|
||||||
progress.markMluv(n)
|
progress.markMluv(n)
|
||||||
refresh()
|
refresh()
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ final class Content {
|
||||||
let lit2: [J]
|
let lit2: [J]
|
||||||
let lit3: [J]
|
let lit3: [J]
|
||||||
let lit4: [J]
|
let lit4: [J]
|
||||||
|
let chem: [J]
|
||||||
|
let bio: [J]
|
||||||
let mluvnice: [J]
|
let mluvnice: [J]
|
||||||
let books: [J]
|
let books: [J]
|
||||||
let changelog: [J]
|
let changelog: [J]
|
||||||
|
|
@ -78,6 +80,8 @@ final class Content {
|
||||||
lit2 = raw.arr("lit2")
|
lit2 = raw.arr("lit2")
|
||||||
lit3 = raw.arr("lit3")
|
lit3 = raw.arr("lit3")
|
||||||
lit4 = raw.arr("lit4")
|
lit4 = raw.arr("lit4")
|
||||||
|
chem = raw.arr("chem")
|
||||||
|
bio = raw.arr("bio")
|
||||||
mluvnice = raw.arr("mluvnice")
|
mluvnice = raw.arr("mluvnice")
|
||||||
books = raw.arr("books")
|
books = raw.arr("books")
|
||||||
changelog = raw.arr("changelog")
|
changelog = raw.arr("changelog")
|
||||||
|
|
@ -94,6 +98,8 @@ final class Content {
|
||||||
func lit2Lesson(_ id: Int) -> J? { lit2.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 lit3Lesson(_ id: Int) -> J? { lit3.first { $0.int("id") == id } }
|
||||||
func lit4Lesson(_ id: Int) -> J? { lit4.first { $0.int("id") == id } }
|
func lit4Lesson(_ id: Int) -> J? { lit4.first { $0.int("id") == id } }
|
||||||
|
func chemLesson(_ id: Int) -> J? { chem.first { $0.int("id") == id } }
|
||||||
|
func bioLesson(_ id: Int) -> J? { bio.first { $0.int("id") == id } }
|
||||||
func mluv(_ n: Int) -> J? { mluvnice.first { $0.int("id") == n } }
|
func mluv(_ n: Int) -> J? { mluvnice.first { $0.int("id") == n } }
|
||||||
func book(_ id: String) -> J? { books.first { $0.str("id") == id } }
|
func book(_ id: String) -> J? { books.first { $0.str("id") == id } }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ final class ProgressStore {
|
||||||
func lit4Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit4.\(id)") }
|
func lit4Done(_ id: Int) -> Bool { defaults.bool(forKey: "lit4.\(id)") }
|
||||||
func markLit4(_ id: Int) { defaults.set(true, forKey: "lit4.\(id)") }
|
func markLit4(_ id: Int) { defaults.set(true, forKey: "lit4.\(id)") }
|
||||||
|
|
||||||
|
func chemDone(_ id: Int) -> Bool { defaults.bool(forKey: "chem.\(id)") }
|
||||||
|
func markChem(_ id: Int) { defaults.set(true, forKey: "chem.\(id)") }
|
||||||
|
func bioDone(_ id: Int) -> Bool { defaults.bool(forKey: "bio.\(id)") }
|
||||||
|
func markBio(_ id: Int) { defaults.set(true, forKey: "bio.\(id)") }
|
||||||
|
|
||||||
func mluvDone(_ n: Int) -> Bool { defaults.bool(forKey: "mluv.\(n)") }
|
func mluvDone(_ n: Int) -> Bool { defaults.bool(forKey: "mluv.\(n)") }
|
||||||
func markMluv(_ n: Int) { defaults.set(true, forKey: "mluv.\(n)") }
|
func markMluv(_ n: Int) { defaults.set(true, forKey: "mluv.\(n)") }
|
||||||
|
|
||||||
|
|
@ -162,6 +167,22 @@ func summarize(_ content: Content, _ p: ProgressStore) -> ProgressSum {
|
||||||
sum.doneUnits += 1
|
sum.doneUnits += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for l in content.chem {
|
||||||
|
sum.totalEx += 1
|
||||||
|
sum.openUnits += 1
|
||||||
|
if p.chemDone(l.int("id")) {
|
||||||
|
sum.doneEx += 1
|
||||||
|
sum.doneUnits += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for l in content.bio {
|
||||||
|
sum.totalEx += 1
|
||||||
|
sum.openUnits += 1
|
||||||
|
if p.bioDone(l.int("id")) {
|
||||||
|
sum.doneEx += 1
|
||||||
|
sum.doneUnits += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
sum.totalEx += content.mluvnice.count
|
sum.totalEx += content.mluvnice.count
|
||||||
sum.openUnits += 1
|
sum.openUnits += 1
|
||||||
let md = content.mluvnice.filter { p.mluvDone($0.int("id")) }.count
|
let md = content.mluvnice.filter { p.mluvDone($0.int("id")) }.count
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,13 @@ enum Route: Hashable {
|
||||||
case lit4Map
|
case lit4Map
|
||||||
case lit4Lesson(Int)
|
case lit4Lesson(Int)
|
||||||
case lit4Ex(Int)
|
case lit4Ex(Int)
|
||||||
|
case sciMap
|
||||||
|
case chemMap
|
||||||
|
case chemLesson(Int)
|
||||||
|
case chemEx(Int)
|
||||||
|
case bioMap
|
||||||
|
case bioLesson(Int)
|
||||||
|
case bioEx(Int)
|
||||||
case czechMap
|
case czechMap
|
||||||
case mluvnice
|
case mluvnice
|
||||||
case mluvEx(Int)
|
case mluvEx(Int)
|
||||||
|
|
@ -100,6 +107,13 @@ enum Route: Hashable {
|
||||||
case .lit4Map: return "lit4map"
|
case .lit4Map: return "lit4map"
|
||||||
case .lit4Lesson(let id): return "lit4unit\(id)"
|
case .lit4Lesson(let id): return "lit4unit\(id)"
|
||||||
case .lit4Ex(let id): return "lit4ex\(id)"
|
case .lit4Ex(let id): return "lit4ex\(id)"
|
||||||
|
case .sciMap: return "scimap"
|
||||||
|
case .chemMap: return "chemmap"
|
||||||
|
case .chemLesson(let id): return "chemunit\(id)"
|
||||||
|
case .chemEx(let id): return "chemex\(id)"
|
||||||
|
case .bioMap: return "biomap"
|
||||||
|
case .bioLesson(let id): return "biounit\(id)"
|
||||||
|
case .bioEx(let id): return "bioex\(id)"
|
||||||
case .czechMap: return "czechmap"
|
case .czechMap: return "czechmap"
|
||||||
case .mluvnice: return "mluvnice"
|
case .mluvnice: return "mluvnice"
|
||||||
case .mluvEx(let n): return "mluve\(n)"
|
case .mluvEx(let n): return "mluve\(n)"
|
||||||
|
|
@ -200,6 +214,20 @@ enum Route: Hashable {
|
||||||
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id)]
|
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id)]
|
||||||
case .lit4Ex(let id):
|
case .lit4Ex(let id):
|
||||||
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id), .lit4Ex(id)]
|
return [.czechMap, .litYears, .lit4Map, .lit4Lesson(id), .lit4Ex(id)]
|
||||||
|
case .sciMap:
|
||||||
|
return [.sciMap]
|
||||||
|
case .chemMap:
|
||||||
|
return [.sciMap, .chemMap]
|
||||||
|
case .chemLesson(let id):
|
||||||
|
return [.sciMap, .chemMap, .chemLesson(id)]
|
||||||
|
case .chemEx(let id):
|
||||||
|
return [.sciMap, .chemMap, .chemLesson(id), .chemEx(id)]
|
||||||
|
case .bioMap:
|
||||||
|
return [.sciMap, .bioMap]
|
||||||
|
case .bioLesson(let id):
|
||||||
|
return [.sciMap, .bioMap, .bioLesson(id)]
|
||||||
|
case .bioEx(let id):
|
||||||
|
return [.sciMap, .bioMap, .bioLesson(id), .bioEx(id)]
|
||||||
case .czechMap:
|
case .czechMap:
|
||||||
return [.czechMap]
|
return [.czechMap]
|
||||||
case .mluvnice:
|
case .mluvnice:
|
||||||
|
|
@ -238,6 +266,9 @@ func routeFromPage(_ page: String) -> Route? {
|
||||||
case "lit2map": return .lit2Map
|
case "lit2map": return .lit2Map
|
||||||
case "lit3map": return .lit3Map
|
case "lit3map": return .lit3Map
|
||||||
case "lit4map": return .lit4Map
|
case "lit4map": return .lit4Map
|
||||||
|
case "scimap": return .sciMap
|
||||||
|
case "chemmap": return .chemMap
|
||||||
|
case "biomap": return .bioMap
|
||||||
case "czechmap": return .czechMap
|
case "czechmap": return .czechMap
|
||||||
case "mluvnice": return .mluvnice
|
case "mluvnice": return .mluvnice
|
||||||
case "readinglist": return .readingList
|
case "readinglist": return .readingList
|
||||||
|
|
@ -281,6 +312,18 @@ func routeFromPage(_ page: String) -> Route? {
|
||||||
if let m = page.wholeMatch(of: /hwex(\d+)/), let n = Int(m.1) {
|
if let m = page.wholeMatch(of: /hwex(\d+)/), let n = Int(m.1) {
|
||||||
return .hwEx(n)
|
return .hwEx(n)
|
||||||
}
|
}
|
||||||
|
if let m = page.wholeMatch(of: /chemunit(\d+)/), let n = Int(m.1) {
|
||||||
|
return .chemLesson(n)
|
||||||
|
}
|
||||||
|
if let m = page.wholeMatch(of: /chemex(\d+)/), let n = Int(m.1) {
|
||||||
|
return .chemEx(n)
|
||||||
|
}
|
||||||
|
if let m = page.wholeMatch(of: /biounit(\d+)/), let n = Int(m.1) {
|
||||||
|
return .bioLesson(n)
|
||||||
|
}
|
||||||
|
if let m = page.wholeMatch(of: /bioex(\d+)/), let n = Int(m.1) {
|
||||||
|
return .bioEx(n)
|
||||||
|
}
|
||||||
if let m = page.wholeMatch(of: /lit4unit(\d+)/), let n = Int(m.1) {
|
if let m = page.wholeMatch(of: /lit4unit(\d+)/), let n = Int(m.1) {
|
||||||
return .lit4Lesson(n)
|
return .lit4Lesson(n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -607,6 +607,7 @@ func subjectSymbol(_ icon: String) -> String {
|
||||||
case "chip": return "cpu"
|
case "chip": return "cpu"
|
||||||
case "cz": return "text.book.closed.fill"
|
case "cz": return "text.book.closed.fill"
|
||||||
case "people": return "person.2.fill"
|
case "people": return "person.2.fill"
|
||||||
|
case "flask": return "flask.fill"
|
||||||
default: return "lock.fill"
|
default: return "lock.fill"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -625,6 +625,27 @@ struct NetQuizScreen: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SciQuizScreen: View {
|
||||||
|
@ObservedObject var vm: AppModel
|
||||||
|
let area: String
|
||||||
|
let id: Int
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let lesson = area == "bio" ? vm.content.bioLesson(id) : vm.content.chemLesson(id)
|
||||||
|
if let lesson {
|
||||||
|
let spec = J([
|
||||||
|
"type": "choice",
|
||||||
|
"title": vm.tr(lesson.str("exTitleKey")),
|
||||||
|
"sub": lesson.str("quizHeadKey"),
|
||||||
|
"questions": lesson.rawArray("quiz"),
|
||||||
|
])
|
||||||
|
DispatchExercise(vm: vm, spec: spec, titleFallback: vm.tr(lesson.str("exTitleKey"))) {
|
||||||
|
if area == "bio" { vm.markBio(id) } else { vm.markChem(id) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct LitYearQuizScreen: View {
|
struct LitYearQuizScreen: View {
|
||||||
@ObservedObject var vm: AppModel
|
@ObservedObject var vm: AppModel
|
||||||
let year: Int
|
let year: Int
|
||||||
|
|
|
||||||
|
|
@ -695,6 +695,10 @@ private func subjectSum(_ vm: AppModel, _ s: J) -> ProgressSum {
|
||||||
+ vm.content.on2.filter { vm.progress.on2Done($0.int("id")) }.count
|
+ vm.content.on2.filter { vm.progress.on2Done($0.int("id")) }.count
|
||||||
+ vm.content.on3.filter { vm.progress.on3Done($0.int("id")) }.count
|
+ vm.content.on3.filter { vm.progress.on3Done($0.int("id")) }.count
|
||||||
+ vm.content.on4.filter { vm.progress.on4Done($0.int("id")) }.count
|
+ vm.content.on4.filter { vm.progress.on4Done($0.int("id")) }.count
|
||||||
|
case "scimap":
|
||||||
|
sum.totalEx = vm.content.chem.count + vm.content.bio.count
|
||||||
|
sum.doneEx = vm.content.chem.filter { vm.progress.chemDone($0.int("id")) }.count
|
||||||
|
+ vm.content.bio.filter { vm.progress.bioDone($0.int("id")) }.count
|
||||||
case "czechmap":
|
case "czechmap":
|
||||||
let litCount = vm.content.lit.count + vm.content.lit2.count + vm.content.lit3.count + vm.content.lit4.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
|
let litDone = vm.content.lit.filter { vm.progress.litDone($0.int("id")) }.count
|
||||||
|
|
@ -925,6 +929,16 @@ private func buildSearch(_ vm: AppModel) -> [Hit] {
|
||||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit\(l.int("id"))", extra: "literatura")
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit\(l.int("id"))", extra: "literatura")
|
||||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex\(l.int("id"))")
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex\(l.int("id"))")
|
||||||
}
|
}
|
||||||
|
add(vm.tr("Chemie"), vm.tr("search_lesson"), "chemmap", extra: "chemie")
|
||||||
|
add(vm.tr("Biologie"), vm.tr("search_lesson"), "biomap", extra: "biologie")
|
||||||
|
for l in vm.content.chem {
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "chemunit\(l.int("id"))", extra: "chemie")
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "chemex\(l.int("id"))")
|
||||||
|
}
|
||||||
|
for l in vm.content.bio {
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "biounit\(l.int("id"))", extra: "biologie")
|
||||||
|
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "bioex\(l.int("id"))")
|
||||||
|
}
|
||||||
add(vm.tr("Mluvnice"), vm.tr("search_lesson"), "mluvnice")
|
add(vm.tr("Mluvnice"), vm.tr("search_lesson"), "mluvnice")
|
||||||
add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist")
|
add(vm.tr("Maturitní četba"), vm.tr("search_book"), "readinglist")
|
||||||
for b in vm.content.books {
|
for b in vm.content.books {
|
||||||
|
|
@ -1471,6 +1485,50 @@ struct LitYearsScreen: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SciMapScreen: View {
|
||||||
|
@ObservedObject var vm: AppModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
#if os(macOS)
|
||||||
|
MacFillGrid(count: 2, minWidth: 260, minHeight: 180) { i in
|
||||||
|
if i == 0 {
|
||||||
|
NavigationLink(value: Route.chemMap) {
|
||||||
|
MacLinkCard(title: vm.tr("Chemie"), subtitle: vm.tr("chem_sub"), systemImage: "flask.fill")
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
} else {
|
||||||
|
NavigationLink(value: Route.bioMap) {
|
||||||
|
MacLinkCard(title: vm.tr("Biologie"), subtitle: vm.tr("bio_sub"), systemImage: "leaf.fill")
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle(vm.tr("Základy Přírodopisných věd"))
|
||||||
|
.navigationSubtitle(vm.tr("sci_sub"))
|
||||||
|
#else
|
||||||
|
List {
|
||||||
|
NavigationLink(value: Route.chemMap) {
|
||||||
|
Label {
|
||||||
|
ListRowLabel(title: vm.tr("Chemie"), subtitle: vm.tr("chem_sub"))
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "flask.fill")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NavigationLink(value: Route.bioMap) {
|
||||||
|
Label {
|
||||||
|
ListRowLabel(title: vm.tr("Biologie"), subtitle: vm.tr("bio_sub"))
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "leaf.fill")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle(vm.tr("Základy Přírodopisných věd"))
|
||||||
|
.navigationSubtitle(vm.tr("sci_sub"))
|
||||||
|
.appListStyle()
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct CzechMapScreen: View {
|
struct CzechMapScreen: View {
|
||||||
@ObservedObject var vm: AppModel
|
@ObservedObject var vm: AppModel
|
||||||
|
|
||||||
|
|
@ -2151,6 +2209,50 @@ struct RouteDestination: View {
|
||||||
}
|
}
|
||||||
case .lit4Ex(let id):
|
case .lit4Ex(let id):
|
||||||
LitYearQuizScreen(vm: vm, year: 4, id: id)
|
LitYearQuizScreen(vm: vm, year: 4, id: id)
|
||||||
|
case .sciMap:
|
||||||
|
SciMapScreen(vm: vm)
|
||||||
|
case .chemMap:
|
||||||
|
LessonListScreen(
|
||||||
|
vm: vm,
|
||||||
|
title: vm.tr("Chemie"),
|
||||||
|
subtitle: vm.tr("chem_sub"),
|
||||||
|
rows: vm.content.chem.map { l in
|
||||||
|
let id = l.int("id")
|
||||||
|
return LessonRow(
|
||||||
|
id: "c\(id)",
|
||||||
|
title: vm.tr(l.str("titleKey")),
|
||||||
|
done: vm.progress.chemDone(id),
|
||||||
|
destination: .chemLesson(id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case .chemLesson(let id):
|
||||||
|
if let l = vm.content.chemLesson(id) {
|
||||||
|
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .chemEx(id))
|
||||||
|
}
|
||||||
|
case .chemEx(let id):
|
||||||
|
SciQuizScreen(vm: vm, area: "chem", id: id)
|
||||||
|
case .bioMap:
|
||||||
|
LessonListScreen(
|
||||||
|
vm: vm,
|
||||||
|
title: vm.tr("Biologie"),
|
||||||
|
subtitle: vm.tr("bio_sub"),
|
||||||
|
rows: vm.content.bio.map { l in
|
||||||
|
let id = l.int("id")
|
||||||
|
return LessonRow(
|
||||||
|
id: "b\(id)",
|
||||||
|
title: vm.tr(l.str("titleKey")),
|
||||||
|
done: vm.progress.bioDone(id),
|
||||||
|
destination: .bioLesson(id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case .bioLesson(let id):
|
||||||
|
if let l = vm.content.bioLesson(id) {
|
||||||
|
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .bioEx(id))
|
||||||
|
}
|
||||||
|
case .bioEx(let id):
|
||||||
|
SciQuizScreen(vm: vm, area: "bio", id: id)
|
||||||
case .mluvnice:
|
case .mluvnice:
|
||||||
LessonListScreen(
|
LessonListScreen(
|
||||||
vm: vm,
|
vm: vm,
|
||||||
|
|
|
||||||
|
|
@ -1109,6 +1109,8 @@ def main() -> int:
|
||||||
lit2_lessons = lit_pack("lit2")
|
lit2_lessons = lit_pack("lit2")
|
||||||
lit3_lessons = lit_pack("lit3")
|
lit3_lessons = lit_pack("lit3")
|
||||||
lit4_lessons = lit_pack("lit4")
|
lit4_lessons = lit_pack("lit4")
|
||||||
|
chem_lessons = lit_pack("chem")
|
||||||
|
bio_lessons = lit_pack("bio")
|
||||||
|
|
||||||
on_lessons = []
|
on_lessons = []
|
||||||
for i in range(1, 18):
|
for i in range(1, 18):
|
||||||
|
|
@ -1559,7 +1561,7 @@ def main() -> int:
|
||||||
{"key": "English", "open": False, "target": None, "icon": "lock"},
|
{"key": "English", "open": False, "target": None, "icon": "lock"},
|
||||||
{"key": "Matematika", "open": False, "target": None, "icon": "lock"},
|
{"key": "Matematika", "open": False, "target": None, "icon": "lock"},
|
||||||
{"key": "Fyzika", "open": False, "target": None, "icon": "lock"},
|
{"key": "Fyzika", "open": False, "target": None, "icon": "lock"},
|
||||||
{"key": "Základy Přírodopisných věd", "open": False, "target": None, "icon": "lock"},
|
{"key": "Základy Přírodopisných věd", "open": True, "target": "scimap", "icon": "flask"},
|
||||||
{"key": "Technická grafika", "open": False, "target": None, "icon": "lock"},
|
{"key": "Technická grafika", "open": False, "target": None, "icon": "lock"},
|
||||||
{"key": "Prezentační grafika", "open": False, "target": None, "icon": "lock"},
|
{"key": "Prezentační grafika", "open": False, "target": None, "icon": "lock"},
|
||||||
{"key": "Programování", "open": False, "target": None, "icon": "lock"},
|
{"key": "Programování", "open": False, "target": None, "icon": "lock"},
|
||||||
|
|
@ -1581,6 +1583,8 @@ def main() -> int:
|
||||||
"lit2": lit2_lessons,
|
"lit2": lit2_lessons,
|
||||||
"lit3": lit3_lessons,
|
"lit3": lit3_lessons,
|
||||||
"lit4": lit4_lessons,
|
"lit4": lit4_lessons,
|
||||||
|
"chem": chem_lessons,
|
||||||
|
"bio": bio_lessons,
|
||||||
"on2": on2_lessons,
|
"on2": on2_lessons,
|
||||||
"on3": on3_lessons,
|
"on3": on3_lessons,
|
||||||
"on4": on4_lessons,
|
"on4": on4_lessons,
|
||||||
|
|
@ -1620,6 +1624,8 @@ def main() -> int:
|
||||||
print(f" hw lessons: {sum(1 for L in hw_lessons if L['slides'])}")
|
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" 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" lit lessons: {sum(1 for L in lit_lessons + lit2_lessons + lit3_lessons + lit4_lessons if L['slides'])}")
|
||||||
|
print(f" chem lessons: {sum(1 for L in chem_lessons if L['slides'])}")
|
||||||
|
print(f" bio lessons: {sum(1 for L in bio_lessons if L['slides'])}")
|
||||||
print(f" on2 lessons: {sum(1 for L in on2_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" 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'])}")
|
print(f" on4 lessons: {sum(1 for L in on4_lessons if L['slides'])}")
|
||||||
|
|
@ -1679,6 +1685,7 @@ def main() -> int:
|
||||||
for label, block in (
|
for label, block in (
|
||||||
("lit", lit_lessons), ("lit2", lit2_lessons),
|
("lit", lit_lessons), ("lit2", lit2_lessons),
|
||||||
("lit3", lit3_lessons), ("lit4", lit4_lessons),
|
("lit3", lit3_lessons), ("lit4", lit4_lessons),
|
||||||
|
("chem", chem_lessons), ("bio", bio_lessons),
|
||||||
):
|
):
|
||||||
for L in block:
|
for L in block:
|
||||||
if not L["slides"]:
|
if not L["slides"]:
|
||||||
|
|
|
||||||
617
src/biologie.c
Normal file
617
src/biologie.c
Normal file
|
|
@ -0,0 +1,617 @@
|
||||||
|
#include "graduately.h"
|
||||||
|
|
||||||
|
/* Biology for Základy přírodopisných věd.
|
||||||
|
* Follows the secondary-school outline: general biology, a survey of
|
||||||
|
* organisms, human biology, genetics and ecology. */
|
||||||
|
|
||||||
|
NetLesson bio_lessons[SCI_N] = {
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit1", .ex_page = "bioex1" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit2", .ex_page = "bioex2" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit3", .ex_page = "bioex3" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit4", .ex_page = "bioex4" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit5", .ex_page = "bioex5" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit6", .ex_page = "bioex6" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit7", .ex_page = "bioex7" },
|
||||||
|
{ .n_slides = 3, .unit_page = "biounit8", .ex_page = "bioex8" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit1_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Život", "Čím se živé liší",
|
||||||
|
"Tip: metabolismus je přeměna látek a energie, ne jen dýchání.",
|
||||||
|
{
|
||||||
|
"Živé soustavy mají metabolismus, dráždivost, růst a vývin.",
|
||||||
|
"Rozmnožují se a předávají dědičnou informaci.",
|
||||||
|
"Udržují stálé vnitřní prostředí, homeostázu.",
|
||||||
|
"Bez příjmu energie a látek z okolí život nepokračuje.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Řada", "Od buňky k ekosystému",
|
||||||
|
"Tip: populace je jeden druh, společenstvo je víc druhů pohromadě.",
|
||||||
|
{
|
||||||
|
"Buňka je základní stavební a funkční jednotka živého.",
|
||||||
|
"Tkáně tvoří orgány, orgány soustavy a soustavy organismus.",
|
||||||
|
"Populace jsou jedinci téhož druhu na jednom místě.",
|
||||||
|
"Společenstvo s neživým prostředím tvoří ekosystém.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Výživa", "Autotrof a heterotrof",
|
||||||
|
"Tip: zelená rostlina je autotrof, živočich heterotrof.",
|
||||||
|
{
|
||||||
|
"Autotrof tvoří organické látky z anorganických, hlavně fotosyntézou.",
|
||||||
|
"Heterotrof přijímá hotové organické látky.",
|
||||||
|
"Život na Zemi je vázaný na vodu a na zdroj energie.",
|
||||||
|
"Buňka vznikla dřív než mnohobuněčné organismy.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[0], "bio_unit1", "bio_unit1_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit1_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co je základní jednotka živých organismů?",
|
||||||
|
{"Atom", "Buňka", "Ekosystém", "Orgán"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je metabolismus?",
|
||||||
|
{"Jen pohyb živočicha",
|
||||||
|
"Přeměna látek a energie v organismu",
|
||||||
|
"Počet chromozomů",
|
||||||
|
"Rozmnožování viru mimo buňku"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je populace?",
|
||||||
|
{"Jedinci jednoho druhu na určitém místě",
|
||||||
|
"Všechny druhy v ekosystému",
|
||||||
|
"Jedna buňka",
|
||||||
|
"Neživé složky prostředí"},
|
||||||
|
4, 0},
|
||||||
|
{"Čím se autotrof liší od heterotrofa?",
|
||||||
|
{"Nemá buňky",
|
||||||
|
"Sám tvoří organické látky z anorganických",
|
||||||
|
"Nepotřebuje energii",
|
||||||
|
"Žije jen bez vody"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Buněčná teorie: nová buňka vzniká z buňky.",
|
||||||
|
"Metabolismus zahrnuje výstavbu i rozklad látek.",
|
||||||
|
"Společenstvo už sdružuje populace různých druhů.",
|
||||||
|
"Rostliny fotosyntetizují. Živočichové a houby jsou heterotrofní.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 0, "biounit1", "bio_ex1_title", "bio_quiz1_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit2_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Dva typy", "Prokaryota a eukaryota",
|
||||||
|
"Tip: bakterie nemají jádro, živočišná a rostlinná buňka ano.",
|
||||||
|
{
|
||||||
|
"Prokaryotní buňka nemá pravé jádro. Patří sem bakterie.",
|
||||||
|
"Eukaryotní buňka má jádro oddělené membránou a má organely.",
|
||||||
|
"Plazmatická membrána ohraničuje každou buňku.",
|
||||||
|
"Ribozomy vyrábějí bílkoviny v obou typech buněk.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Organely", "Co je v eukaryotní buňce",
|
||||||
|
"Tip: chloroplast mají rostliny, mitochondrii mají i živočichové.",
|
||||||
|
{
|
||||||
|
"Jádro obsahuje DNA a řídí buňku.",
|
||||||
|
"Mitochondrie uvolňují energii buněčným dýcháním.",
|
||||||
|
"Chloroplasty provádějí fotosyntézu a jsou v rostlinách.",
|
||||||
|
"Rostlinná buňka má navíc buněčnou stěnu a vakuolu.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Dělení", "Mitóza a meióza",
|
||||||
|
"Tip: člověk má 46 chromozomů, pohlavní buňka 23.",
|
||||||
|
{
|
||||||
|
"Mitóza dává dvě tělní buňky se stejnou genetickou informací.",
|
||||||
|
"Slouží k růstu, obnově a nepohlavnímu rozmnožování.",
|
||||||
|
"Meióza tvoří pohlavní buňky s polovičním počtem chromozomů.",
|
||||||
|
"Oplozením se počet chromozomů vrací na původní.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[1], "bio_unit2", "bio_unit2_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit2_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Která buňka je prokaryotní?",
|
||||||
|
{"Bakterie", "Rostlinná buňka", "Živočišná buňka", "Buňka houby s jádrem"},
|
||||||
|
4, 0},
|
||||||
|
{"Kde probíhá fotosyntéza v rostlinné buňce?",
|
||||||
|
{"V mitochondrii", "V chloroplastu", "V ribozomu", "Jen v jádře"},
|
||||||
|
4, 1},
|
||||||
|
{"K čemu slouží mitóza?",
|
||||||
|
{"Ke vzniku pohlavních buněk s poloviční sadou",
|
||||||
|
"Ke vzniku dvou geneticky stejných tělních buněk",
|
||||||
|
"K tvorbě viru",
|
||||||
|
"K odstranění jádra"},
|
||||||
|
4, 1},
|
||||||
|
{"Kolik chromozomů má lidská pohlavní buňka?",
|
||||||
|
{"46", "23", "92", "2"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Prokaryota nemají pravé jádro. Eukaryota ano.",
|
||||||
|
"Chloroplast je zelený a je v rostlinách a některých protistech.",
|
||||||
|
"Meióza, ne mitóza, snižuje počet chromozomů na polovinu.",
|
||||||
|
"Tělní buňka má 46, spermie a vajíčko po 23.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 1, "biounit2", "bio_ex2_title", "bio_quiz2_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit3_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Virus", "Na hranici živého",
|
||||||
|
"Tip: virus není buňka a sám se mimo hostitele nemnoží.",
|
||||||
|
{
|
||||||
|
"Virus má nukleovou kyselinu v bílkovinném obalu.",
|
||||||
|
"Nemá vlastní metabolismus a množí se jen v hostitelské buňce.",
|
||||||
|
"Způsobuje třeba chřipku. Antibiotika na virus nepůsobí.",
|
||||||
|
"Očkování učí imunitu poznat virus dřív, než nemoc propukne.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Bakterie a houby", "Rozkladači a původci",
|
||||||
|
"Tip: houba není rostlina, živí se hotovými organickými látkami.",
|
||||||
|
{
|
||||||
|
"Bakterie jsou prokaryota. Některé jsou symbionti, jiné patogeny.",
|
||||||
|
"V průmyslu kvasí jogurt, v přírodě rozkládají organické zbytky.",
|
||||||
|
"Houby mají buněčnou stěnu z chitinu a nemají chlorofyl.",
|
||||||
|
"Kvasinky, plísně i kloboukaté houby patří mezi houby.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Rostliny", "Kořen, stonek, list",
|
||||||
|
"Tip: fotosyntéza běží hlavně v listech, v chloroplastech.",
|
||||||
|
{
|
||||||
|
"Rostliny jsou autotrofní a mají buněčnou stěnu z celulózy.",
|
||||||
|
"Kořen přijímá vodu a minerály a upevňuje rostlinu.",
|
||||||
|
"Stonek nese listy a vede látky, list je hlavní místo fotosyntézy.",
|
||||||
|
"Květ slouží rozmnožování, semeno obsahuje zárodek.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[2], "bio_unit3", "bio_unit3_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit3_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Proč se virus množí jen v hostiteli?",
|
||||||
|
{"Má vlastní chloroplast, ale bez světla",
|
||||||
|
"Nemá buněčný metabolismus",
|
||||||
|
"Je to prokaryotní buňka",
|
||||||
|
"Má jádro a mitochondrie"},
|
||||||
|
4, 1},
|
||||||
|
{"Čím se houby liší od rostlin?",
|
||||||
|
{"Nemají buňky",
|
||||||
|
"Jsou heterotrofní a nemají chlorofyl",
|
||||||
|
"Mají chloroplasty navíc",
|
||||||
|
"Jsou vždy jednobuněčné prokaryota"},
|
||||||
|
4, 1},
|
||||||
|
{"Kde v rostlině probíhá většina fotosyntézy?",
|
||||||
|
{"V kořeni", "V listu", "Jen v květu", "Ve dřevu bez chloroplastů"},
|
||||||
|
4, 1},
|
||||||
|
{"Z čeho je buněčná stěna rostlin?",
|
||||||
|
{"Z chitinu", "Z celulózy", "Z cholesterolu", "Z peptidoglykanu jako u všech hub"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Virus je nukleová kyselina v obalu. Buňku si půjčuje.",
|
||||||
|
"Chitin je stěna hub. Rostliny mají celulózu a chlorofyl.",
|
||||||
|
"List má nejvíc chloroplastů. Kořen je většinou pod zemí.",
|
||||||
|
"Rostliny: celulóza. Houby: chitin. Bakterie: peptidoglykan.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 2, "biounit3", "bio_ex3_title", "bio_quiz3_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit4_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Bezobratlí", "Hmyz a další",
|
||||||
|
"Tip: hmyz má tři páry nohou a tělo ze tří částí.",
|
||||||
|
{
|
||||||
|
"Bezobratlí nemají vnitřní kostru z obratlů.",
|
||||||
|
"Kroužkovci, třeba žížala, mají článkované tělo.",
|
||||||
|
"Měkkýši mají měkké tělo, často schránku. Patří sem hlemýžď.",
|
||||||
|
"Hmyz má hlavu, hruď a zadeček a šest nohou.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Obratlovci", "Pět tříd, které škola probírá",
|
||||||
|
"Tip: ptáci i savci mají stálou tělesnou teplotu.",
|
||||||
|
{
|
||||||
|
"Ryby dýchají žábrami a žijí ve vodě.",
|
||||||
|
"Obojživelníci mají larvu ve vodě a vlhkou kůži, třeba žába.",
|
||||||
|
"Plazi mají suchou kůži se šupinami a vejce s obalem.",
|
||||||
|
"Ptáci mají peří, savci srst a mláďata krmí mlékem.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Vývoj", "Jak číst příbuznost",
|
||||||
|
"Tip: vývoj není žebřík od horšího k dokonalému člověku.",
|
||||||
|
{
|
||||||
|
"Druhy se mění v čase. Společný předek vysvětluje podobnost.",
|
||||||
|
"Obratlovci jsou jedna větev, ne vrchol všech živočichů.",
|
||||||
|
"Hmyz je druhově nejbohatší skupina živočichů.",
|
||||||
|
"Přizpůsobení prostředí se týká stavby těla i chování.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[3], "bio_unit4", "bio_unit4_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit4_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Kolik nohou má hmyz?",
|
||||||
|
{"Čtyři", "Šest", "Osm", "Deset"},
|
||||||
|
4, 1},
|
||||||
|
{"Čím dýchají ryby?",
|
||||||
|
{"Plicemi jako savci", "Žábrami", "Jen kůží bez cév", "Vzdušnicemi jako hmyz"},
|
||||||
|
4, 1},
|
||||||
|
{"Který znak patří ptákům?",
|
||||||
|
{"Mléčné žlázy", "Peří", "Žábry u dospělce", "Tělo bez kostry"},
|
||||||
|
4, 1},
|
||||||
|
{"Čím savci živí mláďata?",
|
||||||
|
{"Vždy jen žloutkem mimo tělo", "Mlékem",
|
||||||
|
"Fotosyntézou mláděte", "Filtrací vody žábrami"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Tři páry nohou jsou šest. Pavouci mají osm a nejsou hmyz.",
|
||||||
|
"Žábry berou kyslík z vody. Dospělá žába už dýchá plícemi a kůží.",
|
||||||
|
"Peří je ptačí znak. Srst a mléko patří savcům.",
|
||||||
|
"Mléčné žlázy jsou znak savců. Ptáci vejce zahřívají.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 3, "biounit4", "bio_ex4_title", "bio_quiz4_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit5_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Pohyb", "Kostra a svaly",
|
||||||
|
"Tip: kost je živá tkáň, ne jen minerál.",
|
||||||
|
{
|
||||||
|
"Kostra dává oporu, chrání orgány a je zásobárna vápníku.",
|
||||||
|
"Sval se upíná na kost šlachou a pohyb vzniká jeho stahem.",
|
||||||
|
"Kloub spojuje kosti pohyblivě.",
|
||||||
|
"Páteř chrání míchu.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Oběh", "Srdce a krev",
|
||||||
|
"Tip: malý oběh vede krev do plic, velký do těla.",
|
||||||
|
{
|
||||||
|
"Srdce člověka má dvě síně a dvě komory.",
|
||||||
|
"Pravá komora žene krev do plic, levá do těla.",
|
||||||
|
"Tepny vedou krev ze srdce, žíly do srdce.",
|
||||||
|
"V plicních sklípcích se do krve dostává kyslík a odchází oxid uhličitý.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Trávení", "Od úst k ledvinám",
|
||||||
|
"Tip: živiny se vstřebávají hlavně v tenkém střevě.",
|
||||||
|
{
|
||||||
|
"V ústech začíná mechanické a chemické zpracování potravy.",
|
||||||
|
"Žaludek kyselinou a enzymy pokračuje v trávení bílkovin.",
|
||||||
|
"Tenké střevo živiny vstřebá, tlusté hlavně vodu.",
|
||||||
|
"Ledviny filtrují krev a tvoří moč, játra zpracovávají živiny.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[4], "bio_unit5", "bio_unit5_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit5_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Kolik dutin má srdce člověka?",
|
||||||
|
{"Dvě", "Tři", "Čtyři", "Jednu"},
|
||||||
|
4, 2},
|
||||||
|
{"Kam vede malý krevní oběh?",
|
||||||
|
{"Z levé komory do celého těla", "Z pravé komory do plic",
|
||||||
|
"Z jater do žaludku", "Z ledvin do střeva"},
|
||||||
|
4, 1},
|
||||||
|
{"Kde se vstřebává většina živin?",
|
||||||
|
{"V jícnu", "V tenkém střevě", "V tlustém střevě jako cukry", "Ve slezině"},
|
||||||
|
4, 1},
|
||||||
|
{"Co tvoří ledviny?",
|
||||||
|
{"Žluč", "Moč", "Insulin", "Slinu"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Dvě síně a dvě komory. Mezi pravou a levou polovinou je přepážka.",
|
||||||
|
"Malý oběh okysličuje krev. Velký ji rozvádí tělem.",
|
||||||
|
"Klky tenkého střeva zvětšují plochu. Tlusté střevo hlavně zahušťuje.",
|
||||||
|
"Játra tvoří žluč. Slinivka insulin. Ledviny moč.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 4, "biounit5", "bio_ex5_title", "bio_quiz5_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit6_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Nervy", "Řízení organismu",
|
||||||
|
"Tip: mozek a mícha jsou ústřední nervová soustava.",
|
||||||
|
{
|
||||||
|
"Nervová soustava vede vzruchy rychle a cíleně.",
|
||||||
|
"Mozek a mícha tvoří ústřední část, nervy obvodovou.",
|
||||||
|
"Reflex je odpověď na podnět, třeba ucuknutí od horka.",
|
||||||
|
"Smysly převádějí podněty z okolí na vzruch.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Hormony", "Pomalejší řízení",
|
||||||
|
"Tip: insulin ze slinivky snižuje hladinu glukózy v krvi.",
|
||||||
|
{
|
||||||
|
"Hormony jsou signální látky přenášené krví.",
|
||||||
|
"Štítná žláza ovlivňuje metabolismus, nadledviny stresovou odpověď.",
|
||||||
|
"Insulin snižuje glykemii, glukagon ji zvyšuje.",
|
||||||
|
"Pohlavní hormony řídí dospívání a rozmnožování.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Obrana", "Rozmnožování a imunita",
|
||||||
|
"Tip: očkování připraví imunitu, aniž by člověk nemoc prodělal.",
|
||||||
|
{
|
||||||
|
"Spermie a vajíčko mají po 23 chromozomech, zygota 46.",
|
||||||
|
"Oplození spojí genetickou informaci obou rodičů.",
|
||||||
|
"Bílé krvinky a protilátky patří k imunitě.",
|
||||||
|
"Imunita rozliší vlastní buňky od cizích a od patogenů.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[5], "bio_unit6", "bio_unit6_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit6_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co tvoří ústřední nervovou soustavu?",
|
||||||
|
{"Jen obvodové nervy", "Mozek a mícha",
|
||||||
|
"Jen štítná žláza", "Srdce a plíce"},
|
||||||
|
4, 1},
|
||||||
|
{"Co dělá insulin?",
|
||||||
|
{"Zvyšuje množství glukózy v krvi",
|
||||||
|
"Snižuje hladinu glukózy v krvi",
|
||||||
|
"Tvoří moč",
|
||||||
|
"Nahrazuje červené krvinky"},
|
||||||
|
4, 1},
|
||||||
|
{"Kolik chromozomů má lidská zygota?",
|
||||||
|
{"23", "46", "92 v každé běžné tělní buňce navíc", "2"},
|
||||||
|
4, 1},
|
||||||
|
{"K čemu je očkování?",
|
||||||
|
{"Aby virus získal buňku",
|
||||||
|
"Aby se imunita naučila poznat patogen předem",
|
||||||
|
"Aby nahradilo všechny bílé krvinky natrvalo",
|
||||||
|
"Aby zastavilo mitózu"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Obvodové nervy spojují ústředí se smysly a svaly.",
|
||||||
|
"Insulin vyrábí slinivka. Jeho nedostatek je podstatou cukrovky 1. typu.",
|
||||||
|
"23 + 23 = 46. Pohlavní buňky jsou haploidní, zygota diploidní.",
|
||||||
|
"Vakcína je antigen, který imunitní paměť připraví.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 5, "biounit6", "bio_ex6_title", "bio_quiz6_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit7_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • DNA", "Gen a alela",
|
||||||
|
"Tip: gen je úsek DNA, alela je jeho konkrétní forma.",
|
||||||
|
{
|
||||||
|
"DNA nese dědičnou informaci a je v chromozomech.",
|
||||||
|
"Gen je úsek DNA, který ovlivňuje určitý znak.",
|
||||||
|
"Alely jsou varianty téhož genu.",
|
||||||
|
"Dominantní alela se projeví i v jedné kopii, recesivní až ve dvou.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Mendel", "Genotyp a fenotyp",
|
||||||
|
"Tip: fenotyp je to, co vidíme, genotyp je zápis alel.",
|
||||||
|
{
|
||||||
|
"Johann Gregor Mendel sledoval dědičnost na hrachu.",
|
||||||
|
"Při křížení se alely rozcházejí do pohlavních buněk.",
|
||||||
|
"Genotyp je sestava alel, fenotyp je jejich projev.",
|
||||||
|
"Ne každý znak řídí jediný gen a prostředí projev také mění.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Změna", "Mutace a pohlaví",
|
||||||
|
"Tip: u člověka je typická žena XX a typický muž XY.",
|
||||||
|
{
|
||||||
|
"Mutace je změna DNA. Může být neutrální, škodlivá, nebo vzácně užitečná.",
|
||||||
|
"Mutace v pohlavní buňce se může přenést na potomka.",
|
||||||
|
"Pohlavní chromozomy člověka jsou X a Y.",
|
||||||
|
"Kombinace XX odpovídá ženě, XY muži.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[6], "bio_unit7", "bio_unit7_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit7_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co je gen?",
|
||||||
|
{"Celá buňka", "Úsek DNA ovlivňující znak",
|
||||||
|
"Druh bílkoviny v potravě", "Hormon štítné žlázy"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je fenotyp?",
|
||||||
|
{"Sestava alel v buňce", "Pozorovatelný projev znaku",
|
||||||
|
"Počet ribozomů", "Vzorec glukózy"},
|
||||||
|
4, 1},
|
||||||
|
{"Kdy se projeví recesivní alela?",
|
||||||
|
{"Vždycky, i když je v páru s dominantní",
|
||||||
|
"Až když jsou recesivní obě alely",
|
||||||
|
"Jen u bakterií",
|
||||||
|
"Jen jako mutace viru"},
|
||||||
|
4, 1},
|
||||||
|
{"Která sestava chromozomů odpovídá muži?",
|
||||||
|
{"XX", "XY", "YY jako jediná možnost u savců", "Jen autozomy bez X a Y"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Alela je varianta genu. Chromozom nese mnoho genů.",
|
||||||
|
"Genotyp je zápis, fenotyp je výsledek genů a prostředí.",
|
||||||
|
"Heterozygot s dominantní alelou má dominantní fenotyp.",
|
||||||
|
"XX je žena, XY muž. Y nese gen pro vývoj varlat.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 6, "biounit7", "bio_ex7_title", "bio_quiz7_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit8_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Úrovně", "Od jedince k biosféře",
|
||||||
|
"Tip: ekosystém zahrnuje živé i neživé.",
|
||||||
|
{
|
||||||
|
"Ekologie zkoumá vztahy organismů mezi sebou a k prostředí.",
|
||||||
|
"Populace, společenstvo a ekosystém jsou tři navazující úrovně.",
|
||||||
|
"Biosféra je všechny ekosystémy Země.",
|
||||||
|
"Abiotické faktory jsou světlo, voda, teplota, vzduch a půda.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Potravní vztahy", "Kdo koho živí",
|
||||||
|
"Tip: na každý další článek řetězce zbývá méně energie.",
|
||||||
|
{
|
||||||
|
"Producenti, hlavně rostliny, vážou energii fotosyntézou.",
|
||||||
|
"Konzumenti se živí jinými organismy.",
|
||||||
|
"Rozkladači, bakterie a houby, vracejí látky do koloběhu.",
|
||||||
|
"V potravním řetězci se většina energie ztrácí jako teplo.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Člověk", "Prostředí a ochrana",
|
||||||
|
"Tip: fotosyntéza váže CO2, dýchání a spalování ho vracejí.",
|
||||||
|
{
|
||||||
|
"Člověk mění krajinu, klima i biodiverzitu.",
|
||||||
|
"Znečištění, kácení a nadměrný lov snižují rozmanitost druhů.",
|
||||||
|
"Koloběh uhlíku spojuje fotosyntézu, dýchání a spalování.",
|
||||||
|
"Ochrana přírody drží životní podmínky i pro člověka.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(1, &bio_lessons[7], "bio_unit8", "bio_unit8_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_bio_unit8_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co je ekosystém?",
|
||||||
|
{"Jen jedinci jednoho druhu",
|
||||||
|
"Společenstvo spolu s neživým prostředím",
|
||||||
|
"Jedna buňka",
|
||||||
|
"Jen atmosféra bez organismů"},
|
||||||
|
4, 1},
|
||||||
|
{"Kdo je v ekosystému producent?",
|
||||||
|
{"Dravec", "Zelená rostlina", "Houba rozkladač", "Virus"},
|
||||||
|
4, 1},
|
||||||
|
{"Co dělají rozkladači?",
|
||||||
|
{"Vyrábějí kyslík fotosyntézou jako hlavní producenti",
|
||||||
|
"Rozkládají organické zbytky a vracejí látky do koloběhu",
|
||||||
|
"Jsou vždy obratlovci",
|
||||||
|
"Nahrazují producenty v moři i na souši jako rostliny"},
|
||||||
|
4, 1},
|
||||||
|
{"Proč je na vrcholu potravního řetězce málo energie?",
|
||||||
|
{"Protože se na každém článku část energie ztratí",
|
||||||
|
"Protože producenti energii nevytvářejí",
|
||||||
|
"Protože rozkladači energii zdvojnásobí",
|
||||||
|
"Protože slunce ekosystém neovlivňuje"},
|
||||||
|
4, 0},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Společenstvo jsou živé složky. Ekosystém k nim přidává neživé.",
|
||||||
|
"Producent je autotrof. Konzument je heterotrof, který někoho žere.",
|
||||||
|
"Bakterie a houby mineralizují zbytky. Rostliny je znovu využijí.",
|
||||||
|
"Škola často uvádí, že na další hladinu přejde jen malá část energie.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(1, 7, "biounit8", "bio_ex8_title", "bio_quiz8_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_bio_pages(GtkStack *stack) {
|
||||||
|
typedef GtkWidget *(*SciBuilder)(void);
|
||||||
|
static const struct {
|
||||||
|
const char *unit_name;
|
||||||
|
const char *ex_name;
|
||||||
|
SciBuilder build_unit;
|
||||||
|
SciBuilder build_ex;
|
||||||
|
} pages[] = {
|
||||||
|
{"biounit1", "bioex1", build_bio_unit1_page, build_bio_unit1_exercise_page},
|
||||||
|
{"biounit2", "bioex2", build_bio_unit2_page, build_bio_unit2_exercise_page},
|
||||||
|
{"biounit3", "bioex3", build_bio_unit3_page, build_bio_unit3_exercise_page},
|
||||||
|
{"biounit4", "bioex4", build_bio_unit4_page, build_bio_unit4_exercise_page},
|
||||||
|
{"biounit5", "bioex5", build_bio_unit5_page, build_bio_unit5_exercise_page},
|
||||||
|
{"biounit6", "bioex6", build_bio_unit6_page, build_bio_unit6_exercise_page},
|
||||||
|
{"biounit7", "bioex7", build_bio_unit7_page, build_bio_unit7_exercise_page},
|
||||||
|
{"biounit8", "bioex8", build_bio_unit8_page, build_bio_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
604
src/chemie.c
Normal file
604
src/chemie.c
Normal file
|
|
@ -0,0 +1,604 @@
|
||||||
|
#include "graduately.h"
|
||||||
|
|
||||||
|
/* Chemistry for Základy přírodopisných věd.
|
||||||
|
* Follows the secondary-school outline (RVP for vocational schools,
|
||||||
|
* přírodovědné vzdělávání, and the gymnasium general-chemistry track):
|
||||||
|
* general chemistry, inorganic chemistry, organic chemistry, biochemistry. */
|
||||||
|
|
||||||
|
NetLesson chem_lessons[SCI_N] = {
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit1", .ex_page = "chemex1" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit2", .ex_page = "chemex2" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit3", .ex_page = "chemex3" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit4", .ex_page = "chemex4" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit5", .ex_page = "chemex5" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit6", .ex_page = "chemex6" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit7", .ex_page = "chemex7" },
|
||||||
|
{ .n_slides = 3, .unit_page = "chemunit8", .ex_page = "chemex8" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit1_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Atom", "Z čeho je látka",
|
||||||
|
"Tip: protonové číslo je počet protonů, ne elektronů.",
|
||||||
|
{
|
||||||
|
"Atom má jádro z protonů a neutronů a obal z elektronů.",
|
||||||
|
"Proton má kladný náboj, elektron záporný, neutron je bez náboje.",
|
||||||
|
"Protonové číslo Z udává počet protonů a určuje prvek.",
|
||||||
|
"Nukleonové číslo A je součet protonů a neutronů.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Tabulka", "Periody a skupiny",
|
||||||
|
"Tip: perioda je řádek, skupina je sloupec.",
|
||||||
|
{
|
||||||
|
"Periodická soustava řadí prvky podle rostoucího protonového čísla.",
|
||||||
|
"Prvky v jedné skupině mají podobné chemické vlastnosti.",
|
||||||
|
"Číslo periody souvisí s počtem obsazených slupek.",
|
||||||
|
"Vlevo jsou kovy, vpravo nekovy, mezi nimi polokovy.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Částice", "Atom, molekula, ion",
|
||||||
|
"Tip: kation vzniká ztrátou elektronů, anion jejich přijetím.",
|
||||||
|
{
|
||||||
|
"Prvek tvoří atomy se stejným protonovým číslem.",
|
||||||
|
"Molekula je částice ze dvou nebo více atomů spojených vazbou.",
|
||||||
|
"Ion je nabitá částice: kation je kladný, anion záporný.",
|
||||||
|
"Izotopy jednoho prvku se liší počtem neutronů, ne protonů.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[0], "chem_unit1", "chem_unit1_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit1_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co udává protonové číslo?",
|
||||||
|
{"Počet protonů v jádře", "Počet neutronů v jádře",
|
||||||
|
"Součet protonů a elektronů v molekule", "Hmotnost atomu v gramech"},
|
||||||
|
4, 0},
|
||||||
|
{"Jaký náboj má elektron?",
|
||||||
|
{"Kladný", "Záporný", "Žádný", "Stejný jako neutron"},
|
||||||
|
4, 1},
|
||||||
|
{"Co mají společného prvky v jedné skupině?",
|
||||||
|
{"Stejné nukleonové číslo", "Podobné chemické vlastnosti",
|
||||||
|
"Stejný počet neutronů", "Stejné skupenství za pokojové teploty"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je v periodické soustavě perioda?",
|
||||||
|
{"Sloupec prvků", "Řádek prvků",
|
||||||
|
"Jen skupina vzácných plynů", "Rozdíl protonů a neutronů"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Z je počet protonů a zároveň pořadí prvku v tabulce.",
|
||||||
|
"Proton je kladný, elektron záporný, neutron neutrální.",
|
||||||
|
"Skupina je sloupec. Podobné vlastnosti plynou z podobného obalu.",
|
||||||
|
"Perioda je řádek. Číslo periody souvisí s obsazenými slupkami.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 0, "chemunit1", "chem_ex1_title", "chem_quiz1_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit2_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Ionty", "Iontová vazba",
|
||||||
|
"Tip: NaCl je typická iontová sloučenina.",
|
||||||
|
{
|
||||||
|
"Iontová vazba vzniká přenosem elektronů mezi atomy.",
|
||||||
|
"Kov odevzdá elektrony a stane se kationtem, nekov je přijme jako anion.",
|
||||||
|
"Opačné náboje se přitahují a drží krystal pohromadě.",
|
||||||
|
"Iontové látky mají vysoké teploty tání a v tavenině vedou proud.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Sdílení", "Kovalentní vazba",
|
||||||
|
"Tip: ve vodě atomy elektrony sdílejí, nepředávají si je natrvalo.",
|
||||||
|
{
|
||||||
|
"Kovalentní vazba vzniká sdílením elektronového páru.",
|
||||||
|
"Jednoduchá vazba je jeden pár, dvojná dva, trojná tři.",
|
||||||
|
"Nepolární vazba spojuje atomy se stejnou elektronegativitou, třeba H2.",
|
||||||
|
"Polární vazba vzniká mezi atomy s různou elektronegativitou, třeba v H2O.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Kovy", "Kovová vazba",
|
||||||
|
"Tip: volné elektrony vysvětlují lesk i vodivost kovů.",
|
||||||
|
{
|
||||||
|
"V kovu jsou kationty obklopené sdílenými elektrony.",
|
||||||
|
"Elektrony se mohou posouvat, proto kov vede proud a teplo.",
|
||||||
|
"Elektronegativita je schopnost atomu přitahovat elektrony vazby.",
|
||||||
|
"Velký rozdíl elektronegativit vede spíš k iontové vazbě.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[1], "chem_unit2", "chem_unit2_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit2_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Jaká vazba drží krystal chloridu sodného?",
|
||||||
|
{"Kovalentní nepolární", "Iontová", "Kovová", "Vodíkový můstek jako jediná"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je kovalentní vazba?",
|
||||||
|
{"Přenos elektronu z kovu na nekov",
|
||||||
|
"Sdílení elektronového páru",
|
||||||
|
"Pohyb volných elektronů mezi kationty kovu",
|
||||||
|
"Přitažlivost jen mezi molekulami vody"},
|
||||||
|
4, 1},
|
||||||
|
{"Proč kovy vedou elektrický proud?",
|
||||||
|
{"Mají pevné jádro bez elektronů",
|
||||||
|
"Obsahují pohyblivé elektrony kovové vazby",
|
||||||
|
"Jsou vždy kapalné",
|
||||||
|
"Nemají protony"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je elektronegativita?",
|
||||||
|
{"Počet neutronů v jádře",
|
||||||
|
"Schopnost atomu přitahovat elektrony vazby",
|
||||||
|
"Hmotnost jednoho molu",
|
||||||
|
"Teplota varu kovu"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Sodík předá elektron chloru. Vznikne Na+ a Cl−.",
|
||||||
|
"Kovalentní vazba je společný elektronový pár, ne trvalý přenos.",
|
||||||
|
"Kovová vazba má volné elektrony, které přenášejí náboj.",
|
||||||
|
"Čím větší rozdíl elektronegativit, tím polárnější nebo iontovější vazba.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 1, "chemunit2", "chem_ex2_title", "chem_quiz2_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit3_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Rovnice", "Co se při reakci zachová",
|
||||||
|
"Tip: vyčíslit znamená srovnat počty atomů, ne měnit vzorce.",
|
||||||
|
{
|
||||||
|
"Při chemické reakci se atomy přeskupují, ale neztrácejí.",
|
||||||
|
"Zákon zachování hmotnosti: hmotnost reaktantů se rovná hmotnosti produktů.",
|
||||||
|
"V rovnici musí být na obou stranách stejný počet atomů každého prvku.",
|
||||||
|
"Koeficient před vzorcem násobí celou částici.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Mol", "Kolik je částic",
|
||||||
|
"Tip: molární hmotnost vody je přibližně 18 g/mol.",
|
||||||
|
{
|
||||||
|
"Mol je jednotka látkového množství.",
|
||||||
|
"Jeden mol obsahuje 6,022 × 10^23 částic, to je Avogadrova konstanta.",
|
||||||
|
"Molární hmotnost M je hmotnost jednoho molu v g/mol.",
|
||||||
|
"Látkové množství se počítá jako n = m / M.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Výpočet", "Od hmotnosti k molům",
|
||||||
|
"Tip: nejdřív sečti relativní atomové hmotnosti ve vzorci.",
|
||||||
|
{
|
||||||
|
"Relativní atomová hmotnost vodíku je 1, kyslíku 16, uhlíku 12.",
|
||||||
|
"Voda H2O má molární hmotnost 18 g/mol, oxid uhličitý CO2 má 44 g/mol.",
|
||||||
|
"18 g vody je 1 mol, tedy 6,022 × 10^23 molekul.",
|
||||||
|
"Stechiometrie porovnává moly podle koeficientů v rovnici.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[2], "chem_unit3", "chem_unit3_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit3_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co říká zákon zachování hmotnosti?",
|
||||||
|
{"Hmotnost produktů je vždy menší",
|
||||||
|
"Hmotnost reaktantů se rovná hmotnosti produktů",
|
||||||
|
"Atomy se při reakci ničí",
|
||||||
|
"Molární hmotnost se během reakce mění"},
|
||||||
|
4, 1},
|
||||||
|
{"Kolik částic je v jednom molu?",
|
||||||
|
{"18", "44", "6,022 × 10^23", "1000"},
|
||||||
|
4, 2},
|
||||||
|
{"Jak se spočítá látkové množství?",
|
||||||
|
{"n = m × M", "n = m / M", "n = M / m", "n = Z + A"},
|
||||||
|
4, 1},
|
||||||
|
{"Jaká je přibližně molární hmotnost vody?",
|
||||||
|
{"2 g/mol", "16 g/mol", "18 g/mol", "44 g/mol"},
|
||||||
|
4, 2},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Atomy se přeskupují. Jejich celková hmotnost zůstává.",
|
||||||
|
"Avogadrova konstanta je počet částic v jednom molu.",
|
||||||
|
"Hmotnost dělíme molární hmotností. Výsledek je v molech.",
|
||||||
|
"H2O: 1 + 1 + 16 = 18. CO2 je 12 + 16 + 16 = 44.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 2, "chemunit3", "chem_ex3_title", "chem_quiz3_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit4_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Směsi", "Čistá látka a směs",
|
||||||
|
"Tip: roztok je homogenní směs, suspenze heterogenní.",
|
||||||
|
{
|
||||||
|
"Čistá látka má stálé složení a stálé vlastnosti.",
|
||||||
|
"Směs obsahuje dvě nebo více látek, které nejsou chemicky vázané.",
|
||||||
|
"Homogenní směs, třeba roztok, vypadá v celém objemu stejně.",
|
||||||
|
"Heterogenní směs má rozlišitelné složky, třeba suspenze nebo emulze.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Roztok", "Složení roztoku",
|
||||||
|
"Tip: hmotnostní zlomek je podíl hmotnosti složky a hmotnosti směsi.",
|
||||||
|
{
|
||||||
|
"Rozpouštědlo je látka, v níž se rozpouští rozpuštěná látka.",
|
||||||
|
"Hmotnostní zlomek w = hmotnost složky / hmotnost celé směsi.",
|
||||||
|
"Nasycený roztok už při dané teplotě další látku nerozpustí.",
|
||||||
|
"Rozpustnost většiny pevných látek s teplotou roste.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • pH", "Kyseliny a zásady",
|
||||||
|
"Tip: neutralizace kyseliny hydroxidem dává sůl a vodu.",
|
||||||
|
{
|
||||||
|
"Kyselina ve vodě zvyšuje množství H+, zásada množství OH−.",
|
||||||
|
"pH menší než 7 je kyselé, 7 neutrální, větší než 7 zásadité.",
|
||||||
|
"Silné kyseliny jsou třeba HCl a H2SO4, silná zásada je NaOH.",
|
||||||
|
"Neutralizace: kyselina + hydroxid → sůl + voda.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[3], "chem_unit4", "chem_unit4_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit4_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co je roztok?",
|
||||||
|
{"Heterogenní směs dvou kovů", "Homogenní směs",
|
||||||
|
"Čistý prvek", "Jen sraženina na dně"},
|
||||||
|
4, 1},
|
||||||
|
{"Jaké pH má kyselý roztok?",
|
||||||
|
{"Přesně 7", "Menší než 7", "Větší než 7", "Vždy 14"},
|
||||||
|
4, 1},
|
||||||
|
{"Co vzniká neutralizací kyseliny hydroxidem?",
|
||||||
|
{"Jen vodík a kyslík jako prvky", "Sůl a voda",
|
||||||
|
"Uhlovodík", "Vzácný plyn"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je hmotnostní zlomek?",
|
||||||
|
{"Podíl hmotnosti složky a hmotnosti směsi",
|
||||||
|
"Počet molů v litru",
|
||||||
|
"Rozdíl pH a 7",
|
||||||
|
"Hmotnost jednoho protonu"},
|
||||||
|
4, 0},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Roztok je stejnorodý. Suspenze a emulze jsou různorodé.",
|
||||||
|
"Neutrální pH je 7. Pod ním je kyselina, nad ním zásada.",
|
||||||
|
"H+ z kyseliny a OH− ze zásady dají vodu, zbytek iontů sůl.",
|
||||||
|
"w = m(složky) / m(směsi). Nemá jednotku, nebo se uvádí v procentech.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 3, "chemunit4", "chem_ex4_title", "chem_quiz4_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit5_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Názvy", "Čtyři skupiny sloučenin",
|
||||||
|
"Tip: oxid uhličitý je CO2, oxid uhelnatý je CO.",
|
||||||
|
{
|
||||||
|
"Oxidy jsou sloučeniny prvku s kyslíkem.",
|
||||||
|
"Kyseliny ve vzorci obsahují vodík, který mohou odštěpit jako H+.",
|
||||||
|
"Hydroxidy obsahují skupinu OH, soli vznikají z kyseliny náhradou vodíku.",
|
||||||
|
"NaCl je chlorid sodný, NaOH hydroxid sodný, HCl kyselina chlorovodíková.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Nekovy", "Halogeny, kyslík, dusík",
|
||||||
|
"Tip: halogeny jsou ve 17. skupině a jsou velmi reaktivní.",
|
||||||
|
{
|
||||||
|
"Kyslík O2 tvoří asi pětinu vzduchu a je nutný k dýchání i hoření.",
|
||||||
|
"Halogeny fluor, chlor, brom a jod tvoří soli, halogenidy.",
|
||||||
|
"Dusík N2 tvoří většinu vzduchu a je v bílkovinách i v hnojivech.",
|
||||||
|
"Síra je v kyselině sírové H2SO4, důležité průmyslové kyselině.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Kovy", "Sodík, vápník, železo",
|
||||||
|
"Tip: alkalické kovy reagují s vodou a musí se uchovávat pod petrolejem.",
|
||||||
|
{
|
||||||
|
"Alkalické kovy lithium, sodík a draslík jsou měkké a velmi reaktivní.",
|
||||||
|
"Vápník a hořčík patří ke kovům alkalických zemin a jsou v kostech i chlorofylu.",
|
||||||
|
"Železo je přechodný kov, základ oceli, a v těle je v hemoglobinu.",
|
||||||
|
"Ušlechtilé kovy, třeba zlato, vzdorují korozi víc než železo.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[4], "chem_unit5", "chem_unit5_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit5_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Který vzorec patří oxidu uhličitému?",
|
||||||
|
{"CO", "CO2", "H2CO3", "CaCO3"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je hydroxid sodný?",
|
||||||
|
{"NaCl", "NaOH", "HCl", "H2SO4"},
|
||||||
|
4, 1},
|
||||||
|
{"Které prvky jsou halogeny?",
|
||||||
|
{"Li, Na, K", "F, Cl, Br, I", "Fe, Cu, Zn", "He, Ne, Ar"},
|
||||||
|
4, 1},
|
||||||
|
{"Kam patří sodík a draslík?",
|
||||||
|
{"Mezi vzácné plyny", "Mezi alkalické kovy",
|
||||||
|
"Mezi halogeny", "Mezi polokovy"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"CO je oxid uhelnatý, CO2 oxid uhličitý. H2CO3 je kyselina uhličitá.",
|
||||||
|
"Hydroxidy končí na OH. NaOH je silná zásada.",
|
||||||
|
"Halogeny jsou 17. skupina. Alkalické kovy jsou 1. skupina.",
|
||||||
|
"Li, Na a K jsou alkalické kovy. S vodou reagují bouřlivě.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 4, "chemunit5", "chem_ex5_title", "chem_quiz5_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit6_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Uhlík", "Proč existuje organická chemie",
|
||||||
|
"Tip: organické sloučeniny staví řetězce a kruhy z uhlíku.",
|
||||||
|
{
|
||||||
|
"Organická chemie zkoumá sloučeniny uhlíku, kromě oxidů a uhličitanů.",
|
||||||
|
"Uhlík tvoří čtyři vazby a může se řetězit.",
|
||||||
|
"Uhlovodíky obsahují jen uhlík a vodík.",
|
||||||
|
"Nasycené mají jen jednoduché vazby, nenasycené i dvojné nebo trojné.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Řady", "Alkany, alkeny a alkyny",
|
||||||
|
"Tip: obecný vzorec alkanů je CnH2n+2.",
|
||||||
|
{
|
||||||
|
"Alkany jsou nasycené. Methan CH4 je nejjednodušší.",
|
||||||
|
"Alkeny mají dvojnou vazbu. Ethen C2H4 je surovina pro plasty.",
|
||||||
|
"Alkyny mají trojnou vazbu. Ethyn, acetylen, se používá ke svařování.",
|
||||||
|
"Hořením uhlovodíků vzniká oxid uhličitý a voda.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Areny", "Benzen",
|
||||||
|
"Tip: benzen není alken se třemi obyčejnými dvojnými vazbami.",
|
||||||
|
{
|
||||||
|
"Areny jsou aromatické uhlovodíky s zvláštně stálým kruhem.",
|
||||||
|
"Benzen má vzorec C6H6.",
|
||||||
|
"Aromatický kruh je stálejší než obyčejné střídání dvojných vazeb.",
|
||||||
|
"Z arenů se vyrábějí plasty, léčiva i barviva.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[5], "chem_unit6", "chem_unit6_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit6_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Který uhlovodík je alkan?",
|
||||||
|
{"Ethen", "Ethyn", "Methan", "Benzen"},
|
||||||
|
4, 2},
|
||||||
|
{"Jaký je obecný vzorec alkanů?",
|
||||||
|
{"CnH2n", "CnH2n+2", "CnH2n−2", "CnH2n−6"},
|
||||||
|
4, 1},
|
||||||
|
{"Čím se ethen liší od ethanu?",
|
||||||
|
{"Nemá uhlík", "Má dvojnou vazbu",
|
||||||
|
"Je to kov", "Má trojnou vazbu"},
|
||||||
|
4, 1},
|
||||||
|
{"Jaký vzorec má benzen?",
|
||||||
|
{"CH4", "C2H4", "C2H2", "C6H6"},
|
||||||
|
4, 3},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Methan a ethan jsou alkany. Ethen je alken, ethyn alkyn, benzen aren.",
|
||||||
|
"Alkany CnH2n+2, alkeny CnH2n, alkyny CnH2n−2.",
|
||||||
|
"Ethan je nasycený. Ethen má jednu dvojnou vazbu.",
|
||||||
|
"Benzen C6H6 je základní aren. Methan je CH4.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 5, "chemunit6", "chem_ex6_title", "chem_quiz6_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit7_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Skupiny", "Deriváty uhlovodíků",
|
||||||
|
"Tip: funkční skupina rozhoduje o vlastnostech víc než délka řetězce.",
|
||||||
|
{
|
||||||
|
"Derivát vzniká náhradou vodíku jinou skupinou atomů.",
|
||||||
|
"Alkoholy mají hydroxyl −OH. Ethanol je v alkoholických nápojích.",
|
||||||
|
"Karboxylové kyseliny mají −COOH. Kyselina octová je v octu.",
|
||||||
|
"Aldehydy a ketony obsahují karbonylovou skupinu C=O.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Cukry", "Sacharidy",
|
||||||
|
"Tip: glukóza je monosacharid, škrob a celulóza jsou její polymery.",
|
||||||
|
{
|
||||||
|
"Sacharidy jsou přírodní látky z uhlíku, vodíku a kyslíku.",
|
||||||
|
"Glukóza C6H12O6 je základní cukr a palivo buněk.",
|
||||||
|
"Sacharosa je řepný a třtinový cukr, škrob je zásoba rostlin.",
|
||||||
|
"Celulóza tvoří buněčné stěny rostlin a člověk ji netráví.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • Tuky a bílkoviny", "Z čeho je tělo",
|
||||||
|
"Tip: bílkovina je řetězec aminokyselin, tuk je ester glycerolu.",
|
||||||
|
{
|
||||||
|
"Lipidy jsou tuky a oleje, estery glycerolu a mastných kyselin.",
|
||||||
|
"Tuky jsou zásoba energie a součást membrán.",
|
||||||
|
"Bílkoviny vznikají spojením aminokyselin peptidovou vazbou.",
|
||||||
|
"Pořadí aminokyselin určuje tvar a funkci bílkoviny.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[6], "chem_unit7", "chem_unit7_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit7_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Kterou skupinu mají alkoholy?",
|
||||||
|
{"−COOH", "−OH", "−NH2 jako jedinou v alkanech", "Jen dvojnou vazbu uhlík–uhlík"},
|
||||||
|
4, 1},
|
||||||
|
{"Co je kyselina octová?",
|
||||||
|
{"Alkan", "Karboxylová kyselina", "Halogen", "Hydroxid"},
|
||||||
|
4, 1},
|
||||||
|
{"Která látka je sacharid?",
|
||||||
|
{"Škrob", "Chlorid sodný", "Ethyn", "Oxid vápenatý"},
|
||||||
|
4, 0},
|
||||||
|
{"Z čeho jsou bílkoviny?",
|
||||||
|
{"Z glycerolu a nic jiného", "Z aminokyselin",
|
||||||
|
"Jen z glukózy", "Z vzácných plynů"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Hydroxyl −OH je alkohol. Karboxyl −COOH je kyselina.",
|
||||||
|
"Octová kyselina CH3COOH má karboxyl. V octu je její zředěný roztok.",
|
||||||
|
"Glukóza, sacharosa, škrob a celulóza jsou sacharidy.",
|
||||||
|
"Aminokyseliny se pojí peptidovou vazbou do bílkoviny.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 6, "chemunit7", "chem_ex7_title", "chem_quiz7_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit8_page(void) {
|
||||||
|
static const NetSlide slides[] = {
|
||||||
|
{
|
||||||
|
"1 / 3 • Enzymy", "Biokatalyzátory",
|
||||||
|
"Tip: enzym je bílkovina a urychluje jednu určitou reakci.",
|
||||||
|
{
|
||||||
|
"Biochemie zkoumá chemické děje v živých organismech.",
|
||||||
|
"Enzym je bílkovinný katalyzátor. Snižuje aktivační energii.",
|
||||||
|
"Každý enzym působí na určitý substrát, jako klíč do zámku.",
|
||||||
|
"Teplo a nevhodné pH enzym denaturují a reakce se zpomalí.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"2 / 3 • Energie", "Fotosyntéza a dýchání",
|
||||||
|
"Tip: fotosyntéza váže energii, buněčné dýchání ji uvolňuje.",
|
||||||
|
{
|
||||||
|
"Fotosyntéza: 6 CO2 + 6 H2O → C6H12O6 + 6 O2, potřebuje světlo.",
|
||||||
|
"Probíhá v chloroplastech a je zdrojem kyslíku i organických látek.",
|
||||||
|
"Buněčné dýchání glukózu oxiduje a uvolňuje energii pro buňku.",
|
||||||
|
"Zjednodušeně je dýchání opačný směr než fotosyntéza.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"3 / 3 • DNA", "Chemický zápis dědičnosti",
|
||||||
|
"Tip: v RNA je uracil tam, kde má DNA thymin.",
|
||||||
|
{
|
||||||
|
"Nukleové kyseliny jsou DNA a RNA.",
|
||||||
|
"DNA nese genetickou informaci. Báze jsou adenin, thymin, guanin a cytosin.",
|
||||||
|
"Adenin se páruje s thyminem, guanin s cytosinem.",
|
||||||
|
"RNA má místo thyminu uracil a v buňce pomáhá číst geny.",
|
||||||
|
NULL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_unit_page(0, &chem_lessons[7], "chem_unit8", "chem_unit8_sub",
|
||||||
|
slides, G_N_ELEMENTS(slides));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *build_chem_unit8_exercise_page(void) {
|
||||||
|
static const ChoiceQ qs[] = {
|
||||||
|
{"Co je enzym?",
|
||||||
|
{"Anorganická sůl", "Bílkovinný biokatalyzátor",
|
||||||
|
"Vzácný plyn", "Nasycený uhlovodík"},
|
||||||
|
4, 1},
|
||||||
|
{"Co při fotosyntéze vzniká spolu s glukózou?",
|
||||||
|
{"Dusík", "Kyslík", "Chlorid sodný", "Železo"},
|
||||||
|
4, 1},
|
||||||
|
{"Která báze je v RNA místo thyminu?",
|
||||||
|
{"Adenin", "Uracil", "Guanin navíc bez cytosinu", "Sodík"},
|
||||||
|
4, 1},
|
||||||
|
{"Co dělá buněčné dýchání s glukózou?",
|
||||||
|
{"Ukládá ji beze změny do jádra",
|
||||||
|
"Oxiduje ji a uvolňuje energii",
|
||||||
|
"Mění ji na vzácný plyn",
|
||||||
|
"Zastavuje všechny enzymy"},
|
||||||
|
4, 1},
|
||||||
|
};
|
||||||
|
static const char *hints[] = {
|
||||||
|
"Enzym je bílkovina. Katalyzátor reakci urychlí a sám se nespotřebuje.",
|
||||||
|
"Zjednodušená rovnice končí glukózou a kyslíkem.",
|
||||||
|
"DNA: A, T, G, C. RNA má U místo T.",
|
||||||
|
"Dýchání je opak fotosyntézy v tom smyslu, že energii z glukózy uvolní.",
|
||||||
|
};
|
||||||
|
|
||||||
|
return sci_mcq_page(0, 7, "chemunit8", "chem_ex8_title", "chem_quiz8_head",
|
||||||
|
qs, hints, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_chem_pages(GtkStack *stack) {
|
||||||
|
typedef GtkWidget *(*SciBuilder)(void);
|
||||||
|
static const struct {
|
||||||
|
const char *unit_name;
|
||||||
|
const char *ex_name;
|
||||||
|
SciBuilder build_unit;
|
||||||
|
SciBuilder build_ex;
|
||||||
|
} pages[] = {
|
||||||
|
{"chemunit1", "chemex1", build_chem_unit1_page, build_chem_unit1_exercise_page},
|
||||||
|
{"chemunit2", "chemex2", build_chem_unit2_page, build_chem_unit2_exercise_page},
|
||||||
|
{"chemunit3", "chemex3", build_chem_unit3_page, build_chem_unit3_exercise_page},
|
||||||
|
{"chemunit4", "chemex4", build_chem_unit4_page, build_chem_unit4_exercise_page},
|
||||||
|
{"chemunit5", "chemex5", build_chem_unit5_page, build_chem_unit5_exercise_page},
|
||||||
|
{"chemunit6", "chemex6", build_chem_unit6_page, build_chem_unit6_exercise_page},
|
||||||
|
{"chemunit7", "chemex7", build_chem_unit7_page, build_chem_unit7_exercise_page},
|
||||||
|
{"chemunit8", "chemex8", build_chem_unit8_page, build_chem_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#define HW_SUBJ 2 /* index of "Technické vybavení" */
|
#define HW_SUBJ 2 /* index of "Technické vybavení" */
|
||||||
#define CZ_SUBJ 3 /* index of "Český jazyk a literatura" */
|
#define CZ_SUBJ 3 /* index of "Český jazyk a literatura" */
|
||||||
#define ON_SUBJ 4 /* index of "Občanská nauka" */
|
#define ON_SUBJ 4 /* index of "Občanská nauka" */
|
||||||
|
#define SCI_SUBJ 8 /* index of "Základy Přírodopisných věd" */
|
||||||
#define CSS_FILE "style.css"
|
#define CSS_FILE "style.css"
|
||||||
#define CHANGELOG_FILE "changelog.txt"
|
#define CHANGELOG_FILE "changelog.txt"
|
||||||
#define APP_ID "org.maturita.Maturita"
|
#define APP_ID "org.maturita.Maturita"
|
||||||
|
|
@ -59,6 +60,8 @@ extern char *app_progress_lit;
|
||||||
extern char *app_progress_lit2;
|
extern char *app_progress_lit2;
|
||||||
extern char *app_progress_lit3;
|
extern char *app_progress_lit3;
|
||||||
extern char *app_progress_lit4;
|
extern char *app_progress_lit4;
|
||||||
|
extern char *app_progress_chem;
|
||||||
|
extern char *app_progress_bio;
|
||||||
#define PROGRESS_DIR app_progress_dir
|
#define PROGRESS_DIR app_progress_dir
|
||||||
#define PROGRESS_U1 app_progress_u1
|
#define PROGRESS_U1 app_progress_u1
|
||||||
#define PROGRESS_U2 app_progress_u2
|
#define PROGRESS_U2 app_progress_u2
|
||||||
|
|
@ -136,6 +139,7 @@ extern char *app_progress_lit4;
|
||||||
#define ON4_UNITS 16
|
#define ON4_UNITS 16
|
||||||
#define ON4_LESSONS 16
|
#define ON4_LESSONS 16
|
||||||
#define LIT_N 8
|
#define LIT_N 8
|
||||||
|
#define SCI_N 8
|
||||||
#define HW_SLIDES 3
|
#define HW_SLIDES 3
|
||||||
#define HW2_SLIDES 6
|
#define HW2_SLIDES 6
|
||||||
#define HW3_SLIDES 2
|
#define HW3_SLIDES 2
|
||||||
|
|
@ -929,6 +933,23 @@ extern NetLesson lit_lessons[LIT_N];
|
||||||
extern NetLesson lit2_lessons[LIT_N];
|
extern NetLesson lit2_lessons[LIT_N];
|
||||||
extern NetLesson lit3_lessons[LIT_N];
|
extern NetLesson lit3_lessons[LIT_N];
|
||||||
extern NetLesson lit4_lessons[LIT_N];
|
extern NetLesson lit4_lessons[LIT_N];
|
||||||
|
void sci_load_progress(void);
|
||||||
|
void sci_rail_theme_reset(void);
|
||||||
|
void sci_lessons_apply_lang(void);
|
||||||
|
void progress_for_sci(ProgressSum *out);
|
||||||
|
GtkWidget *sci_unit_page(int area, NetLesson *L, const char *title_key,
|
||||||
|
const char *sub_key, const NetSlide *slides,
|
||||||
|
guint n_slides);
|
||||||
|
GtkWidget *sci_mcq_page(int area, 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_scimap_page(void);
|
||||||
|
GtkWidget *build_chemmap_page(void);
|
||||||
|
GtkWidget *build_biomap_page(void);
|
||||||
|
void add_chem_pages(GtkStack *stack);
|
||||||
|
void add_bio_pages(GtkStack *stack);
|
||||||
|
extern NetLesson chem_lessons[SCI_N];
|
||||||
|
extern NetLesson bio_lessons[SCI_N];
|
||||||
void hw_lessons_apply_lang(void);
|
void hw_lessons_apply_lang(void);
|
||||||
GtkWidget *build_hwyears_page(void);
|
GtkWidget *build_hwyears_page(void);
|
||||||
GtkWidget *build_hwmap_page(void);
|
GtkWidget *build_hwmap_page(void);
|
||||||
|
|
@ -1016,6 +1037,8 @@ void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
int width, int height, gpointer data);
|
int width, int height, gpointer data);
|
||||||
void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr,
|
void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
int width, int height, gpointer data);
|
int width, int height, gpointer data);
|
||||||
|
void draw_science_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
|
int width, int height, gpointer data);
|
||||||
void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,
|
void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,
|
||||||
int width, int height, gpointer data);
|
int width, int height, gpointer data);
|
||||||
void draw_book_icon(GtkDrawingArea *area, cairo_t *cr,
|
void draw_book_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
|
|
|
||||||
102
src/i18n.c
102
src/i18n.c
|
|
@ -90,12 +90,12 @@ const TrEntry tr_ui[] = {
|
||||||
"Cvičení, nápovědy a vokabeltraining. Aplikace si pamatuje, kde jste skončili.",
|
"Cvičení, nápovědy a vokabeltraining. Aplikace si pamatuje, kde jste skončili.",
|
||||||
"Exercises, hints and vocabulary drills. The app remembers where you left off."},
|
"Exercises, hints and vocabulary drills. The app remembers where you left off."},
|
||||||
{"welcome_feat1_link", "Začít procvičovat", "Start practicing"},
|
{"welcome_feat1_link", "Začít procvičovat", "Start practicing"},
|
||||||
{"welcome_feat2_title", "Čtyři otevřené předměty", "Four open subjects"},
|
{"welcome_feat2_title", "Šest otevřených předmětů", "Six open subjects"},
|
||||||
{"welcome_feat2_body",
|
{"welcome_feat2_body",
|
||||||
"Deutsch, sítě, hardware a čeština. Ostatní předměty čekají na svůj obsah.",
|
"Deutsch, sítě, hardware, čeština, občanská nauka a přírodní vědy. Ostatní předměty čekají na svůj obsah.",
|
||||||
"German, networks, hardware and Czech. The other subjects are still locked."},
|
"German, networks, hardware, Czech, civics and natural sciences. The other subjects are still locked."},
|
||||||
{"welcome_feat2_link", "Jaké předměty jsou otevřené?", "Which subjects are open?"},
|
{"welcome_feat2_link", "Jaké předměty jsou otevřené?", "Which subjects are open?"},
|
||||||
{"welcome_stat_value", "4", "4"},
|
{"welcome_stat_value", "6", "6"},
|
||||||
{"welcome_stat_label", "otevřené\npředměty", "open\nsubjects"},
|
{"welcome_stat_label", "otevřené\npředměty", "open\nsubjects"},
|
||||||
{"continue", "Pokračuj", "Continue"},
|
{"continue", "Pokračuj", "Continue"},
|
||||||
{"roadmap_title", "Učební plán", "Learning path"},
|
{"roadmap_title", "Učební plán", "Learning path"},
|
||||||
|
|
@ -1304,6 +1304,98 @@ const TrEntry tr_ui[] = {
|
||||||
{"lit4_ex8_title", "Kvíz: interpretace", "Quiz: interpretation"},
|
{"lit4_ex8_title", "Kvíz: interpretace", "Quiz: interpretation"},
|
||||||
{"lit4_quiz8_head", "Ověřte si postup rozboru textu",
|
{"lit4_quiz8_head", "Ověřte si postup rozboru textu",
|
||||||
"Check how to read a text"},
|
"Check how to read a text"},
|
||||||
|
{"sci_sub", "Vyberte chemii nebo biologii.", "Pick chemistry or biology."},
|
||||||
|
{"Chemie", "Chemie", "Chemistry"},
|
||||||
|
{"Biologie", "Biologie", "Biology"},
|
||||||
|
{"chem_sub", "Osm lekcí od atomu po biochemii.",
|
||||||
|
"Eight lessons from the atom to biochemistry."},
|
||||||
|
{"bio_sub", "Osm lekcí od buňky po ekologii.",
|
||||||
|
"Eight lessons from the cell to ecology."},
|
||||||
|
{"chem_unit1", "Částice a periodická soustava", "Particles and the periodic table"},
|
||||||
|
{"chem_unit1_sub", "Atom, protonové číslo, periody a skupiny.",
|
||||||
|
"The atom, atomic number, periods and groups."},
|
||||||
|
{"chem_ex1_title", "Kvíz: částice", "Quiz: particles"},
|
||||||
|
{"chem_quiz1_head", "Ověřte si stavbu atomu", "Check the structure of the atom"},
|
||||||
|
{"chem_unit2", "Chemická vazba", "Chemical bonding"},
|
||||||
|
{"chem_unit2_sub", "Iontová, kovalentní a kovová vazba.",
|
||||||
|
"Ionic, covalent and metallic bonds."},
|
||||||
|
{"chem_ex2_title", "Kvíz: vazba", "Quiz: bonding"},
|
||||||
|
{"chem_quiz2_head", "Ověřte si chemickou vazbu", "Check chemical bonding"},
|
||||||
|
{"chem_unit3", "Reakce a výpočty", "Reactions and calculations"},
|
||||||
|
{"chem_unit3_sub", "Zákon zachování hmotnosti, mol a molární hmotnost.",
|
||||||
|
"Conservation of mass, the mole and molar mass."},
|
||||||
|
{"chem_ex3_title", "Kvíz: výpočty", "Quiz: calculations"},
|
||||||
|
{"chem_quiz3_head", "Ověřte si mol a reakce", "Check the mole and reactions"},
|
||||||
|
{"chem_unit4", "Směsi, roztoky a pH", "Mixtures, solutions and pH"},
|
||||||
|
{"chem_unit4_sub", "Homogenní a heterogenní směsi, neutralizace.",
|
||||||
|
"Homogeneous and heterogeneous mixtures, neutralization."},
|
||||||
|
{"chem_ex4_title", "Kvíz: roztoky", "Quiz: solutions"},
|
||||||
|
{"chem_quiz4_head", "Ověřte si směsi a pH", "Check mixtures and pH"},
|
||||||
|
{"chem_unit5", "Anorganické látky", "Inorganic substances"},
|
||||||
|
{"chem_unit5_sub", "Oxidy, kyseliny, hydroxidy, soli a vybrané prvky.",
|
||||||
|
"Oxides, acids, hydroxides, salts and selected elements."},
|
||||||
|
{"chem_ex5_title", "Kvíz: anorganika", "Quiz: inorganic chemistry"},
|
||||||
|
{"chem_quiz5_head", "Ověřte si anorganické látky", "Check inorganic substances"},
|
||||||
|
{"chem_unit6", "Uhlovodíky", "Hydrocarbons"},
|
||||||
|
{"chem_unit6_sub", "Alkany, alkeny, alkyny a benzen.",
|
||||||
|
"Alkanes, alkenes, alkynes and benzene."},
|
||||||
|
{"chem_ex6_title", "Kvíz: uhlovodíky", "Quiz: hydrocarbons"},
|
||||||
|
{"chem_quiz6_head", "Ověřte si uhlovodíky", "Check hydrocarbons"},
|
||||||
|
{"chem_unit7", "Deriváty a přírodní látky", "Derivatives and natural substances"},
|
||||||
|
{"chem_unit7_sub", "Alkoholy, kyseliny, sacharidy a bílkoviny.",
|
||||||
|
"Alcohols, acids, carbohydrates and proteins."},
|
||||||
|
{"chem_ex7_title", "Kvíz: deriváty", "Quiz: derivatives"},
|
||||||
|
{"chem_quiz7_head", "Ověřte si deriváty a přírodní látky",
|
||||||
|
"Check derivatives and natural substances"},
|
||||||
|
{"chem_unit8", "Biochemie", "Biochemistry"},
|
||||||
|
{"chem_unit8_sub", "Enzymy, fotosyntéza, dýchání a nukleové kyseliny.",
|
||||||
|
"Enzymes, photosynthesis, respiration and nucleic acids."},
|
||||||
|
{"chem_ex8_title", "Kvíz: biochemie", "Quiz: biochemistry"},
|
||||||
|
{"chem_quiz8_head", "Ověřte si biochemii", "Check biochemistry"},
|
||||||
|
{"bio_unit1", "Živé soustavy", "Living systems"},
|
||||||
|
{"bio_unit1_sub", "Metabolismus a organizace od buňky k ekosystému.",
|
||||||
|
"Metabolism and organisation from the cell to the ecosystem."},
|
||||||
|
{"bio_ex1_title", "Kvíz: živé soustavy", "Quiz: living systems"},
|
||||||
|
{"bio_quiz1_head", "Ověřte si znaky života", "Check the features of life"},
|
||||||
|
{"bio_unit2", "Buňka", "The cell"},
|
||||||
|
{"bio_unit2_sub", "Prokaryota, eukaryota, organely a dělení.",
|
||||||
|
"Prokaryotes, eukaryotes, organelles and division."},
|
||||||
|
{"bio_ex2_title", "Kvíz: buňka", "Quiz: the cell"},
|
||||||
|
{"bio_quiz2_head", "Ověřte si stavbu buňky", "Check the structure of the cell"},
|
||||||
|
{"bio_unit3", "Viry, bakterie, houby a rostliny",
|
||||||
|
"Viruses, bacteria, fungi and plants"},
|
||||||
|
{"bio_unit3_sub", "Nebuněčné viry, prokaryota a autotrofní rostliny.",
|
||||||
|
"Acellular viruses, prokaryotes and autotrophic plants."},
|
||||||
|
{"bio_ex3_title", "Kvíz: organismy", "Quiz: organisms"},
|
||||||
|
{"bio_quiz3_head", "Ověřte si viry, houby a rostliny",
|
||||||
|
"Check viruses, fungi and plants"},
|
||||||
|
{"bio_unit4", "Živočichové", "Animals"},
|
||||||
|
{"bio_unit4_sub", "Bezobratlí a pět tříd obratlovců.",
|
||||||
|
"Invertebrates and five classes of vertebrates."},
|
||||||
|
{"bio_ex4_title", "Kvíz: živočichové", "Quiz: animals"},
|
||||||
|
{"bio_quiz4_head", "Ověřte si skupiny živočichů", "Check the animal groups"},
|
||||||
|
{"bio_unit5", "Soustavy člověka", "Human body systems"},
|
||||||
|
{"bio_unit5_sub", "Kostra, oběh, dýchání a trávení.",
|
||||||
|
"Skeleton, circulation, breathing and digestion."},
|
||||||
|
{"bio_ex5_title", "Kvíz: člověk", "Quiz: the human body"},
|
||||||
|
{"bio_quiz5_head", "Ověřte si soustavy člověka", "Check the human body systems"},
|
||||||
|
{"bio_unit6", "Řízení, rozmnožování a imunita",
|
||||||
|
"Control, reproduction and immunity"},
|
||||||
|
{"bio_unit6_sub", "Nervy, hormony, oplození a obrana organismu.",
|
||||||
|
"Nerves, hormones, fertilisation and the body's defence."},
|
||||||
|
{"bio_ex6_title", "Kvíz: řízení", "Quiz: control"},
|
||||||
|
{"bio_quiz6_head", "Ověřte si řízení a imunitu", "Check control and immunity"},
|
||||||
|
{"bio_unit7", "Genetika", "Genetics"},
|
||||||
|
{"bio_unit7_sub", "Gen, alela, Mendel a pohlavní chromozomy.",
|
||||||
|
"The gene, the allele, Mendel and the sex chromosomes."},
|
||||||
|
{"bio_ex7_title", "Kvíz: genetika", "Quiz: genetics"},
|
||||||
|
{"bio_quiz7_head", "Ověřte si dědičnost", "Check inheritance"},
|
||||||
|
{"bio_unit8", "Ekologie", "Ecology"},
|
||||||
|
{"bio_unit8_sub", "Ekosystém, potravní vztahy a člověk v prostředí.",
|
||||||
|
"The ecosystem, feeding relationships and humans in the environment."},
|
||||||
|
{"bio_ex8_title", "Kvíz: ekologie", "Quiz: ecology"},
|
||||||
|
{"bio_quiz8_head", "Ověřte si vztahy v ekosystému",
|
||||||
|
"Check relationships in an ecosystem"},
|
||||||
{"czech_sub", "Vyberte oblast a začněte procvičovat.",
|
{"czech_sub", "Vyberte oblast a začněte procvičovat.",
|
||||||
"Pick an area and start practicing."},
|
"Pick an area and start practicing."},
|
||||||
{"Literatura", "Literatura", "Literature"},
|
{"Literatura", "Literatura", "Literature"},
|
||||||
|
|
@ -2332,6 +2424,7 @@ void on2_lessons_apply_lang(void);
|
||||||
void on3_lessons_apply_lang(void);
|
void on3_lessons_apply_lang(void);
|
||||||
void on4_lessons_apply_lang(void);
|
void on4_lessons_apply_lang(void);
|
||||||
void lit_lessons_apply_lang(void);
|
void lit_lessons_apply_lang(void);
|
||||||
|
void sci_lessons_apply_lang(void);
|
||||||
void net_rail_theme_reset(void);
|
void net_rail_theme_reset(void);
|
||||||
|
|
||||||
void apply_language(void) {
|
void apply_language(void) {
|
||||||
|
|
@ -2351,5 +2444,6 @@ void apply_language(void) {
|
||||||
on3_lessons_apply_lang();
|
on3_lessons_apply_lang();
|
||||||
on4_lessons_apply_lang();
|
on4_lessons_apply_lang();
|
||||||
lit_lessons_apply_lang();
|
lit_lessons_apply_lang();
|
||||||
|
sci_lessons_apply_lang();
|
||||||
search_apply_lang();
|
search_apply_lang();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
src/icons.c
40
src/icons.c
|
|
@ -188,6 +188,46 @@ void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
cairo_stroke(cr);
|
cairo_stroke(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Round flask for Základy přírodopisných věd. */
|
||||||
|
void draw_science_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||||
|
int width, int height, gpointer data) {
|
||||||
|
const double s = MIN(width, height);
|
||||||
|
const double cx = width / 2.0;
|
||||||
|
const double top = height / 2.0 - s * 0.38;
|
||||||
|
const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent),
|
||||||
|
color_from_hex(app_theme.accent2), 0.22);
|
||||||
|
|
||||||
|
(void)area;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
cairo_set_source_rgb(cr, c.r, c.g, c.b);
|
||||||
|
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||||
|
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
||||||
|
cairo_set_line_width(cr, MAX(1.6, s * 0.07));
|
||||||
|
|
||||||
|
cairo_move_to(cr, cx - s * 0.08, top);
|
||||||
|
cairo_line_to(cr, cx - s * 0.08, top + s * 0.22);
|
||||||
|
cairo_line_to(cr, cx - s * 0.28, top + s * 0.58);
|
||||||
|
cairo_curve_to(cr, cx - s * 0.34, top + s * 0.78,
|
||||||
|
cx - s * 0.16, top + s * 0.82,
|
||||||
|
cx, top + s * 0.82);
|
||||||
|
cairo_curve_to(cr, cx + s * 0.16, top + s * 0.82,
|
||||||
|
cx + s * 0.34, top + s * 0.78,
|
||||||
|
cx + s * 0.28, top + s * 0.58);
|
||||||
|
cairo_line_to(cr, cx + s * 0.08, top + s * 0.22);
|
||||||
|
cairo_line_to(cr, cx + s * 0.08, top);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_move_to(cr, cx - s * 0.14, top);
|
||||||
|
cairo_line_to(cr, cx + s * 0.14, top);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_set_line_width(cr, MAX(1.4, s * 0.055));
|
||||||
|
cairo_move_to(cr, cx - s * 0.16, top + s * 0.62);
|
||||||
|
cairo_line_to(cr, cx + s * 0.16, top + s * 0.62);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Open book glyph, painted in the given colour. */
|
/* Open book glyph, painted in the given colour. */
|
||||||
static void book_paint(cairo_t *cr, int width, int height, Rgb c) {
|
static void book_paint(cairo_t *cr, int width, int height, Rgb c) {
|
||||||
const double w = width;
|
const double w = width;
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,9 @@ static gboolean run_smoke_test(gpointer data) {
|
||||||
"on3map", "on4map",
|
"on3map", "on4map",
|
||||||
"czechmap",
|
"czechmap",
|
||||||
"lityears", "litmap", "lit2map", "lit3map", "lit4map",
|
"lityears", "litmap", "lit2map", "lit3map", "lit4map",
|
||||||
|
"scimap", "chemmap", "biomap",
|
||||||
|
"chemunit1", "chemex1", "chemunit8", "chemex8",
|
||||||
|
"biounit1", "bioex1", "biounit8", "bioex8",
|
||||||
"litunit1", "litex1", "litunit8", "litex8",
|
"litunit1", "litex1", "litunit8", "litex8",
|
||||||
"lit2unit1", "lit2ex1", "lit3unit1", "lit3ex1",
|
"lit2unit1", "lit2ex1", "lit3unit1", "lit3ex1",
|
||||||
"lit4unit1", "lit4ex1", "lit4unit8", "lit4ex8",
|
"lit4unit1", "lit4ex1", "lit4unit8", "lit4ex8",
|
||||||
|
|
@ -525,6 +528,11 @@ void activate(GtkApplication *app, gpointer user_data) {
|
||||||
add_on3_pages(main_stack);
|
add_on3_pages(main_stack);
|
||||||
gtk_stack_add_named(main_stack, build_on4map_page(), "on4map");
|
gtk_stack_add_named(main_stack, build_on4map_page(), "on4map");
|
||||||
add_on4_pages(main_stack);
|
add_on4_pages(main_stack);
|
||||||
|
gtk_stack_add_named(main_stack, build_scimap_page(), "scimap");
|
||||||
|
gtk_stack_add_named(main_stack, build_chemmap_page(), "chemmap");
|
||||||
|
add_chem_pages(main_stack);
|
||||||
|
gtk_stack_add_named(main_stack, build_biomap_page(), "biomap");
|
||||||
|
add_bio_pages(main_stack);
|
||||||
gtk_stack_add_named(main_stack, build_czechmap_page(), "czechmap");
|
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_lityears_page(), "lityears");
|
||||||
gtk_stack_add_named(main_stack, build_litmap_page(), "litmap");
|
gtk_stack_add_named(main_stack, build_litmap_page(), "litmap");
|
||||||
|
|
|
||||||
720
src/priroda.c
Normal file
720
src/priroda.c
Normal file
|
|
@ -0,0 +1,720 @@
|
||||||
|
#include "graduately.h"
|
||||||
|
|
||||||
|
/* Základy přírodopisných věd: chemistry and biology share one subject.
|
||||||
|
* Each area is a vertical list of lessons, then slides and a quiz. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *map_page;
|
||||||
|
const char *back_page;
|
||||||
|
const char *title_key;
|
||||||
|
const char *sub_key;
|
||||||
|
char **progress_path;
|
||||||
|
NetLesson *lessons;
|
||||||
|
const char *unit_keys[SCI_N];
|
||||||
|
const char *sub_keys[SCI_N];
|
||||||
|
GtkWidget *nodes[SCI_N];
|
||||||
|
int note_last_w;
|
||||||
|
} SciTrack;
|
||||||
|
|
||||||
|
static SciTrack sci_tracks[2];
|
||||||
|
static GtkWidget *sci_rail;
|
||||||
|
static gboolean sci_ready;
|
||||||
|
|
||||||
|
static void sci_ensure(void) {
|
||||||
|
static const char *chem_units[] = {
|
||||||
|
"chem_unit1", "chem_unit2", "chem_unit3", "chem_unit4",
|
||||||
|
"chem_unit5", "chem_unit6", "chem_unit7", "chem_unit8",
|
||||||
|
};
|
||||||
|
static const char *chem_subs[] = {
|
||||||
|
"chem_unit1_sub", "chem_unit2_sub", "chem_unit3_sub", "chem_unit4_sub",
|
||||||
|
"chem_unit5_sub", "chem_unit6_sub", "chem_unit7_sub", "chem_unit8_sub",
|
||||||
|
};
|
||||||
|
static const char *bio_units[] = {
|
||||||
|
"bio_unit1", "bio_unit2", "bio_unit3", "bio_unit4",
|
||||||
|
"bio_unit5", "bio_unit6", "bio_unit7", "bio_unit8",
|
||||||
|
};
|
||||||
|
static const char *bio_subs[] = {
|
||||||
|
"bio_unit1_sub", "bio_unit2_sub", "bio_unit3_sub", "bio_unit4_sub",
|
||||||
|
"bio_unit5_sub", "bio_unit6_sub", "bio_unit7_sub", "bio_unit8_sub",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (sci_ready)
|
||||||
|
return;
|
||||||
|
sci_tracks[0].map_page = "chemmap";
|
||||||
|
sci_tracks[0].back_page = "scimap";
|
||||||
|
sci_tracks[0].title_key = "Chemie";
|
||||||
|
sci_tracks[0].sub_key = "chem_sub";
|
||||||
|
sci_tracks[0].progress_path = &app_progress_chem;
|
||||||
|
sci_tracks[0].lessons = chem_lessons;
|
||||||
|
sci_tracks[0].note_last_w = -1;
|
||||||
|
sci_tracks[1].map_page = "biomap";
|
||||||
|
sci_tracks[1].back_page = "scimap";
|
||||||
|
sci_tracks[1].title_key = "Biologie";
|
||||||
|
sci_tracks[1].sub_key = "bio_sub";
|
||||||
|
sci_tracks[1].progress_path = &app_progress_bio;
|
||||||
|
sci_tracks[1].lessons = bio_lessons;
|
||||||
|
sci_tracks[1].note_last_w = -1;
|
||||||
|
for (int i = 0; i < SCI_N; i++) {
|
||||||
|
sci_tracks[0].unit_keys[i] = chem_units[i];
|
||||||
|
sci_tracks[0].sub_keys[i] = chem_subs[i];
|
||||||
|
sci_tracks[1].unit_keys[i] = bio_units[i];
|
||||||
|
sci_tracks[1].sub_keys[i] = bio_subs[i];
|
||||||
|
}
|
||||||
|
sci_ready = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_save(SciTrack *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 < SCI_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 sci_load_one(SciTrack *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 < SCI_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 sci_load_progress(void) {
|
||||||
|
sci_ensure();
|
||||||
|
sci_load_one(&sci_tracks[0]);
|
||||||
|
sci_load_one(&sci_tracks[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_refresh(SciTrack *T) {
|
||||||
|
for (int i = 0; i < SCI_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 sci_mark_done(SciTrack *T, int lesson_id) {
|
||||||
|
if (lesson_id < 0 || lesson_id >= SCI_N)
|
||||||
|
return;
|
||||||
|
if (T->lessons[lesson_id].done)
|
||||||
|
return;
|
||||||
|
T->lessons[lesson_id].done = TRUE;
|
||||||
|
sci_save(T);
|
||||||
|
sci_refresh(T);
|
||||||
|
refresh_stats_ui();
|
||||||
|
}
|
||||||
|
|
||||||
|
void progress_for_sci(ProgressSum *out) {
|
||||||
|
if (!out)
|
||||||
|
return;
|
||||||
|
sci_ensure();
|
||||||
|
for (int a = 0; a < 2; a++) {
|
||||||
|
SciTrack *T = &sci_tracks[a];
|
||||||
|
|
||||||
|
out->total_ex += SCI_N;
|
||||||
|
out->open_units += SCI_N;
|
||||||
|
for (int i = 0; i < SCI_N; i++) {
|
||||||
|
if (T->lessons[i].done) {
|
||||||
|
out->done_ex++;
|
||||||
|
out->done_units++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_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 GtkWidget *sci_lesson_button(SciTrack *T, int index) {
|
||||||
|
GtkWidget *btn;
|
||||||
|
GtkWidget *row;
|
||||||
|
GtkWidget *num;
|
||||||
|
GtkWidget *texts;
|
||||||
|
GtkWidget *title;
|
||||||
|
GtkWidget *sub;
|
||||||
|
GtkWidget *icon;
|
||||||
|
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", index + 1);
|
||||||
|
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, T->unit_keys[index], 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, T->sub_keys[index], 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);
|
||||||
|
|
||||||
|
icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18);
|
||||||
|
gtk_widget_set_visible(icon, FALSE);
|
||||||
|
gtk_widget_set_valign(icon, GTK_ALIGN_CENTER);
|
||||||
|
gtk_box_append(GTK_BOX(row), icon);
|
||||||
|
T->lessons[index].done_icon = icon;
|
||||||
|
T->nodes[index] = btn;
|
||||||
|
g_signal_connect(btn, "clicked", G_CALLBACK(sci_open_unit),
|
||||||
|
&T->lessons[index]);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *sci_build_list(SciTrack *T) {
|
||||||
|
GtkWidget *page;
|
||||||
|
GtkWidget *scroll;
|
||||||
|
GtkWidget *list;
|
||||||
|
|
||||||
|
sci_ensure();
|
||||||
|
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_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_START);
|
||||||
|
gtk_widget_set_size_request(list, 520, -1);
|
||||||
|
gtk_widget_set_margin_bottom(list, 12);
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list);
|
||||||
|
|
||||||
|
for (int i = 0; i < SCI_N; i++)
|
||||||
|
gtk_box_append(GTK_BOX(list), sci_lesson_button(T, i));
|
||||||
|
sci_refresh(T);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *build_chemmap_page(void) { return sci_build_list(&sci_tracks[0]); }
|
||||||
|
GtkWidget *build_biomap_page(void) { return sci_build_list(&sci_tracks[1]); }
|
||||||
|
|
||||||
|
#define SCI_BUBBLE SUB_BUBBLE
|
||||||
|
#define SCI_LABEL_W 180.0
|
||||||
|
#define SCI_CW 560
|
||||||
|
#define SCI_CH 280
|
||||||
|
|
||||||
|
static double sci_cx[2];
|
||||||
|
static double sci_cy[2];
|
||||||
|
|
||||||
|
static void draw_sci_rail(GtkDrawingArea *area, cairo_t *cr,
|
||||||
|
int width, int height, gpointer data) {
|
||||||
|
const Rgb rail = color_from_hex(app_theme.rail);
|
||||||
|
const Rgb slate = color_from_hex(app_theme.surface1);
|
||||||
|
|
||||||
|
(void)area;
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
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_move_to(cr, sci_cx[0], sci_cy[0]);
|
||||||
|
cairo_line_to(cr, sci_cx[1], sci_cy[1]);
|
||||||
|
cairo_set_line_width(cr, 14);
|
||||||
|
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_move_to(cr, sci_cx[0], sci_cy[0]);
|
||||||
|
cairo_line_to(cr, sci_cx[1], sci_cy[1]);
|
||||||
|
cairo_set_line_width(cr, 9);
|
||||||
|
cairo_set_source_rgb(cr, slate.r, slate.g, slate.b);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sci_rail_theme_reset(void) {
|
||||||
|
if (sci_rail)
|
||||||
|
gtk_widget_queue_draw(sci_rail);
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *build_scimap_page(void) {
|
||||||
|
GtkWidget *page;
|
||||||
|
GtkWidget *scroll;
|
||||||
|
GtkWidget *wrap;
|
||||||
|
GtkWidget *fixed;
|
||||||
|
GtkWidget *rail;
|
||||||
|
static const char *keys[] = {"Chemie", "Biologie"};
|
||||||
|
static const char *initials[] = {"C", "B"};
|
||||||
|
static const char *targets[] = {"chemmap", "biomap"};
|
||||||
|
|
||||||
|
sci_cx[0] = 160.0;
|
||||||
|
sci_cy[0] = 110.0;
|
||||||
|
sci_cx[1] = 400.0;
|
||||||
|
sci_cy[1] = 110.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("subjects", "Základy Přírodopisných věd", "sci_sub"));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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, SCI_CW, SCI_CH);
|
||||||
|
gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed);
|
||||||
|
|
||||||
|
rail = gtk_drawing_area_new();
|
||||||
|
gtk_widget_set_size_request(rail, SCI_CW, SCI_CH);
|
||||||
|
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_sci_rail,
|
||||||
|
NULL, NULL);
|
||||||
|
gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0);
|
||||||
|
sci_rail = rail;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
GtkWidget *btn = gtk_button_new();
|
||||||
|
GtkWidget *letter = gtk_label_new(initials[i]);
|
||||||
|
GtkWidget *name = gtk_label_new(NULL);
|
||||||
|
|
||||||
|
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_size_request(btn, (int)SCI_BUBBLE, (int)SCI_BUBBLE);
|
||||||
|
gtk_widget_add_css_class(letter, "unit-number");
|
||||||
|
gtk_button_set_child(GTK_BUTTON(btn), letter);
|
||||||
|
g_object_set_data_full(G_OBJECT(btn), "target",
|
||||||
|
g_strdup(targets[i]), g_free);
|
||||||
|
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
|
||||||
|
|
||||||
|
i18n_bind(name, keys[i], 0);
|
||||||
|
gtk_widget_set_size_request(name, (int)SCI_LABEL_W, -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_widget_add_css_class(name, "unit-name");
|
||||||
|
|
||||||
|
gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0);
|
||||||
|
gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0);
|
||||||
|
gtk_fixed_move(GTK_FIXED(fixed), btn,
|
||||||
|
(int)(sci_cx[i] - SCI_BUBBLE / 2.0),
|
||||||
|
(int)(sci_cy[i] - SCI_BUBBLE / 2.0));
|
||||||
|
gtk_fixed_move(GTK_FIXED(fixed), name,
|
||||||
|
(int)(sci_cx[i] - SCI_LABEL_W / 2.0),
|
||||||
|
(int)(sci_cy[i] + SCI_BUBBLE / 2.0 + 10.0));
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_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 sci_slide_prev(GtkButton *button, gpointer data) {
|
||||||
|
NetLesson *L = data;
|
||||||
|
|
||||||
|
(void)button;
|
||||||
|
if (!L || L->idx == 0)
|
||||||
|
return;
|
||||||
|
L->idx--;
|
||||||
|
sci_slide_apply(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_slide_next(GtkButton *button, gpointer data) {
|
||||||
|
NetLesson *L = data;
|
||||||
|
|
||||||
|
(void)button;
|
||||||
|
if (!L)
|
||||||
|
return;
|
||||||
|
if (L->idx + 1 < L->n_slides) {
|
||||||
|
L->idx++;
|
||||||
|
sci_slide_apply(L);
|
||||||
|
} else {
|
||||||
|
gtk_stack_set_visible_child_name(main_stack, L->ex_page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_rescale(SciTrack *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 < SCI_N; i++)
|
||||||
|
net_rescale_lesson_notes(&T->lessons[i], body, head, kick);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean sci_note_tick(GtkWidget *w, GdkFrameClock *clock,
|
||||||
|
gpointer data) {
|
||||||
|
SciTrack *T = data;
|
||||||
|
int width = gtk_widget_get_allocated_width(w);
|
||||||
|
|
||||||
|
(void)clock;
|
||||||
|
if (width != T->note_last_w) {
|
||||||
|
T->note_last_w = width;
|
||||||
|
sci_rescale(T, width);
|
||||||
|
}
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *sci_unit_page(int area, NetLesson *L, const char *title_key,
|
||||||
|
const char *sub_key, const NetSlide *slides,
|
||||||
|
guint n_slides) {
|
||||||
|
SciTrack *T;
|
||||||
|
GtkWidget *page;
|
||||||
|
GtkWidget *scroll;
|
||||||
|
GtkWidget *nav;
|
||||||
|
|
||||||
|
sci_ensure();
|
||||||
|
if (area < 0 || area > 1)
|
||||||
|
area = 0;
|
||||||
|
T = &sci_tracks[area];
|
||||||
|
|
||||||
|
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, sci_note_tick, T, NULL);
|
||||||
|
T->note_last_w = -1;
|
||||||
|
sci_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(sci_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(sci_slide_next), L);
|
||||||
|
gtk_box_append(GTK_BOX(nav), L->next_btn);
|
||||||
|
|
||||||
|
L->idx = 0;
|
||||||
|
sci_slide_apply(L);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sci_lessons_apply_lang(void) {
|
||||||
|
sci_ensure();
|
||||||
|
for (int a = 0; a < 2; a++) {
|
||||||
|
for (int i = 0; i < SCI_N; i++)
|
||||||
|
sci_slide_apply(&sci_tracks[a].lessons[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const ChoiceQ *qs;
|
||||||
|
int n;
|
||||||
|
int n_opts;
|
||||||
|
SciTrack *track;
|
||||||
|
int lesson_id;
|
||||||
|
GtkWidget *feedback;
|
||||||
|
GtkToggleButton **toggles;
|
||||||
|
GtkWidget **hints;
|
||||||
|
} SciMcqCtx;
|
||||||
|
|
||||||
|
static void sci_mcq_check(GtkButton *button, gpointer data) {
|
||||||
|
SciMcqCtx *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"));
|
||||||
|
sci_mark_done(ctx->track, ctx->lesson_id);
|
||||||
|
} else {
|
||||||
|
set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *sci_mcq_page(int area, 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;
|
||||||
|
SciMcqCtx *ctx = g_new0(SciMcqCtx, 1);
|
||||||
|
int n_opts = qs[0].n_options;
|
||||||
|
|
||||||
|
sci_ensure();
|
||||||
|
if (area < 0 || area > 1)
|
||||||
|
area = 0;
|
||||||
|
|
||||||
|
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 = &sci_tracks[area];
|
||||||
|
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(sci_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;
|
||||||
|
}
|
||||||
|
|
@ -59,6 +59,7 @@ void load_progress(void) {
|
||||||
on3_load_progress();
|
on3_load_progress();
|
||||||
on4_load_progress();
|
on4_load_progress();
|
||||||
lit_load_progress();
|
lit_load_progress();
|
||||||
|
sci_load_progress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw the exercise rails of every unit that already has a page. */
|
/* Redraw the exercise rails of every unit that already has a page. */
|
||||||
|
|
|
||||||
20
src/search.c
20
src/search.c
|
|
@ -23,7 +23,7 @@ static GPtrArray *search_items;
|
||||||
|
|
||||||
static gboolean subject_open(int i) {
|
static gboolean subject_open(int i) {
|
||||||
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
||||||
|| i == ON_SUBJ;
|
|| i == ON_SUBJ || i == SCI_SUBJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *subject_page(int i) {
|
static const char *subject_page(int i) {
|
||||||
|
|
@ -37,6 +37,8 @@ static const char *subject_page(int i) {
|
||||||
return "czechmap";
|
return "czechmap";
|
||||||
if (i == ON_SUBJ)
|
if (i == ON_SUBJ)
|
||||||
return "onyears";
|
return "onyears";
|
||||||
|
if (i == SCI_SUBJ)
|
||||||
|
return "scimap";
|
||||||
return "subjects";
|
return "subjects";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,6 +273,22 @@ static void catalog_rebuild(void) {
|
||||||
g_snprintf(page, sizeof(page), "lit4ex%d", i);
|
g_snprintf(page, sizeof(page), "lit4ex%d", i);
|
||||||
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||||
}
|
}
|
||||||
|
catalog_add_key("Chemie", "search_lesson", "chemmap", FALSE, 1, "chemie");
|
||||||
|
catalog_add_key("Biologie", "search_lesson", "biomap", FALSE, 1, "biologie");
|
||||||
|
for (i = 1; i <= SCI_N; i++) {
|
||||||
|
g_snprintf(key, sizeof(key), "chem_unit%d", i);
|
||||||
|
g_snprintf(page, sizeof(page), "chemunit%d", i);
|
||||||
|
catalog_add_key(key, "search_lesson", page, FALSE, 2, "chemie");
|
||||||
|
g_snprintf(page, sizeof(page), "chemex%d", i);
|
||||||
|
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||||
|
}
|
||||||
|
for (i = 1; i <= SCI_N; i++) {
|
||||||
|
g_snprintf(key, sizeof(key), "bio_unit%d", i);
|
||||||
|
g_snprintf(page, sizeof(page), "biounit%d", i);
|
||||||
|
catalog_add_key(key, "search_lesson", page, FALSE, 2, "biologie");
|
||||||
|
g_snprintf(page, sizeof(page), "bioex%d", i);
|
||||||
|
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||||
|
}
|
||||||
catalog_add_key("Mluvnice", "search_lesson", "mluvnice", FALSE, 1,
|
catalog_add_key("Mluvnice", "search_lesson", "mluvnice", FALSE, 1,
|
||||||
"gramatika grammar");
|
"gramatika grammar");
|
||||||
catalog_add_key("Maturitní četba", "search_book", "readinglist", FALSE, 1,
|
catalog_add_key("Maturitní četba", "search_book", "readinglist", FALSE, 1,
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ void refresh_stats_ui(void) {
|
||||||
progress_for_mluvnice(&all);
|
progress_for_mluvnice(&all);
|
||||||
progress_for_lit(&all);
|
progress_for_lit(&all);
|
||||||
}
|
}
|
||||||
|
else if (s == SCI_SUBJ)
|
||||||
|
progress_for_sci(&all);
|
||||||
else
|
else
|
||||||
progress_for_units(sub_unit_start[s], sub_unit_count[s], &all);
|
progress_for_units(sub_unit_start[s], sub_unit_count[s], &all);
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +107,7 @@ void refresh_stats_ui(void) {
|
||||||
ProgressSum sp = {0};
|
ProgressSum sp = {0};
|
||||||
gboolean has_content = (s == NET_SUBJ) || (s == HW_SUBJ)
|
gboolean has_content = (s == NET_SUBJ) || (s == HW_SUBJ)
|
||||||
|| (s == ON_SUBJ) || (s == CZ_SUBJ)
|
|| (s == ON_SUBJ) || (s == CZ_SUBJ)
|
||||||
|| sub_unit_count[s] > 0;
|
|| (s == SCI_SUBJ) || sub_unit_count[s] > 0;
|
||||||
|
|
||||||
if (!count || !bar)
|
if (!count || !bar)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -119,6 +121,8 @@ void refresh_stats_ui(void) {
|
||||||
progress_for_mluvnice(&sp);
|
progress_for_mluvnice(&sp);
|
||||||
progress_for_lit(&sp);
|
progress_for_lit(&sp);
|
||||||
}
|
}
|
||||||
|
else if (s == SCI_SUBJ)
|
||||||
|
progress_for_sci(&sp);
|
||||||
else
|
else
|
||||||
progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp);
|
progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp);
|
||||||
if (has_content) {
|
if (has_content) {
|
||||||
|
|
@ -388,7 +392,8 @@ GtkWidget *build_stats_page(void) {
|
||||||
GtkWidget *count;
|
GtkWidget *count;
|
||||||
GtkWidget *bar;
|
GtkWidget *bar;
|
||||||
gboolean has_units = (s == NET_SUBJ) || (s == HW_SUBJ)
|
gboolean has_units = (s == NET_SUBJ) || (s == HW_SUBJ)
|
||||||
|| (s == CZ_SUBJ) || sub_unit_count[s] > 0;
|
|| (s == CZ_SUBJ) || (s == ON_SUBJ)
|
||||||
|
|| (s == SCI_SUBJ) || sub_unit_count[s] > 0;
|
||||||
gboolean has_deutsch_units = sub_unit_count[s] > 0;
|
gboolean has_deutsch_units = sub_unit_count[s] > 0;
|
||||||
|
|
||||||
subject = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
subject = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
/* Index 0 (Deutsch), NET_SUBJ (networks), HW_SUBJ (hardware), CZ_SUBJ
|
/* Index 0 (Deutsch), NET_SUBJ (networks), HW_SUBJ (hardware), CZ_SUBJ
|
||||||
* (Czech) and ON_SUBJ (civics) are unlocked. */
|
* (Czech), ON_SUBJ (civics) and SCI_SUBJ (natural sciences) are unlocked. */
|
||||||
const char *sub_keys[NUM_SUBJECTS] = {
|
const char *sub_keys[NUM_SUBJECTS] = {
|
||||||
"Deutsch",
|
"Deutsch",
|
||||||
"Správa počítačových sítí",
|
"Správa počítačových sítí",
|
||||||
|
|
@ -154,7 +154,7 @@ void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,
|
||||||
|
|
||||||
static gboolean subject_is_open(int i) {
|
static gboolean subject_is_open(int i) {
|
||||||
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
||||||
|| i == ON_SUBJ;
|
|| i == ON_SUBJ || i == SCI_SUBJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkWidget *subject_icon(int i) {
|
static GtkWidget *subject_icon(int i) {
|
||||||
|
|
@ -177,6 +177,9 @@ static GtkWidget *subject_icon(int i) {
|
||||||
else if (i == ON_SUBJ)
|
else if (i == ON_SUBJ)
|
||||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
||||||
draw_civics_icon, NULL, NULL);
|
draw_civics_icon, NULL, NULL);
|
||||||
|
else if (i == SCI_SUBJ)
|
||||||
|
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
||||||
|
draw_science_icon, NULL, NULL);
|
||||||
else
|
else
|
||||||
return icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 22);
|
return icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 22);
|
||||||
return area;
|
return area;
|
||||||
|
|
@ -193,6 +196,8 @@ static const char *subject_target(int i) {
|
||||||
return "czechmap";
|
return "czechmap";
|
||||||
if (i == ON_SUBJ)
|
if (i == ON_SUBJ)
|
||||||
return "onyears";
|
return "onyears";
|
||||||
|
if (i == SCI_SUBJ)
|
||||||
|
return "scimap";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,5 +432,6 @@ void apply_theme(void) {
|
||||||
on4_rail_theme_reset();
|
on4_rail_theme_reset();
|
||||||
czech_rail_theme_reset();
|
czech_rail_theme_reset();
|
||||||
lit_rail_theme_reset();
|
lit_rail_theme_reset();
|
||||||
|
sci_rail_theme_reset();
|
||||||
book_rail_theme_reset();
|
book_rail_theme_reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ char *app_progress_lit;
|
||||||
char *app_progress_lit2;
|
char *app_progress_lit2;
|
||||||
char *app_progress_lit3;
|
char *app_progress_lit3;
|
||||||
char *app_progress_lit4;
|
char *app_progress_lit4;
|
||||||
|
char *app_progress_chem;
|
||||||
|
char *app_progress_bio;
|
||||||
|
|
||||||
static char *dup_dirname(const char *path) {
|
static char *dup_dirname(const char *path) {
|
||||||
char *tmp = g_strdup(path);
|
char *tmp = g_strdup(path);
|
||||||
|
|
@ -176,6 +178,8 @@ static void set_progress_paths(const char *write_root) {
|
||||||
g_free(app_progress_lit2);
|
g_free(app_progress_lit2);
|
||||||
g_free(app_progress_lit3);
|
g_free(app_progress_lit3);
|
||||||
g_free(app_progress_lit4);
|
g_free(app_progress_lit4);
|
||||||
|
g_free(app_progress_chem);
|
||||||
|
g_free(app_progress_bio);
|
||||||
|
|
||||||
app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL);
|
app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL);
|
||||||
app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL);
|
app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL);
|
||||||
|
|
@ -194,6 +198,8 @@ static void set_progress_paths(const char *write_root) {
|
||||||
app_progress_lit2 = g_build_filename(app_progress_dir, "lit2.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_lit3 = g_build_filename(app_progress_dir, "lit3.conf", NULL);
|
||||||
app_progress_lit4 = g_build_filename(app_progress_dir, "lit4.conf", NULL);
|
app_progress_lit4 = g_build_filename(app_progress_dir, "lit4.conf", NULL);
|
||||||
|
app_progress_chem = g_build_filename(app_progress_dir, "chem.conf", NULL);
|
||||||
|
app_progress_bio = g_build_filename(app_progress_dir, "bio.conf", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resolve read-only asset root, chdir there, and point progress at a writable
|
/* Resolve read-only asset root, chdir there, and point progress at a writable
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue