mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Add physics lessons across four secondary-school years.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
bd7ab09b1d
commit
524269edd7
32 changed files with 4152 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
|
||||
středních škol), mluvnice (20 cvičení) a maturitní četba
|
||||
(82 knih: zápisky, kvíz, sestavení děje)
|
||||
- **Fyzika** — 4 ročníky, 32 lekcí podle osnov středních škol
|
||||
(mechanika, teplo a vlny, elektřina a magnetismus, optika až astrofyzika)
|
||||
- **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í);
|
||||
|
|
@ -80,7 +82,7 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
|
|||
### Použití
|
||||
|
||||
1. **Pokračuj** otevře mapu předmětů.
|
||||
2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka, váhy, baňka) vede na učební cestu.
|
||||
2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka, váhy, atom, baňka) vede na učební cestu.
|
||||
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.
|
||||
|
||||
|
|
@ -268,6 +270,8 @@ Intel Mac, another architecture, or hacking on the code →
|
|||
- **Czech language** — literature (4 years, 32 lessons from the secondary-school
|
||||
syllabus), grammar (20 exercises) and required reading
|
||||
(82 books: notes, quiz, plot ordering)
|
||||
- **Physics** — 4 years, 32 lessons from the secondary-school syllabus
|
||||
(mechanics, heat and waves, electricity and magnetism, optics through astrophysics)
|
||||
- **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);
|
||||
|
|
@ -280,7 +284,7 @@ Intel Mac, another architecture, or hacking on the code →
|
|||
### Usage
|
||||
|
||||
1. **Continue** opens the subject map.
|
||||
2. An open subject (flag, Wi‑Fi, chip, Czech flag, scales, flask) opens its path.
|
||||
2. An open subject (flag, Wi‑Fi, chip, Czech flag, scales, atom, flask) opens its path.
|
||||
3. Exercise / lesson nodes open content; locked nodes do nothing.
|
||||
4. **Search** (magnifier), **Statistics** (chart) and **Settings** (gear) sit in the top-right.
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,26 @@ class AppViewModel(app: Application) : AndroidViewModel(app) {
|
|||
refresh()
|
||||
}
|
||||
|
||||
fun markFyz(id: Int) {
|
||||
progress.markFyz(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markFyz2(id: Int) {
|
||||
progress.markFyz2(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markFyz3(id: Int) {
|
||||
progress.markFyz3(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markFyz4(id: Int) {
|
||||
progress.markFyz4(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markMluv(n: Int) {
|
||||
progress.markMluv(n)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import org.maturita.maturita.ui.HomeScreen
|
|||
import org.maturita.maturita.ui.HwQuizScreen
|
||||
import org.maturita.maturita.ui.HwYearsScreen
|
||||
import org.maturita.maturita.ui.LessonListScreen
|
||||
import org.maturita.maturita.ui.FyzQuizScreen
|
||||
import org.maturita.maturita.ui.FyzYearsScreen
|
||||
import org.maturita.maturita.ui.LitYearsScreen
|
||||
import org.maturita.maturita.ui.LessonRow
|
||||
import org.maturita.maturita.ui.LitQuizScreen
|
||||
|
|
@ -348,6 +350,63 @@ private fun MaturitaAppBody(vm: AppViewModel) {
|
|||
}
|
||||
}
|
||||
is Route.Lit4Ex -> LitQuizScreen(vm, 4, r.id)
|
||||
Route.FyzYears -> FyzYearsScreen(vm)
|
||||
Route.FyzMap -> LessonListScreen(
|
||||
vm, vm.tr("fyz_year1"), vm.tr("fyz_sub"),
|
||||
vm.content.fyz.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.fyzDone(id), Route.FyzLesson(id))
|
||||
},
|
||||
)
|
||||
is Route.FyzLesson -> {
|
||||
val l = vm.content.fyzLesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.FyzEx(r.id))
|
||||
}
|
||||
}
|
||||
is Route.FyzEx -> FyzQuizScreen(vm, 1, r.id)
|
||||
Route.Fyz2Map -> LessonListScreen(
|
||||
vm, vm.tr("fyz_year2"), vm.tr("fyz2_sub"),
|
||||
vm.content.fyz2.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.fyz2Done(id), Route.Fyz2Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Fyz2Lesson -> {
|
||||
val l = vm.content.fyz2Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Fyz2Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Fyz2Ex -> FyzQuizScreen(vm, 2, r.id)
|
||||
Route.Fyz3Map -> LessonListScreen(
|
||||
vm, vm.tr("fyz_year3"), vm.tr("fyz3_sub"),
|
||||
vm.content.fyz3.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.fyz3Done(id), Route.Fyz3Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Fyz3Lesson -> {
|
||||
val l = vm.content.fyz3Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Fyz3Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Fyz3Ex -> FyzQuizScreen(vm, 3, r.id)
|
||||
Route.Fyz4Map -> LessonListScreen(
|
||||
vm, vm.tr("fyz_year4"), vm.tr("fyz4_sub"),
|
||||
vm.content.fyz4.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.fyz4Done(id), Route.Fyz4Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Fyz4Lesson -> {
|
||||
val l = vm.content.fyz4Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Fyz4Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Fyz4Ex -> FyzQuizScreen(vm, 4, r.id)
|
||||
Route.SciMap -> SciMapScreen(vm)
|
||||
Route.ChemMap -> LessonListScreen(
|
||||
vm, vm.tr("Chemie"), vm.tr("chem_sub"),
|
||||
|
|
|
|||
|
|
@ -50,6 +50,19 @@ sealed class Route(val page: String) {
|
|||
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 FyzYears : Route("fyzyears")
|
||||
data object FyzMap : Route("fyzmap")
|
||||
data class FyzLesson(val id: Int) : Route("fyzunit$id")
|
||||
data class FyzEx(val id: Int) : Route("fyzex$id")
|
||||
data object Fyz2Map : Route("fyz2map")
|
||||
data class Fyz2Lesson(val id: Int) : Route("fyz2unit$id")
|
||||
data class Fyz2Ex(val id: Int) : Route("fyz2ex$id")
|
||||
data object Fyz3Map : Route("fyz3map")
|
||||
data class Fyz3Lesson(val id: Int) : Route("fyz3unit$id")
|
||||
data class Fyz3Ex(val id: Int) : Route("fyz3ex$id")
|
||||
data object Fyz4Map : Route("fyz4map")
|
||||
data class Fyz4Lesson(val id: Int) : Route("fyz4unit$id")
|
||||
data class Fyz4Ex(val id: Int) : Route("fyz4ex$id")
|
||||
data object CzechMap : Route("czechmap")
|
||||
data object Mluvnice : Route("mluvnice")
|
||||
data class MluvEx(val n: Int) : Route("mluve$n")
|
||||
|
|
@ -68,7 +81,9 @@ sealed class Route(val page: String) {
|
|||
this is NetLesson || this is HwLesson || this is OnLesson || this is On2Lesson || this is On3Lesson || this is On4Lesson ||
|
||||
this is LitLesson || this is LitEx || this is Lit2Lesson || this is Lit2Ex ||
|
||||
this is Lit3Lesson || this is Lit3Ex || this is Lit4Lesson || this is Lit4Ex ||
|
||||
this is ChemLesson || this is ChemEx || this is BioLesson || this is BioEx
|
||||
this is ChemLesson || this is ChemEx || this is BioLesson || this is BioEx ||
|
||||
this is FyzLesson || this is FyzEx || this is Fyz2Lesson || this is Fyz2Ex ||
|
||||
this is Fyz3Lesson || this is Fyz3Ex || this is Fyz4Lesson || this is Fyz4Ex
|
||||
|
||||
/** Full stack from the practice root to this screen, so back always goes up one level. */
|
||||
fun stack(): List<Route> = when (this) {
|
||||
|
|
@ -120,6 +135,19 @@ sealed class Route(val page: String) {
|
|||
BioMap -> listOf(Subjects, SciMap, BioMap)
|
||||
is BioLesson -> listOf(Subjects, SciMap, BioMap, this)
|
||||
is BioEx -> listOf(Subjects, SciMap, BioMap, BioLesson(id), this)
|
||||
FyzYears -> listOf(Subjects, FyzYears)
|
||||
FyzMap -> listOf(Subjects, FyzYears, FyzMap)
|
||||
is FyzLesson -> listOf(Subjects, FyzYears, FyzMap, this)
|
||||
is FyzEx -> listOf(Subjects, FyzYears, FyzMap, FyzLesson(id), this)
|
||||
Fyz2Map -> listOf(Subjects, FyzYears, Fyz2Map)
|
||||
is Fyz2Lesson -> listOf(Subjects, FyzYears, Fyz2Map, this)
|
||||
is Fyz2Ex -> listOf(Subjects, FyzYears, Fyz2Map, Fyz2Lesson(id), this)
|
||||
Fyz3Map -> listOf(Subjects, FyzYears, Fyz3Map)
|
||||
is Fyz3Lesson -> listOf(Subjects, FyzYears, Fyz3Map, this)
|
||||
is Fyz3Ex -> listOf(Subjects, FyzYears, Fyz3Map, Fyz3Lesson(id), this)
|
||||
Fyz4Map -> listOf(Subjects, FyzYears, Fyz4Map)
|
||||
is Fyz4Lesson -> listOf(Subjects, FyzYears, Fyz4Map, this)
|
||||
is Fyz4Ex -> listOf(Subjects, FyzYears, Fyz4Map, Fyz4Lesson(id), this)
|
||||
CzechMap -> listOf(Subjects, CzechMap)
|
||||
Mluvnice -> listOf(Subjects, CzechMap, Mluvnice)
|
||||
is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this)
|
||||
|
|
@ -153,6 +181,11 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
"scimap" -> Route.SciMap
|
||||
"chemmap" -> Route.ChemMap
|
||||
"biomap" -> Route.BioMap
|
||||
"fyzyears" -> Route.FyzYears
|
||||
"fyzmap" -> Route.FyzMap
|
||||
"fyz2map" -> Route.Fyz2Map
|
||||
"fyz3map" -> Route.Fyz3Map
|
||||
"fyz4map" -> Route.Fyz4Map
|
||||
"czechmap" -> Route.CzechMap
|
||||
"mluvnice" -> Route.Mluvnice
|
||||
"readinglist" -> Route.ReadingList
|
||||
|
|
@ -196,6 +229,30 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
Regex("""bioex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.BioEx(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz4unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz4Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz4ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz4Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz3unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz3Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz3ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz3Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz2unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz2Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyz2ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Fyz2Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyzunit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.FyzLesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""fyzex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.FyzEx(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""lit4unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Lit4Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ class Content(root: JSONObject) {
|
|||
val lit4 = raw.arr("lit4")
|
||||
val chem = raw.arr("chem")
|
||||
val bio = raw.arr("bio")
|
||||
val fyz = raw.arr("fyz")
|
||||
val fyz2 = raw.arr("fyz2")
|
||||
val fyz3 = raw.arr("fyz3")
|
||||
val fyz4 = raw.arr("fyz4")
|
||||
val mluvnice = raw.arr("mluvnice")
|
||||
val books = raw.arr("books")
|
||||
val changelog = raw.arr("changelog")
|
||||
|
|
@ -56,6 +60,10 @@ class Content(root: JSONObject) {
|
|||
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 fyzLesson(id: Int) = fyz.firstOrNull { it.int("id") == id }
|
||||
fun fyz2Lesson(id: Int) = fyz2.firstOrNull { it.int("id") == id }
|
||||
fun fyz3Lesson(id: Int) = fyz3.firstOrNull { it.int("id") == id }
|
||||
fun fyz4Lesson(id: Int) = fyz4.firstOrNull { it.int("id") == id }
|
||||
fun mluv(n: Int) = mluvnice.firstOrNull { it.int("id") == n }
|
||||
fun book(id: String) = books.firstOrNull { it.str("id") == id }
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@ class ProgressStore(context: Context) {
|
|||
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 fyzDone(id: Int) = prefs.getBoolean("fyz.$id", false)
|
||||
fun markFyz(id: Int) { prefs.edit().putBoolean("fyz.$id", true).apply() }
|
||||
fun fyz2Done(id: Int) = prefs.getBoolean("fyz2.$id", false)
|
||||
fun markFyz2(id: Int) { prefs.edit().putBoolean("fyz2.$id", true).apply() }
|
||||
fun fyz3Done(id: Int) = prefs.getBoolean("fyz3.$id", false)
|
||||
fun markFyz3(id: Int) { prefs.edit().putBoolean("fyz3.$id", true).apply() }
|
||||
fun fyz4Done(id: Int) = prefs.getBoolean("fyz4.$id", false)
|
||||
fun markFyz4(id: Int) { prefs.edit().putBoolean("fyz4.$id", true).apply() }
|
||||
|
||||
fun mluvDone(n: Int) = prefs.getBoolean("mluv.$n", false)
|
||||
fun markMluv(n: Int) { prefs.edit().putBoolean("mluv.$n", true).apply() }
|
||||
|
|
@ -176,6 +184,38 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
|
|||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.fyz.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.fyzDone(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.fyz2.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.fyz2Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.fyz3.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.fyz3Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.fyz4.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.fyz4Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
sum.totalEx += content.mluvnice.size
|
||||
sum.openUnits += 1
|
||||
val md = content.mluvnice.count { p.mluvDone(it.int("id")) }
|
||||
|
|
|
|||
|
|
@ -863,6 +863,30 @@ fun SciQuizScreen(vm: AppViewModel, area: String, id: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FyzQuizScreen(vm: AppViewModel, year: Int, id: Int) {
|
||||
val lesson = when (year) {
|
||||
2 -> vm.content.fyz2Lesson(id)
|
||||
3 -> vm.content.fyz3Lesson(id)
|
||||
4 -> vm.content.fyz4Lesson(id)
|
||||
else -> vm.content.fyzLesson(id)
|
||||
} ?: return
|
||||
val spec = J(org.json.JSONObject().apply {
|
||||
put("type", "choice")
|
||||
put("title", vm.tr(lesson.str("exTitleKey")))
|
||||
put("sub", lesson.str("quizHeadKey"))
|
||||
put("questions", lesson.o.optJSONArray("quiz"))
|
||||
})
|
||||
DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey"))) {
|
||||
when (year) {
|
||||
2 -> vm.markFyz2(id)
|
||||
3 -> vm.markFyz3(id)
|
||||
4 -> vm.markFyz4(id)
|
||||
else -> vm.markFyz(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LitQuizScreen(vm: AppViewModel, year: Int, id: Int) {
|
||||
val lesson = when (year) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.MenuBook
|
||||
import androidx.compose.material.icons.filled.Bolt
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.FormatListNumbered
|
||||
|
|
@ -222,6 +223,7 @@ private fun SubjectIcon(icon: String, open: Boolean) {
|
|||
"people" -> Icon(Icons.Filled.Groups, null, tint = tint, modifier = Modifier.size(26.dp))
|
||||
"cz" -> CzechFlag(28.dp)
|
||||
"flask" -> Icon(Icons.Filled.Science, null, tint = tint, modifier = Modifier.size(26.dp))
|
||||
"bolt" -> Icon(Icons.Filled.Bolt, null, tint = tint, modifier = Modifier.size(26.dp))
|
||||
else -> Icon(Icons.Filled.Lock, null, tint = tint)
|
||||
}
|
||||
}
|
||||
|
|
@ -314,6 +316,13 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
|
|||
sum.doneEx = vm.content.chem.count { vm.progress.chemDone(it.int("id")) } +
|
||||
vm.content.bio.count { vm.progress.bioDone(it.int("id")) }
|
||||
}
|
||||
"fyzyears", "fyzmap", "fyz2map", "fyz3map", "fyz4map" -> {
|
||||
sum.totalEx = vm.content.fyz.size + vm.content.fyz2.size + vm.content.fyz3.size + vm.content.fyz4.size
|
||||
sum.doneEx = vm.content.fyz.count { vm.progress.fyzDone(it.int("id")) } +
|
||||
vm.content.fyz2.count { vm.progress.fyz2Done(it.int("id")) } +
|
||||
vm.content.fyz3.count { vm.progress.fyz3Done(it.int("id")) } +
|
||||
vm.content.fyz4.count { vm.progress.fyz4Done(it.int("id")) }
|
||||
}
|
||||
"czechmap" -> {
|
||||
val litDone = vm.content.lit.count { vm.progress.litDone(it.int("id")) } +
|
||||
vm.content.lit2.count { vm.progress.lit2Done(it.int("id")) } +
|
||||
|
|
@ -547,6 +556,27 @@ 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_exercise"), "lit4ex${l.int("id")}")
|
||||
}
|
||||
add(vm.tr("Fyzika"), vm.tr("search_lesson"), "fyzyears", extra = "fyzika")
|
||||
add(vm.tr("fyz_year1"), vm.tr("search_lesson"), "fyzmap", extra = "rocnik")
|
||||
add(vm.tr("fyz_year2"), vm.tr("search_lesson"), "fyz2map", extra = "rocnik")
|
||||
add(vm.tr("fyz_year3"), vm.tr("search_lesson"), "fyz3map", extra = "rocnik")
|
||||
add(vm.tr("fyz_year4"), vm.tr("search_lesson"), "fyz4map", extra = "rocnik")
|
||||
vm.content.fyz.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyzunit${l.int("id")}", extra = "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyzex${l.int("id")}")
|
||||
}
|
||||
vm.content.fyz2.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz2unit${l.int("id")}", extra = "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz2ex${l.int("id")}")
|
||||
}
|
||||
vm.content.fyz3.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz3unit${l.int("id")}", extra = "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz3ex${l.int("id")}")
|
||||
}
|
||||
vm.content.fyz4.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz4unit${l.int("id")}", extra = "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz4ex${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 ->
|
||||
|
|
@ -683,6 +713,20 @@ fun LitYearsScreen(vm: AppViewModel) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FyzYearsScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Fyzika"), vm.tr("fyz_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("fyz_year1"), subtitle = vm.tr("fyz_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.FyzMap) }
|
||||
NavRow(title = vm.tr("fyz_year2"), subtitle = vm.tr("fyz2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Fyz2Map) }
|
||||
NavRow(title = vm.tr("fyz_year3"), subtitle = vm.tr("fyz3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Fyz3Map) }
|
||||
NavRow(title = vm.tr("fyz_year4"), subtitle = vm.tr("fyz4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Fyz4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SciMapScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Základy Přírodopisných věd"), vm.tr("sci_sub")) { inner ->
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
# cs: bullet
|
||||
# en: bullet
|
||||
|
||||
--- 2026-10-06
|
||||
cs: Fyzika: čtyři ročníky, 32 lekcí podle osnov středních škol
|
||||
cs: Od mechaniky přes teplo a elektřinu až po optiku, jádro a astrofyziku
|
||||
en: Physics: four years, 32 lessons from the secondary-school syllabus
|
||||
en: From mechanics through heat and electricity to optics, the nucleus and astrophysics
|
||||
|
||||
--- 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
|
||||
|
|
|
|||
|
|
@ -178,6 +178,26 @@ final class AppModel: ObservableObject {
|
|||
refresh()
|
||||
}
|
||||
|
||||
func markFyz(_ id: Int) {
|
||||
progress.markFyz(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markFyz2(_ id: Int) {
|
||||
progress.markFyz2(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markFyz3(_ id: Int) {
|
||||
progress.markFyz3(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markFyz4(_ id: Int) {
|
||||
progress.markFyz4(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
func markMluv(_ n: Int) {
|
||||
progress.markMluv(n)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ final class Content {
|
|||
let lit4: [J]
|
||||
let chem: [J]
|
||||
let bio: [J]
|
||||
let fyz: [J]
|
||||
let fyz2: [J]
|
||||
let fyz3: [J]
|
||||
let fyz4: [J]
|
||||
let mluvnice: [J]
|
||||
let books: [J]
|
||||
let changelog: [J]
|
||||
|
|
@ -82,6 +86,10 @@ final class Content {
|
|||
lit4 = raw.arr("lit4")
|
||||
chem = raw.arr("chem")
|
||||
bio = raw.arr("bio")
|
||||
fyz = raw.arr("fyz")
|
||||
fyz2 = raw.arr("fyz2")
|
||||
fyz3 = raw.arr("fyz3")
|
||||
fyz4 = raw.arr("fyz4")
|
||||
mluvnice = raw.arr("mluvnice")
|
||||
books = raw.arr("books")
|
||||
changelog = raw.arr("changelog")
|
||||
|
|
@ -100,6 +108,10 @@ final class Content {
|
|||
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 fyzLesson(_ id: Int) -> J? { fyz.first { $0.int("id") == id } }
|
||||
func fyz2Lesson(_ id: Int) -> J? { fyz2.first { $0.int("id") == id } }
|
||||
func fyz3Lesson(_ id: Int) -> J? { fyz3.first { $0.int("id") == id } }
|
||||
func fyz4Lesson(_ id: Int) -> J? { fyz4.first { $0.int("id") == id } }
|
||||
func mluv(_ n: Int) -> J? { mluvnice.first { $0.int("id") == n } }
|
||||
func book(_ id: String) -> J? { books.first { $0.str("id") == id } }
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,14 @@ final class ProgressStore {
|
|||
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 fyzDone(_ id: Int) -> Bool { defaults.bool(forKey: "fyz.\(id)") }
|
||||
func markFyz(_ id: Int) { defaults.set(true, forKey: "fyz.\(id)") }
|
||||
func fyz2Done(_ id: Int) -> Bool { defaults.bool(forKey: "fyz2.\(id)") }
|
||||
func markFyz2(_ id: Int) { defaults.set(true, forKey: "fyz2.\(id)") }
|
||||
func fyz3Done(_ id: Int) -> Bool { defaults.bool(forKey: "fyz3.\(id)") }
|
||||
func markFyz3(_ id: Int) { defaults.set(true, forKey: "fyz3.\(id)") }
|
||||
func fyz4Done(_ id: Int) -> Bool { defaults.bool(forKey: "fyz4.\(id)") }
|
||||
func markFyz4(_ id: Int) { defaults.set(true, forKey: "fyz4.\(id)") }
|
||||
|
||||
func mluvDone(_ n: Int) -> Bool { defaults.bool(forKey: "mluv.\(n)") }
|
||||
func markMluv(_ n: Int) { defaults.set(true, forKey: "mluv.\(n)") }
|
||||
|
|
@ -183,6 +191,38 @@ func summarize(_ content: Content, _ p: ProgressStore) -> ProgressSum {
|
|||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.fyz {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.fyzDone(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.fyz2 {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.fyz2Done(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.fyz3 {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.fyz3Done(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
for l in content.fyz4 {
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if p.fyz4Done(l.int("id")) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
sum.totalEx += content.mluvnice.count
|
||||
sum.openUnits += 1
|
||||
let md = content.mluvnice.filter { p.mluvDone($0.int("id")) }.count
|
||||
|
|
|
|||
|
|
@ -56,6 +56,19 @@ enum Route: Hashable {
|
|||
case bioMap
|
||||
case bioLesson(Int)
|
||||
case bioEx(Int)
|
||||
case fyzYears
|
||||
case fyzMap
|
||||
case fyzLesson(Int)
|
||||
case fyzEx(Int)
|
||||
case fyz2Map
|
||||
case fyz2Lesson(Int)
|
||||
case fyz2Ex(Int)
|
||||
case fyz3Map
|
||||
case fyz3Lesson(Int)
|
||||
case fyz3Ex(Int)
|
||||
case fyz4Map
|
||||
case fyz4Lesson(Int)
|
||||
case fyz4Ex(Int)
|
||||
case czechMap
|
||||
case mluvnice
|
||||
case mluvEx(Int)
|
||||
|
|
@ -114,6 +127,19 @@ enum Route: Hashable {
|
|||
case .bioMap: return "biomap"
|
||||
case .bioLesson(let id): return "biounit\(id)"
|
||||
case .bioEx(let id): return "bioex\(id)"
|
||||
case .fyzYears: return "fyzyears"
|
||||
case .fyzMap: return "fyzmap"
|
||||
case .fyzLesson(let id): return "fyzunit\(id)"
|
||||
case .fyzEx(let id): return "fyzex\(id)"
|
||||
case .fyz2Map: return "fyz2map"
|
||||
case .fyz2Lesson(let id): return "fyz2unit\(id)"
|
||||
case .fyz2Ex(let id): return "fyz2ex\(id)"
|
||||
case .fyz3Map: return "fyz3map"
|
||||
case .fyz3Lesson(let id): return "fyz3unit\(id)"
|
||||
case .fyz3Ex(let id): return "fyz3ex\(id)"
|
||||
case .fyz4Map: return "fyz4map"
|
||||
case .fyz4Lesson(let id): return "fyz4unit\(id)"
|
||||
case .fyz4Ex(let id): return "fyz4ex\(id)"
|
||||
case .czechMap: return "czechmap"
|
||||
case .mluvnice: return "mluvnice"
|
||||
case .mluvEx(let n): return "mluve\(n)"
|
||||
|
|
@ -228,6 +254,32 @@ enum Route: Hashable {
|
|||
return [.sciMap, .bioMap, .bioLesson(id)]
|
||||
case .bioEx(let id):
|
||||
return [.sciMap, .bioMap, .bioLesson(id), .bioEx(id)]
|
||||
case .fyzYears:
|
||||
return [.fyzYears]
|
||||
case .fyzMap:
|
||||
return [.fyzYears, .fyzMap]
|
||||
case .fyzLesson(let id):
|
||||
return [.fyzYears, .fyzMap, .fyzLesson(id)]
|
||||
case .fyzEx(let id):
|
||||
return [.fyzYears, .fyzMap, .fyzLesson(id), .fyzEx(id)]
|
||||
case .fyz2Map:
|
||||
return [.fyzYears, .fyz2Map]
|
||||
case .fyz2Lesson(let id):
|
||||
return [.fyzYears, .fyz2Map, .fyz2Lesson(id)]
|
||||
case .fyz2Ex(let id):
|
||||
return [.fyzYears, .fyz2Map, .fyz2Lesson(id), .fyz2Ex(id)]
|
||||
case .fyz3Map:
|
||||
return [.fyzYears, .fyz3Map]
|
||||
case .fyz3Lesson(let id):
|
||||
return [.fyzYears, .fyz3Map, .fyz3Lesson(id)]
|
||||
case .fyz3Ex(let id):
|
||||
return [.fyzYears, .fyz3Map, .fyz3Lesson(id), .fyz3Ex(id)]
|
||||
case .fyz4Map:
|
||||
return [.fyzYears, .fyz4Map]
|
||||
case .fyz4Lesson(let id):
|
||||
return [.fyzYears, .fyz4Map, .fyz4Lesson(id)]
|
||||
case .fyz4Ex(let id):
|
||||
return [.fyzYears, .fyz4Map, .fyz4Lesson(id), .fyz4Ex(id)]
|
||||
case .czechMap:
|
||||
return [.czechMap]
|
||||
case .mluvnice:
|
||||
|
|
@ -269,6 +321,11 @@ func routeFromPage(_ page: String) -> Route? {
|
|||
case "scimap": return .sciMap
|
||||
case "chemmap": return .chemMap
|
||||
case "biomap": return .bioMap
|
||||
case "fyzyears": return .fyzYears
|
||||
case "fyzmap": return .fyzMap
|
||||
case "fyz2map": return .fyz2Map
|
||||
case "fyz3map": return .fyz3Map
|
||||
case "fyz4map": return .fyz4Map
|
||||
case "czechmap": return .czechMap
|
||||
case "mluvnice": return .mluvnice
|
||||
case "readinglist": return .readingList
|
||||
|
|
@ -324,6 +381,30 @@ func routeFromPage(_ page: String) -> Route? {
|
|||
if let m = page.wholeMatch(of: /bioex(\d+)/), let n = Int(m.1) {
|
||||
return .bioEx(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz4unit(\d+)/), let n = Int(m.1) {
|
||||
return .fyz4Lesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz4ex(\d+)/), let n = Int(m.1) {
|
||||
return .fyz4Ex(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz3unit(\d+)/), let n = Int(m.1) {
|
||||
return .fyz3Lesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz3ex(\d+)/), let n = Int(m.1) {
|
||||
return .fyz3Ex(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz2unit(\d+)/), let n = Int(m.1) {
|
||||
return .fyz2Lesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyz2ex(\d+)/), let n = Int(m.1) {
|
||||
return .fyz2Ex(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyzunit(\d+)/), let n = Int(m.1) {
|
||||
return .fyzLesson(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /fyzex(\d+)/), let n = Int(m.1) {
|
||||
return .fyzEx(n)
|
||||
}
|
||||
if let m = page.wholeMatch(of: /lit4unit(\d+)/), let n = Int(m.1) {
|
||||
return .lit4Lesson(n)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -608,6 +608,7 @@ func subjectSymbol(_ icon: String) -> String {
|
|||
case "cz": return "text.book.closed.fill"
|
||||
case "people": return "person.2.fill"
|
||||
case "flask": return "flask.fill"
|
||||
case "bolt": return "bolt.fill"
|
||||
default: return "lock.fill"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -646,6 +646,39 @@ struct SciQuizScreen: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct FyzQuizScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
let year: Int
|
||||
let id: Int
|
||||
|
||||
var body: some View {
|
||||
let lesson: J? = {
|
||||
switch year {
|
||||
case 2: return vm.content.fyz2Lesson(id)
|
||||
case 3: return vm.content.fyz3Lesson(id)
|
||||
case 4: return vm.content.fyz4Lesson(id)
|
||||
default: return vm.content.fyzLesson(id)
|
||||
}
|
||||
}()
|
||||
if let lesson {
|
||||
let spec = J([
|
||||
"type": "choice",
|
||||
"title": vm.tr(lesson.str("exTitleKey")),
|
||||
"sub": lesson.str("quizHeadKey"),
|
||||
"questions": lesson.rawArray("quiz"),
|
||||
])
|
||||
DispatchExercise(vm: vm, spec: spec, titleFallback: vm.tr(lesson.str("exTitleKey"))) {
|
||||
switch year {
|
||||
case 2: vm.markFyz2(id)
|
||||
case 3: vm.markFyz3(id)
|
||||
case 4: vm.markFyz4(id)
|
||||
default: vm.markFyz(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LitYearQuizScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
let year: Int
|
||||
|
|
|
|||
|
|
@ -699,6 +699,12 @@ private func subjectSum(_ vm: AppModel, _ s: J) -> ProgressSum {
|
|||
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 "fyzyears", "fyzmap", "fyz2map", "fyz3map", "fyz4map":
|
||||
sum.totalEx = vm.content.fyz.count + vm.content.fyz2.count + vm.content.fyz3.count + vm.content.fyz4.count
|
||||
sum.doneEx = vm.content.fyz.filter { vm.progress.fyzDone($0.int("id")) }.count
|
||||
+ vm.content.fyz2.filter { vm.progress.fyz2Done($0.int("id")) }.count
|
||||
+ vm.content.fyz3.filter { vm.progress.fyz3Done($0.int("id")) }.count
|
||||
+ vm.content.fyz4.filter { vm.progress.fyz4Done($0.int("id")) }.count
|
||||
case "czechmap":
|
||||
let litCount = vm.content.lit.count + vm.content.lit2.count + vm.content.lit3.count + vm.content.lit4.count
|
||||
let litDone = vm.content.lit.filter { vm.progress.litDone($0.int("id")) }.count
|
||||
|
|
@ -929,6 +935,27 @@ private func buildSearch(_ vm: AppModel) -> [Hit] {
|
|||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "lit4unit\(l.int("id"))", extra: "literatura")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "lit4ex\(l.int("id"))")
|
||||
}
|
||||
add(vm.tr("Fyzika"), vm.tr("search_lesson"), "fyzyears", extra: "fyzika")
|
||||
add(vm.tr("fyz_year1"), vm.tr("search_lesson"), "fyzmap", extra: "rocnik")
|
||||
add(vm.tr("fyz_year2"), vm.tr("search_lesson"), "fyz2map", extra: "rocnik")
|
||||
add(vm.tr("fyz_year3"), vm.tr("search_lesson"), "fyz3map", extra: "rocnik")
|
||||
add(vm.tr("fyz_year4"), vm.tr("search_lesson"), "fyz4map", extra: "rocnik")
|
||||
for l in vm.content.fyz {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyzunit\(l.int("id"))", extra: "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyzex\(l.int("id"))")
|
||||
}
|
||||
for l in vm.content.fyz2 {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz2unit\(l.int("id"))", extra: "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz2ex\(l.int("id"))")
|
||||
}
|
||||
for l in vm.content.fyz3 {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz3unit\(l.int("id"))", extra: "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz3ex\(l.int("id"))")
|
||||
}
|
||||
for l in vm.content.fyz4 {
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "fyz4unit\(l.int("id"))", extra: "fyzika")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "fyz4ex\(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 {
|
||||
|
|
@ -1485,6 +1512,47 @@ struct LitYearsScreen: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct FyzYearsScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
let years: [(String, String, Route)] = [
|
||||
("fyz_year1", "fyz_sub", .fyzMap),
|
||||
("fyz_year2", "fyz2_sub", .fyz2Map),
|
||||
("fyz_year3", "fyz3_sub", .fyz3Map),
|
||||
("fyz_year4", "fyz4_sub", .fyz4Map),
|
||||
]
|
||||
MacFillGrid(count: years.count, minWidth: 260, minHeight: 180) { i in
|
||||
NavigationLink(value: years[i].2) {
|
||||
MacLinkCard(title: vm.tr(years[i].0), subtitle: vm.tr(years[i].1), badge: "\(i + 1).")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.navigationTitle(vm.tr("Fyzika"))
|
||||
.navigationSubtitle(vm.tr("fyz_years_sub"))
|
||||
#else
|
||||
List {
|
||||
NavigationLink(value: Route.fyzMap) {
|
||||
ListRowLabel(title: vm.tr("fyz_year1"), subtitle: vm.tr("fyz_sub"))
|
||||
}
|
||||
NavigationLink(value: Route.fyz2Map) {
|
||||
ListRowLabel(title: vm.tr("fyz_year2"), subtitle: vm.tr("fyz2_sub"))
|
||||
}
|
||||
NavigationLink(value: Route.fyz3Map) {
|
||||
ListRowLabel(title: vm.tr("fyz_year3"), subtitle: vm.tr("fyz3_sub"))
|
||||
}
|
||||
NavigationLink(value: Route.fyz4Map) {
|
||||
ListRowLabel(title: vm.tr("fyz_year4"), subtitle: vm.tr("fyz4_sub"))
|
||||
}
|
||||
}
|
||||
.navigationTitle(vm.tr("Fyzika"))
|
||||
.navigationSubtitle(vm.tr("fyz_years_sub"))
|
||||
.appListStyle()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct SciMapScreen: View {
|
||||
@ObservedObject var vm: AppModel
|
||||
|
||||
|
|
@ -2253,6 +2321,92 @@ struct RouteDestination: View {
|
|||
}
|
||||
case .bioEx(let id):
|
||||
SciQuizScreen(vm: vm, area: "bio", id: id)
|
||||
case .fyzYears:
|
||||
FyzYearsScreen(vm: vm)
|
||||
case .fyzMap:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("fyz_year1"),
|
||||
subtitle: vm.tr("fyz_sub"),
|
||||
rows: vm.content.fyz.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "f\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.fyzDone(id),
|
||||
destination: .fyzLesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .fyzLesson(let id):
|
||||
if let l = vm.content.fyzLesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .fyzEx(id))
|
||||
}
|
||||
case .fyzEx(let id):
|
||||
FyzQuizScreen(vm: vm, year: 1, id: id)
|
||||
case .fyz2Map:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("fyz_year2"),
|
||||
subtitle: vm.tr("fyz2_sub"),
|
||||
rows: vm.content.fyz2.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "f2\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.fyz2Done(id),
|
||||
destination: .fyz2Lesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .fyz2Lesson(let id):
|
||||
if let l = vm.content.fyz2Lesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .fyz2Ex(id))
|
||||
}
|
||||
case .fyz2Ex(let id):
|
||||
FyzQuizScreen(vm: vm, year: 2, id: id)
|
||||
case .fyz3Map:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("fyz_year3"),
|
||||
subtitle: vm.tr("fyz3_sub"),
|
||||
rows: vm.content.fyz3.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "f3\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.fyz3Done(id),
|
||||
destination: .fyz3Lesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .fyz3Lesson(let id):
|
||||
if let l = vm.content.fyz3Lesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .fyz3Ex(id))
|
||||
}
|
||||
case .fyz3Ex(let id):
|
||||
FyzQuizScreen(vm: vm, year: 3, id: id)
|
||||
case .fyz4Map:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
title: vm.tr("fyz_year4"),
|
||||
subtitle: vm.tr("fyz4_sub"),
|
||||
rows: vm.content.fyz4.map { l in
|
||||
let id = l.int("id")
|
||||
return LessonRow(
|
||||
id: "f4\(id)",
|
||||
title: vm.tr(l.str("titleKey")),
|
||||
done: vm.progress.fyz4Done(id),
|
||||
destination: .fyz4Lesson(id)
|
||||
)
|
||||
}
|
||||
)
|
||||
case .fyz4Lesson(let id):
|
||||
if let l = vm.content.fyz4Lesson(id) {
|
||||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), subtitle: vm.tr(l.str("subKey")), slides: l.arr("slides"), next: .fyz4Ex(id))
|
||||
}
|
||||
case .fyz4Ex(let id):
|
||||
FyzQuizScreen(vm: vm, year: 4, id: id)
|
||||
case .mluvnice:
|
||||
LessonListScreen(
|
||||
vm: vm,
|
||||
|
|
|
|||
|
|
@ -1111,6 +1111,10 @@ def main() -> int:
|
|||
lit4_lessons = lit_pack("lit4")
|
||||
chem_lessons = lit_pack("chem")
|
||||
bio_lessons = lit_pack("bio")
|
||||
fyz_lessons = lit_pack("fyz")
|
||||
fyz2_lessons = lit_pack("fyz2")
|
||||
fyz3_lessons = lit_pack("fyz3")
|
||||
fyz4_lessons = lit_pack("fyz4")
|
||||
|
||||
on_lessons = []
|
||||
for i in range(1, 18):
|
||||
|
|
@ -1560,7 +1564,7 @@ def main() -> int:
|
|||
{"key": "Občanská nauka", "open": True, "target": "onyears", "icon": "people"},
|
||||
{"key": "English", "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": True, "target": "fyzyears", "icon": "bolt"},
|
||||
{"key": "Základy Přírodopisných věd", "open": True, "target": "scimap", "icon": "flask"},
|
||||
{"key": "Technická grafika", "open": False, "target": None, "icon": "lock"},
|
||||
{"key": "Prezentační grafika", "open": False, "target": None, "icon": "lock"},
|
||||
|
|
@ -1585,6 +1589,10 @@ def main() -> int:
|
|||
"lit4": lit4_lessons,
|
||||
"chem": chem_lessons,
|
||||
"bio": bio_lessons,
|
||||
"fyz": fyz_lessons,
|
||||
"fyz2": fyz2_lessons,
|
||||
"fyz3": fyz3_lessons,
|
||||
"fyz4": fyz4_lessons,
|
||||
"on2": on2_lessons,
|
||||
"on3": on3_lessons,
|
||||
"on4": on4_lessons,
|
||||
|
|
@ -1626,6 +1634,7 @@ def main() -> int:
|
|||
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" fyz lessons: {sum(1 for L in fyz_lessons + fyz2_lessons + fyz3_lessons + fyz4_lessons if L['slides'])}")
|
||||
print(f" on2 lessons: {sum(1 for L in on2_lessons if L['slides'])}")
|
||||
print(f" on3 lessons: {sum(1 for L in on3_lessons if L['slides'])}")
|
||||
print(f" on4 lessons: {sum(1 for L in on4_lessons if L['slides'])}")
|
||||
|
|
@ -1686,6 +1695,8 @@ def main() -> int:
|
|||
("lit", lit_lessons), ("lit2", lit2_lessons),
|
||||
("lit3", lit3_lessons), ("lit4", lit4_lessons),
|
||||
("chem", chem_lessons), ("bio", bio_lessons),
|
||||
("fyz", fyz_lessons), ("fyz2", fyz2_lessons),
|
||||
("fyz3", fyz3_lessons), ("fyz4", fyz4_lessons),
|
||||
):
|
||||
for L in block:
|
||||
if not L["slides"]:
|
||||
|
|
|
|||
615
src/fyz_year1.c
Normal file
615
src/fyz_year1.c
Normal file
|
|
@ -0,0 +1,615 @@
|
|||
#include "graduately.h"
|
||||
|
||||
/* Year 1: mechanics. Quantities, kinematics, dynamics, energy,
|
||||
* gravitation, rigid bodies, fluids. */
|
||||
|
||||
NetLesson fyz_lessons[FYZ_N] = {
|
||||
{ .n_slides = 3, .unit_page = "fyzunit1", .ex_page = "fyzex1" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit2", .ex_page = "fyzex2" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit3", .ex_page = "fyzex3" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit4", .ex_page = "fyzex4" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit5", .ex_page = "fyzex5" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit6", .ex_page = "fyzex6" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit7", .ex_page = "fyzex7" },
|
||||
{ .n_slides = 3, .unit_page = "fyzunit8", .ex_page = "fyzex8" },
|
||||
};
|
||||
|
||||
static GtkWidget *build_fyz_unit1_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Měření", "Veličina a jednotka",
|
||||
"Tip: základní jednotka hmotnosti je kilogram, ne gram.",
|
||||
{
|
||||
"Fyzikální veličina má číselnou hodnotu a jednotku.",
|
||||
"Soustava SI má sedm základních jednotek: m, kg, s, A, K, mol a cd.",
|
||||
"Odvozené jednotky vznikají ze základních, třeba newton nebo joule.",
|
||||
"Předpona kilo znamená tisíc, mili znamená tisícinu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Druhy", "Skalár a vektor",
|
||||
"Tip: rychlost jako vektor má velikost i směr.",
|
||||
{
|
||||
"Skalár má jen velikost. Patří sem hmotnost, čas nebo teplota.",
|
||||
"Vektor má velikost i směr. Patří sem síla, rychlost a zrychlení.",
|
||||
"Vektory se skládají podle rovnoběžníku.",
|
||||
"Opačný vektor má stejnou velikost a opačný směr.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Přesnost", "Chyba měření",
|
||||
"Tip: relativní chyba se často udává v procentech.",
|
||||
{
|
||||
"Každé měření má chybu. Opakování měření ji zmenšuje.",
|
||||
"Absolutní chyba je rozdíl naměřené a správné hodnoty.",
|
||||
"Relativní chyba je podíl absolutní chyby a správné hodnoty.",
|
||||
"Výsledek se zaokrouhluje podle přesnosti měřidla.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[0], "fyz_unit1", "fyz_unit1_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit1_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Která jednotka je základní jednotka SI pro hmotnost?",
|
||||
{"Gram", "Kilogram", "Newton", "Tuna"},
|
||||
4, 1},
|
||||
{"Co má vektor navíc proti skaláru?",
|
||||
{"Jen jednotku", "Směr", "Jen číselnou hodnotu", "Předponu kilo"},
|
||||
4, 1},
|
||||
{"Co znamená předpona mili?",
|
||||
{"Tisíc", "Milion", "Tisícinu", "Setinu"},
|
||||
4, 2},
|
||||
{"Co je relativní chyba?",
|
||||
{"Rozdíl naměřené a správné hodnoty",
|
||||
"Podíl absolutní chyby a správné hodnoty",
|
||||
"Součet všech měření",
|
||||
"Nejmenší dílek měřidla"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Gram je tisícina kilogramu. Newton je jednotka síly.",
|
||||
"Hmotnost je skalár. Rychlost a síla jsou vektory.",
|
||||
"Kilo je 1000, centi je 0,01, mili je 0,001.",
|
||||
"Absolutní chyba je rozdíl. Relativní je tento rozdíl dělený správnou hodnotou.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 0, "fyzunit1", "fyz_ex1_title", "fyz_quiz1_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit2_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Pohyb", "Dráha a rychlost",
|
||||
"Tip: při rovnoměrném pohybu je rychlost stálá.",
|
||||
{
|
||||
"Trajektorie je čára, po které se bod pohybuje. Dráha je její délka.",
|
||||
"Průměrná rychlost je dráha dělená časem.",
|
||||
"Rovnoměrný přímočarý pohyb má stálou rychlost a přímou trajektorii.",
|
||||
"Dráha rovnoměrného pohybu je s = v·t.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Změna rychlosti", "Zrychlení",
|
||||
"Tip: jednotka zrychlení je metr za sekundu na druhou.",
|
||||
{
|
||||
"Zrychlení popisuje, jak rychle se mění rychlost.",
|
||||
"Rovnoměrně zrychlený pohyb má stálé zrychlení.",
|
||||
"Rychlost je v = v₀ + a·t.",
|
||||
"Dráha z klidu je s = ½·a·t².",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Pád", "Volný pád",
|
||||
"Tip: tíhové zrychlení u Země je přibližně 9,81 m/s².",
|
||||
{
|
||||
"Volný pád je pohyb jen pod vlivem tíhového zrychlení.",
|
||||
"Tíhové zrychlení g je u povrchu Země asi 9,81 m/s².",
|
||||
"Odpor vzduchu volný pád zpomaluje. Ve vakuu padají tělesa stejně.",
|
||||
"Graf rychlosti na čase je u rovnoměrně zrychleného pohybu přímka.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[1], "fyz_unit2", "fyz_unit2_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit2_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá dráha rovnoměrného pohybu?",
|
||||
{"s = v / t", "s = v·t", "s = a·t", "s = v·a"},
|
||||
4, 1},
|
||||
{"Jaká je jednotka zrychlení?",
|
||||
{"m/s", "m/s²", "N", "J"},
|
||||
4, 1},
|
||||
{"Čemu se rovná rychlost rovnoměrně zrychleného pohybu?",
|
||||
{"v = v₀ + a·t", "v = s·t", "v = a / t", "v = g·m"},
|
||||
4, 0},
|
||||
{"Jak velké je tíhové zrychlení u povrchu Země?",
|
||||
{"Asi 1 m/s²", "Asi 9,81 m/s²", "Asi 100 m/s²", "Přesně rychlost světla"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Rychlost je dráha za čas, proto dráha je rychlost krát čas.",
|
||||
"Zrychlení je změna rychlosti za čas, tedy metr za sekundu za sekundu.",
|
||||
"Počáteční rychlost se k přírůstku a·t přičítá.",
|
||||
"Škola používá g ≈ 9,81 m/s², často i přibližně 10 m/s².",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 1, "fyzunit2", "fyz_ex2_title", "fyz_quiz2_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit3_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • První zákon", "Setrvačnost",
|
||||
"Tip: zákon platí v inerciální soustavě.",
|
||||
{
|
||||
"Těleso zůstává v klidu nebo v rovnoměrném přímočarém pohybu, dokud na ně nepůsobí výsledná síla.",
|
||||
"Setrvačnost je snaha tělesa udržet svůj pohybový stav.",
|
||||
"Hmotnost je míra setrvačnosti.",
|
||||
"Inerciální soustava se vůči jiné inerciální nepohybuje se zrychlením.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Druhý zákon", "Síla a zrychlení",
|
||||
"Tip: newton je síla, která hmotnosti 1 kg udělí zrychlení 1 m/s².",
|
||||
{
|
||||
"Výsledná síla je F = m·a.",
|
||||
"Větší síla při stejné hmotnosti znamená větší zrychlení.",
|
||||
"Větší hmotnost při stejné síle znamená menší zrychlení.",
|
||||
"Jednotka síly je newton, N.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Třetí zákon", "Akce a reakce",
|
||||
"Tip: obě síly působí na dvě různá tělesa.",
|
||||
{
|
||||
"Síly, kterými na sebe dvě tělesa působí, jsou stejně velké a opačně orientované.",
|
||||
"Akce a reakce vznikají i zanikají současně.",
|
||||
"Navzájem se neruší, protože každá působí na jiné těleso.",
|
||||
"Hybnost je p = m·v. V izolované soustavě se hybnost zachovává.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[2], "fyz_unit3", "fyz_unit3_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit3_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co říká první Newtonův zákon?",
|
||||
{"F = m·a",
|
||||
"Těleso nemění pohybový stav, dokud na ně nepůsobí výsledná síla",
|
||||
"Akce a reakce se sčítají na jednom tělese",
|
||||
"Hybnost se vždy ztrácí"},
|
||||
4, 1},
|
||||
{"Jak zní druhý Newtonův zákon?",
|
||||
{"F = m / a", "F = m·a", "F = m·v", "F = a / m"},
|
||||
4, 1},
|
||||
{"Na co působí akce a reakce?",
|
||||
{"Na jedno a totéž těleso a ruší se",
|
||||
"Na dvě různá tělesa",
|
||||
"Jen na těleso v klidu",
|
||||
"Jen ve směru tíhy"},
|
||||
4, 1},
|
||||
{"Co je hybnost?",
|
||||
{"m·a", "m·v", "F·t jen jako jednotka", "m·g·h"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"První zákon je zákon setrvačnosti. Druhý je F = m·a.",
|
||||
"Newton je kg·m/s². Síla a zrychlení mají stejný směr.",
|
||||
"Reakce není síla, která by na stejném tělese rušila akci.",
|
||||
"Hybnost je vektor. Izolovaná soustava ji zachovává.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 2, "fyzunit3", "fyz_ex3_title", "fyz_quiz3_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit4_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Tíha", "Tíhová a třecí síla",
|
||||
"Tip: tíhová síla je G = m·g.",
|
||||
{
|
||||
"Tíhová síla působí svisle dolů a je G = m·g.",
|
||||
"Třecí síla působí proti pohybu nebo proti snaze o pohyb.",
|
||||
"Smykové tření závisí na normálové síle a na součiniteli tření.",
|
||||
"Valivé tření je obvykle menší než smykové.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Tlak", "Síla na plochu",
|
||||
"Tip: pascal je newton na metr čtvereční.",
|
||||
{
|
||||
"Tlak je p = F / S, kde S je obsah plochy.",
|
||||
"Stejná síla na menší plochu znamená větší tlak.",
|
||||
"Jednotka tlaku je pascal, Pa.",
|
||||
"Ostrý hrot má malou plochu, proto velký tlak.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Skládání", "Výslednice sil",
|
||||
"Tip: dvě stejně velké opačné síly dají nulu.",
|
||||
{
|
||||
"Síly stejného směru se sčítají.",
|
||||
"Síly opačného směru se odečítají.",
|
||||
"Kolmé síly se skládají podle Pythagorovy věty.",
|
||||
"Rovnováha nastane, když je výslednice nulová.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[3], "fyz_unit4", "fyz_unit4_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit4_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá tíhová síla?",
|
||||
{"G = m / g", "G = m·g", "G = m·v", "G = F / S"},
|
||||
4, 1},
|
||||
{"Na čem závisí smykové tření?",
|
||||
{"Jen na barvě tělesa",
|
||||
"Na normálové síle a součiniteli tření",
|
||||
"Jen na objemu",
|
||||
"Na rychlosti světla"},
|
||||
4, 1},
|
||||
{"Jak se počítá tlak?",
|
||||
{"p = F·S", "p = F / S", "p = m·a", "p = S / F"},
|
||||
4, 1},
|
||||
{"Jaká je jednotka tlaku?",
|
||||
{"Newton", "Pascal", "Joule", "Watt"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"g je tíhové zrychlení. Tíha má směr svisle dolů.",
|
||||
"Ft = f·Fn. Drsnější styk má větší součinitel tření.",
|
||||
"Menší plocha při stejné síle zvětší tlak.",
|
||||
"1 Pa = 1 N/m². Atmosférický tlak je asi 101 kPa.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 3, "fyzunit4", "fyz_ex4_title", "fyz_quiz4_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit5_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Práce", "Síla po dráze",
|
||||
"Tip: síla kolmá k posunutí práci nekoná.",
|
||||
{
|
||||
"Mechanická práce je W = F·s·cos α.",
|
||||
"α je úhel mezi silou a posunutím.",
|
||||
"Když je síla kolmá k posunutí, práce je nulová.",
|
||||
"Jednotka práce je joule, J.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Energie", "Pohybová a polohová",
|
||||
"Tip: polohová energie roste s výškou.",
|
||||
{
|
||||
"Kinetická energie je Ek = ½·m·v².",
|
||||
"Polohová energie v tíhovém poli je Ep = m·g·h.",
|
||||
"Výšku h počítáme od zvolené hladiny.",
|
||||
"Bez tření se součet kinetické a polohové energie zachovává.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Výkon", "Práce za čas",
|
||||
"Tip: watt je joule za sekundu.",
|
||||
{
|
||||
"Výkon je P = W / t.",
|
||||
"Jednotka výkonu je watt, W.",
|
||||
"Účinnost je podíl užitečné a dodané energie.",
|
||||
"Účinnost je vždy menší než 1, protože část energie se ztrácí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[4], "fyz_unit5", "fyz_unit5_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit5_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Kdy je mechanická práce nulová?",
|
||||
{"Když je síla rovnoběžná s posunutím",
|
||||
"Když je síla kolmá k posunutí",
|
||||
"Když je hmotnost velká",
|
||||
"Když je výkon 1 W"},
|
||||
4, 1},
|
||||
{"Jak se počítá kinetická energie?",
|
||||
{"Ek = m·g·h", "Ek = ½·m·v²", "Ek = F / s", "Ek = m·v"},
|
||||
4, 1},
|
||||
{"Jak se počítá polohová energie v tíhovém poli?",
|
||||
{"Ep = ½·m·v²", "Ep = m·g·h", "Ep = F·a", "Ep = p·V"},
|
||||
4, 1},
|
||||
{"Co je výkon?",
|
||||
{"Práce dělená časem", "Síla dělená plochou",
|
||||
"Hmotnost krát zrychlení", "Hybnost za dráhu"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"cos 90° je 0, proto kolmá síla práci nekoná.",
|
||||
"Dvojnásobná rychlost znamená čtyřnásobnou kinetickou energii.",
|
||||
"Hladinu nulové polohové energie si volíme.",
|
||||
"Watt je J/s. Účinnost je podíl energií, ne jejich součet.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 4, "fyzunit5", "fyz_ex5_title", "fyz_quiz5_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit6_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Zákon", "Newtonova gravitace",
|
||||
"Tip: gravitační síla klesá s druhou mocninou vzdálenosti.",
|
||||
{
|
||||
"Dvě tělesa se přitahují silou Fg = κ·m₁·m₂ / r².",
|
||||
"κ je gravitační konstanta, asi 6,67·10⁻¹¹ N·m²/kg².",
|
||||
"r je vzdálenost středů těles.",
|
||||
"Gravitace působí na dálku a je vždy přitažlivá.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • U Země", "Tíhové zrychlení",
|
||||
"Tip: první kosmická rychlost je asi 7,9 km/s.",
|
||||
{
|
||||
"U povrchu Země je tíhové zrychlení přibližně 9,81 m/s².",
|
||||
"Tíhová síla je výslednice gravitační síly a setrvačné síly od otáčení Země.",
|
||||
"První kosmická rychlost je rychlost kruhové dráhy těsně u povrchu, asi 7,9 km/s.",
|
||||
"Druhá kosmická rychlost, asi 11,2 km/s, stačí k opuštění Země.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Pohyby", "Keplerovy zákony",
|
||||
"Tip: planety obíhají po elipsách, Slunce je v ohnisku.",
|
||||
{
|
||||
"Planety se pohybují po elipsách a Slunce je v jednom ohnisku.",
|
||||
"Průvodič planety opíše za stejný čas stejnou plochu.",
|
||||
"Poměr krychle velké poloosy a čtverce oběžné doby je pro planety stejný.",
|
||||
"Družice padá kolem Země, proto zůstává na oběžné dráze.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[5], "fyz_unit6", "fyz_unit6_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit6_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak závisí gravitační síla na vzdálenosti?",
|
||||
{"Je přímo úměrná vzdálenosti",
|
||||
"Je nepřímo úměrná druhé mocnině vzdálenosti",
|
||||
"Na vzdálenosti nezávisí",
|
||||
"Je úměrná třetí mocnině vzdálenosti"},
|
||||
4, 1},
|
||||
{"Jaká je přibližně gravitační konstanta κ?",
|
||||
{"9,81", "6,67·10⁻¹¹ N·m²/kg²", "3·10⁸ m/s", "101 kPa"},
|
||||
4, 1},
|
||||
{"Co je první kosmická rychlost?",
|
||||
{"Rychlost světla",
|
||||
"Rychlost kruhové dráhy těsně u Země, asi 7,9 km/s",
|
||||
"Rychlost zvuku",
|
||||
"Rychlost volného pádu z 1 m"},
|
||||
4, 1},
|
||||
{"Jaký tvar mají dráhy planet podle Keplera?",
|
||||
{"Kružnice se Sluncem ve středu vždy",
|
||||
"Elipsy a Slunce je v ohnisku",
|
||||
"Přímky",
|
||||
"Paraboly se Zemí v ohnisku"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Dvojnásobná vzdálenost znamená čtvrtinovou sílu.",
|
||||
"κ je velmi malé číslo. g = 9,81 m/s² je zrychlení, ne konstanta κ.",
|
||||
"Druhá kosmická rychlost je asi 11,2 km/s.",
|
||||
"První Keplerův zákon mluví o elipse a ohnisku.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 5, "fyzunit6", "fyz_ex6_title", "fyz_quiz6_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit7_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Otáčení", "Moment síly",
|
||||
"Tip: moment je větší, když síla zabírá dál od osy.",
|
||||
{
|
||||
"Tuhé těleso nemění působením sil svůj tvar.",
|
||||
"Moment síly je M = F·d, kde d je rameno síly.",
|
||||
"Rameno je kolmá vzdálenost osy od přímky síly.",
|
||||
"Jednotka momentu je newton metr, N·m.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Páka", "Rovnováha",
|
||||
"Tip: na páce v rovnováze jsou momenty na obou stranách stejné.",
|
||||
{
|
||||
"Těleso je v rovnováze, když je výslednice sil i výsledný moment nulový.",
|
||||
"Na dvojzvratné páce platí F₁·d₁ = F₂·d₂.",
|
||||
"Páka, kladka a nakloněná rovina jsou jednoduché stroje.",
|
||||
"Jednoduchý stroj práci neušetří, jen změní velikost síly nebo dráhu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Těžiště", "Stabilita",
|
||||
"Tip: těleso je stabilní, když se po malém vychýlení vrací.",
|
||||
{
|
||||
"Těžiště je působiště tíhové síly.",
|
||||
"U stejnorodého pravidelného tělesa je těžiště ve středu.",
|
||||
"Stabilní poloha se po vychýlení vrací, labilní se převrací.",
|
||||
"Nízké těžiště a široká základna zvětšují stabilitu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[6], "fyz_unit7", "fyz_unit7_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit7_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá moment síly?",
|
||||
{"M = F / d", "M = F·d", "M = m·g·h", "M = p·V"},
|
||||
4, 1},
|
||||
{"Kdy je páka v rovnováze?",
|
||||
{"Když jsou síly vždy stejně velké bez ohledu na rameno",
|
||||
"Když se momenty na obou stranách rovnají",
|
||||
"Když je jedno rameno nulové",
|
||||
"Když páka koná práci zdarma"},
|
||||
4, 1},
|
||||
{"Co je těžiště?",
|
||||
{"Místo největšího tlaku kapaliny",
|
||||
"Působiště tíhové síly",
|
||||
"Ohnisko elipsy",
|
||||
"Střed elektrického náboje"},
|
||||
4, 1},
|
||||
{"Která poloha je stabilní?",
|
||||
{"Po malém vychýlení se těleso vrací",
|
||||
"Po malém vychýlení se těleso převrátí",
|
||||
"Těleso zůstane v nové poloze vždy",
|
||||
"Těžiště je nad bodem dotyku co nejvýš a základna je bod"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Delší rameno znamená větší moment při stejné síle.",
|
||||
"F₁·d₁ = F₂·d₂. Menší silou na delším rameni zvedneme větší náklad.",
|
||||
"Těleso se chová, jako by v těžišti působila celá tíha.",
|
||||
"Labilní poloha se po vychýlení vzdaluje. Volná zůstane, kde je.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 6, "fyzunit7", "fyz_ex7_title", "fyz_quiz7_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit8_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Tlak", "Hydrostatický tlak",
|
||||
"Tip: tlak v kapalině roste s hloubkou.",
|
||||
{
|
||||
"Tlak v kapalině způsobený tíhou je p = h·ρ·g.",
|
||||
"h je hloubka, ρ je hustota kapaliny.",
|
||||
"V téže hloubce je tlak ve všech směrech stejný.",
|
||||
"Pascalův zákon: tlak v uzavřené kapalině se šíří všemi směry stejně.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Vztlak", "Archimédův zákon",
|
||||
"Tip: těleso plave, když se jeho průměrná hustota rovná hustotě kapaliny nebo je menší.",
|
||||
{
|
||||
"Na těleso v tekutině působí vztlaková síla svisle vzhůru.",
|
||||
"Vztlak se rovná tíze tekutiny tělesem vytlačené.",
|
||||
"Těleso se potápí, když je jeho hustota větší než hustota tekutiny.",
|
||||
"Těleso se vznáší, když jsou hustoty stejné.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Plyny", "Atmosféra a proudění",
|
||||
"Tip: normální atmosférický tlak je asi 101,3 kPa.",
|
||||
{
|
||||
"Atmosférický tlak u hladiny moře je přibližně 101,3 kPa.",
|
||||
"S výškou atmosférický tlak klesá.",
|
||||
"V užší části trubice proudí kapalina rychleji a tlak tam klesá.",
|
||||
"Na tom stojí vztlak křídla i rozprašovač.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(0, &fyz_lessons[7], "fyz_unit8", "fyz_unit8_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz_unit8_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá hydrostatický tlak?",
|
||||
{"p = h / ρ", "p = h·ρ·g", "p = F·S", "p = m·v"},
|
||||
4, 1},
|
||||
{"Co říká Archimédův zákon?",
|
||||
{"Vztlak se rovná tíze vytlačené tekutiny",
|
||||
"Tlak nezávisí na hloubce",
|
||||
"Kapaliny se nedají stlačit vůbec a nemají vztlak",
|
||||
"Vztlak působí dolů"},
|
||||
4, 0},
|
||||
{"Kdy se těleso v kapalině potápí?",
|
||||
{"Když má menší hustotu než kapalina",
|
||||
"Když má větší hustotu než kapalina",
|
||||
"Když má stejnou hustotu",
|
||||
"Když je hladina v klidu"},
|
||||
4, 1},
|
||||
{"Jak velký je přibližně normální atmosférický tlak?",
|
||||
{"1 Pa", "101 kPa", "9,81 Pa", "6,67·10⁻¹¹ Pa"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Hustší kapalina a větší hloubka znamenají větší tlak.",
|
||||
"Vytlačená tekutina má objem ponořené části tělesa.",
|
||||
"Vznášení je při stejné hustotě. Plování je při menší průměrné hustotě.",
|
||||
"1013 hPa je totéž co asi 101,3 kPa.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(0, 7, "fyzunit8", "fyz_ex8_title", "fyz_quiz8_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
void add_fyz_pages(GtkStack *stack) {
|
||||
typedef GtkWidget *(*FyzBuilder)(void);
|
||||
static const struct {
|
||||
const char *unit_name;
|
||||
const char *ex_name;
|
||||
FyzBuilder build_unit;
|
||||
FyzBuilder build_ex;
|
||||
} pages[] = {
|
||||
{"fyzunit1", "fyzex1", build_fyz_unit1_page, build_fyz_unit1_exercise_page},
|
||||
{"fyzunit2", "fyzex2", build_fyz_unit2_page, build_fyz_unit2_exercise_page},
|
||||
{"fyzunit3", "fyzex3", build_fyz_unit3_page, build_fyz_unit3_exercise_page},
|
||||
{"fyzunit4", "fyzex4", build_fyz_unit4_page, build_fyz_unit4_exercise_page},
|
||||
{"fyzunit5", "fyzex5", build_fyz_unit5_page, build_fyz_unit5_exercise_page},
|
||||
{"fyzunit6", "fyzex6", build_fyz_unit6_page, build_fyz_unit6_exercise_page},
|
||||
{"fyzunit7", "fyzex7", build_fyz_unit7_page, build_fyz_unit7_exercise_page},
|
||||
{"fyzunit8", "fyzex8", build_fyz_unit8_page, build_fyz_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);
|
||||
}
|
||||
}
|
||||
621
src/fyz_year2.c
Normal file
621
src/fyz_year2.c
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
#include "graduately.h"
|
||||
|
||||
/* Year 2: kinetic theory, heat, the structure of matter, changes of
|
||||
* state, mechanical oscillation and waves, sound. */
|
||||
|
||||
NetLesson fyz2_lessons[FYZ_N] = {
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit1", .ex_page = "fyz2ex1" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit2", .ex_page = "fyz2ex2" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit3", .ex_page = "fyz2ex3" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit4", .ex_page = "fyz2ex4" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit5", .ex_page = "fyz2ex5" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit6", .ex_page = "fyz2ex6" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit7", .ex_page = "fyz2ex7" },
|
||||
{ .n_slides = 3, .unit_page = "fyz2unit8", .ex_page = "fyz2ex8" },
|
||||
};
|
||||
|
||||
static GtkWidget *build_fyz2_unit1_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Částice", "Z čeho je látka",
|
||||
"Tip: částice se neustále neuspořádaně pohybují.",
|
||||
{
|
||||
"Látky se skládají z atomů, molekul nebo iontů.",
|
||||
"Částice se neuspořádaně pohybují. Tomu říkáme tepelný pohyb.",
|
||||
"Mezi částicemi působí přitažlivé i odpudivé síly.",
|
||||
"Brownův pohyb a difuze jsou důkazy pohybu částic.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Skupenství", "Pevné, kapalné, plynné",
|
||||
"Tip: v plynu jsou částice daleko od sebe a nevyplňují stálý tvar.",
|
||||
{
|
||||
"V pevné látce částice kmitají kolem rovnovážných poloh.",
|
||||
"V kapalině jsou částice blízko, ale mohou se přesouvat.",
|
||||
"V plynu se částice pohybují volně a narážejí do stěn.",
|
||||
"Plazma je ionizovaný plyn a bývá čtvrté skupenství.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Energie", "Vnitřní energie",
|
||||
"Tip: vnitřní energie roste s teplotou.",
|
||||
{
|
||||
"Vnitřní energie je součet kinetické a potenciální energie částic.",
|
||||
"Teplo je energie předaná díky rozdílu teplot.",
|
||||
"Práce i teplo mohou vnitřní energii změnit.",
|
||||
"Teplota popisuje stav, teplo popisuje děj.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[0], "fyz2_unit1", "fyz2_unit1_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit1_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co dokazuje Brownův pohyb?",
|
||||
{"Že částice stojí", "Že se částice neustále pohybují",
|
||||
"Že světlo je vlna", "Že tlak nezávisí na teplotě"},
|
||||
4, 1},
|
||||
{"Jak se částice chovají v pevné látce?",
|
||||
{"Volně létají nádobou",
|
||||
"Kmitají kolem rovnovážných poloh",
|
||||
"Nemají žádnou energii",
|
||||
"Jsou od sebe jako v řídkém plynu"},
|
||||
4, 1},
|
||||
{"Co je teplo?",
|
||||
{"Stavová veličina stejná jako teplota",
|
||||
"Energie předaná díky rozdílu teplot",
|
||||
"Hmotnost částic",
|
||||
"Tlak nasycené páry"},
|
||||
4, 1},
|
||||
{"Co je vnitřní energie?",
|
||||
{"Jen polohová energie celého tělesa m·g·h",
|
||||
"Součet kinetické a potenciální energie částic",
|
||||
"Práce tíhové síly",
|
||||
"Výkon ohřívače"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Pylová zrnka ve vodě poskakují, protože do nich narážejí molekuly.",
|
||||
"Kapalina teče, plyn vyplní nádobu. Pevná látka drží tvar.",
|
||||
"Teplota je stav. Teplo je přenos energie.",
|
||||
"Zahřátí zvýší kinetickou energii částic, a tím vnitřní energii.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 0, "fyz2unit1", "fyz2_ex1_title", "fyz2_quiz1_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit2_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Stupnice", "Celsiova a termodynamická",
|
||||
"Tip: 0 °C je 273,15 K. Velikost jednoho stupně je stejná.",
|
||||
{
|
||||
"Celsiova teplota má nulu při tání ledu a 100 °C při varu vody za normálního tlaku.",
|
||||
"Termodynamická teplota T se měří v kelvinech.",
|
||||
"T = t + 273,15. Absolutní nula je 0 K, tedy −273,15 °C.",
|
||||
"Částice se při absolutní nule nezastaví úplně, ale klasická teorie tam končí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Teplo", "Kalorimetrická rovnice",
|
||||
"Tip: měrná tepelná kapacita vody je asi 4180 J/(kg·K).",
|
||||
{
|
||||
"Teplo přijaté tělesem je Q = m·c·Δt.",
|
||||
"c je měrná tepelná kapacita, u vody přibližně 4180 J/(kg·K).",
|
||||
"Tepelná kapacita C = m·c říká, kolik tepla ohřeje těleso o 1 K.",
|
||||
"V izolované soustavě je teplo odevzdané rovno teplu přijatému.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Přenos", "Vedení, proudění, záření",
|
||||
"Tip: vakuum nevede teplo částicemi, záření jím projde.",
|
||||
{
|
||||
"Vedení přenáší energii srážkami částic, hlavně v pevných látkách.",
|
||||
"Proudění přenáší teplo pohybem kapaliny nebo plynu.",
|
||||
"Záření přenáší energii elektromagnetickými vlnami i ve vakuu.",
|
||||
"Kovy vedou teplo dobře, vzduch a pěnové izolace špatně.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[1], "fyz2_unit2", "fyz2_unit2_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit2_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Kolik kelvinů je 0 °C?",
|
||||
{"0 K", "100 K", "273,15 K", "373,15 K"},
|
||||
4, 2},
|
||||
{"Jak se počítá přijaté teplo?",
|
||||
{"Q = m·c·Δt", "Q = m·g·h", "Q = ½·m·v²", "Q = p·V"},
|
||||
4, 0},
|
||||
{"Jaká je přibližně měrná tepelná kapacita vody?",
|
||||
{"4180 J/(kg·K)", "9,81 J/(kg·K)", "101 J/(kg·K)", "3·10⁸ J/(kg·K)"},
|
||||
4, 0},
|
||||
{"Který přenos tepla funguje i ve vakuu?",
|
||||
{"Vedení", "Proudění", "Záření", "Difuzi částic"},
|
||||
4, 2},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"100 °C je 373,15 K. Rozdíl 1 °C je stejný jako rozdíl 1 K.",
|
||||
"Δt je změna teploty. Větší hmotnost i větší c znamenají více tepla.",
|
||||
"Voda má velkou měrnou tepelnou kapacitu, proto se ohřívá pomalu.",
|
||||
"Vedení a proudění potřebují látku. Záření ne.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 1, "fyz2unit2", "fyz2_ex2_title", "fyz2_quiz2_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit3_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Kalorimetr", "Směšovací rovnice",
|
||||
"Tip: teplejší těleso teplo odevzdá, chladnější přijme.",
|
||||
{
|
||||
"V izolované soustavě platí Q odevzdané = Q přijaté.",
|
||||
"Při smíchání dvou dávek téže kapaliny je m₁·c·(t₁ − t) = m₂·c·(t − t₂).",
|
||||
"c se u stejné látky zkrátí.",
|
||||
"Kalorimetr sám také přijme část tepla. Přesný výpočet s ním počítá.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Skupenství", "Teplo bez změny teploty",
|
||||
"Tip: při tání a varu se teplota čisté látky nemění.",
|
||||
{
|
||||
"Skupenské teplo tání je Lt = m·lt.",
|
||||
"Skupenské teplo varu je Lv = m·lv.",
|
||||
"Měrné skupenské teplo tání ledu je asi 334 kJ/kg.",
|
||||
"Měrné skupenské teplo varu vody je asi 2,26 MJ/kg.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • 1. věta", "Zákon zachování",
|
||||
"Tip: perpetuum mobile prvního druhu odporuje první větě.",
|
||||
{
|
||||
"První termodynamická věta: ΔU = W + Q.",
|
||||
"Znaménka závisí na dohodě, škola často bere teplo přijaté a práci vykonanou na soustavě.",
|
||||
"Energie nevzniká ani nezaniká, jen se přeměňuje.",
|
||||
"Stroj nemůže trvale konat práci bez přísunu energie.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[2], "fyz2_unit3", "fyz2_unit3_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit3_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co platí v izolované soustavě při výměně tepla?",
|
||||
{"Teplo odevzdané je větší než přijaté",
|
||||
"Teplo odevzdané se rovná teplu přijatému",
|
||||
"Teplota obou těles zůstane původní",
|
||||
"Hmotnost se zdvojnásobí"},
|
||||
4, 1},
|
||||
{"Co se děje s teplotou čisté látky při tání?",
|
||||
{"Stoupá rovnoměrně", "Nemění se, dokud látka taje",
|
||||
"Klesá k absolutní nule", "Skáče o 100 K"},
|
||||
4, 1},
|
||||
{"Jak se počítá skupenské teplo tání?",
|
||||
{"Lt = m·c·Δt", "Lt = m·lt", "Lt = p·V", "Lt = ½·m·v²"},
|
||||
4, 1},
|
||||
{"Co říká první termodynamická věta?",
|
||||
{"Teplo se nedá nikam předat",
|
||||
"Změna vnitřní energie souvisí s teplem a prací",
|
||||
"Teplota je vždy 273 K",
|
||||
"Účinnost tepelného stroje je 100 %"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Kalorimetrická rovnice z toho přímo vychází.",
|
||||
"Dodávané teplo při tání rozrušuje vazby, nezvedá teplotu.",
|
||||
"lt je měrné skupenské teplo tání. U ledu asi 334 kJ/kg.",
|
||||
"Druhá věta omezuje, kolik tepla lze proměnit v práci.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 2, "fyz2unit3", "fyz2_ex3_title", "fyz2_quiz3_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit4_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Model", "Ideální plyn",
|
||||
"Tip: stavová rovnice je p·V = n·R·T.",
|
||||
{
|
||||
"Ideální plyn má zanedbatelný vlastní objem částic a srážky bez ztráty kinetické energie.",
|
||||
"Stavová rovnice je p·V = n·R·T.",
|
||||
"R je molární plynová konstanta, asi 8,31 J/(mol·K).",
|
||||
"T v této rovnici musí být v kelvinech.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Děje", "Izochorický, izobarický, izotermický",
|
||||
"Tip: izotermický děj má stálou teplotu, proto p·V je konstantní.",
|
||||
{
|
||||
"Izochorický děj má stálý objem. Platí p / T = konst.",
|
||||
"Izobarický děj má stálý tlak. Platí V / T = konst.",
|
||||
"Izotermický děj má stálou teplotu. Platí p·V = konst.",
|
||||
"Adiabatický děj nevyměňuje teplo s okolím.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Tlak plynu", "Odkud se bere",
|
||||
"Tip: vyšší teplota znamená rychlejší částice a větší tlak.",
|
||||
{
|
||||
"Tlak plynu vzniká nárazy částic na stěnu.",
|
||||
"Střední kinetická energie částice je úměrná termodynamické teplotě.",
|
||||
"Normální podmínky jsou 0 °C a normální atmosférický tlak.",
|
||||
"Reálný plyn se ideálnímu blíží při nízkém tlaku a vyšší teplotě.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[3], "fyz2_unit4", "fyz2_unit4_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit4_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak zní stavová rovnice ideálního plynu?",
|
||||
{"p·V = n·R·T", "p / V = T", "Q = m·c·Δt", "F = m·a"},
|
||||
4, 0},
|
||||
{"Co je stálé při izotermickém ději?",
|
||||
{"Objem", "Tlak", "Teplota", "Hmotnost částice"},
|
||||
4, 2},
|
||||
{"Co platí při izochorickém ději?",
|
||||
{"V / T = konst.", "p / T = konst.", "p·V = konst.", "p·T = V"},
|
||||
4, 1},
|
||||
{"V jakých jednotkách musí být T ve stavové rovnici?",
|
||||
{"Ve stupních Celsia", "V kelvinech", "Ve wattech", "V pascalech"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"n je látkové množství, R ≈ 8,31 J/(mol·K).",
|
||||
"Boylův-Mariottův zákon: p·V = konst. při stálé teplotě.",
|
||||
"Izochorický znamená stálý objem. Zahřátí zvedne tlak.",
|
||||
"Dosazení Celsiovy teploty do p·V = n·R·T je chyba.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 3, "fyz2unit4", "fyz2_ex4_title", "fyz2_quiz4_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit5_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Deformace", "Hookův zákon",
|
||||
"Tip: v pružné oblasti je prodloužení úměrné síle.",
|
||||
{
|
||||
"Deformace je změna tvaru nebo objemu.",
|
||||
"Pružná deformace zmizí, až síla přestane působit.",
|
||||
"Tvárná deformace zůstane.",
|
||||
"Hookův zákon: F = k·Δl. k je tuhost.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Krystal", "Pevné látky",
|
||||
"Tip: amorfní látka nemá pravidelnou mřížku v celém objemu.",
|
||||
{
|
||||
"Krystal má částice v pravidelné mřížce.",
|
||||
"Amorfní látka, třeba sklo, pravidelnou mřížku na velkou vzdálenost nemá.",
|
||||
"Teplotní roztažnost zvětšuje rozměry při zahřátí.",
|
||||
"Dilatace mostů a kolejí počítá s mezerami.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Povrch", "Kapaliny",
|
||||
"Tip: kapka je kulatá, protože povrchová vrstva se stahuje.",
|
||||
{
|
||||
"Povrchová vrstva kapaliny se chová jako tenká blána.",
|
||||
"Povrchové napětí stahuje povrch na co nejmenší obsah.",
|
||||
"Kapilární elevace zvedá smáčivou kapalinu v úzké trubici.",
|
||||
"Kapilární deprese stahuje nesmáčivou kapalinu, třeba rtuť ve skle.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[4], "fyz2_unit5", "fyz2_unit5_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit5_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co říká Hookův zákon v pružné oblasti?",
|
||||
{"Síla je úměrná prodloužení",
|
||||
"Síla je úměrná druhé mocnině prodloužení vždy",
|
||||
"Deformace je vždy trvalá",
|
||||
"Tlak nezávisí na síle"},
|
||||
4, 0},
|
||||
{"Čím se krystal liší od amorfní látky?",
|
||||
{"Nemá částice",
|
||||
"Má pravidelnou mřížku",
|
||||
"Nemá teplotní roztažnost",
|
||||
"Je vždy plyn"},
|
||||
4, 1},
|
||||
{"Proč má kapka kulový tvar?",
|
||||
{"Protože povrchová vrstva stahuje povrch",
|
||||
"Protože v kapalině není tlak",
|
||||
"Protože kapka je krystal",
|
||||
"Protože Hookův zákon platí jen pro koule"},
|
||||
4, 0},
|
||||
{"Co je kapilární elevace?",
|
||||
{"Pokles nesmáčivé kapaliny",
|
||||
"Vzestup smáčivé kapaliny v úzké trubici",
|
||||
"Var při nízkém tlaku",
|
||||
"Trvalá deformace"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Za mezí pružnosti už závislost není přímá a těleso se nevrátí.",
|
||||
"Sklo je typická amorfní látka. Sůl je krystal.",
|
||||
"Koule má při daném objemu nejmenší povrch.",
|
||||
"Deprese je pokles, třeba rtuti. Elevace je vzestup, třeba vody.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 4, "fyz2unit5", "fyz2_ex5_title", "fyz2_quiz5_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit6_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Tání a tuhnutí", "Pevná látka a kapalina",
|
||||
"Tip: teplota tání a teplota tuhnutí téže látky jsou stejné.",
|
||||
{
|
||||
"Tání mění pevnou látku na kapalinu při teplotě tání.",
|
||||
"Tuhnutí je opačný děj a u čisté látky probíhá při stejné teplotě.",
|
||||
"Příměsi teplotu tání obvykle snižují.",
|
||||
"Led potřebuje skupenské teplo tání, proto směs ledu a vody drží 0 °C.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Vypařování", "Var a pára",
|
||||
"Tip: var nastane, když se tlak syté páry rovná vnějšímu tlaku.",
|
||||
{
|
||||
"Vypařování probíhá z povrchu při každé teplotě.",
|
||||
"Var probíhá v celém objemu při teplotě varu.",
|
||||
"Sytá pára je v rovnováze se svou kapalinou.",
|
||||
"Nižší vnější tlak znamená nižší teplotu varu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Vlhkost", "Pára ve vzduchu",
|
||||
"Tip: relativní vlhkost 100 % znamená, že pára je sytá.",
|
||||
{
|
||||
"Absolutní vlhkost udává hmotnost vodní páry v objemu vzduchu.",
|
||||
"Relativní vlhkost je podíl tlaku páry a tlaku syté páry při dané teplotě.",
|
||||
"Rosný bod je teplota, při které se pára ve vzduchu stane sytou.",
|
||||
"Kondenzace je vznik kapaliny z páry.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[5], "fyz2_unit6", "fyz2_unit6_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit6_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Při jaké teplotě tuhne čistá voda za normálního tlaku?",
|
||||
{"Při 100 °C", "Při 0 °C", "Při −273,15 °C", "Při teplotě varu rtuti"},
|
||||
4, 1},
|
||||
{"Čím se var liší od vypařování?",
|
||||
{"Var probíhá jen na povrchu a při každé teplotě",
|
||||
"Var probíhá v celém objemu při teplotě varu",
|
||||
"Var nepotřebuje skupenské teplo",
|
||||
"Vypařování nastane jen při 100 °C"},
|
||||
4, 1},
|
||||
{"Kdy nastane var?",
|
||||
{"Když je tlak syté páry roven vnějšímu tlaku",
|
||||
"Když je relativní vlhkost nulová",
|
||||
"Když klesne teplota k rosnému bodu",
|
||||
"Když je látka amorfní"},
|
||||
4, 0},
|
||||
{"Co je relativní vlhkost 100 %?",
|
||||
{"Ve vzduchu není žádná pára",
|
||||
"Pára ve vzduchu je sytá",
|
||||
"Teplota je 100 °C",
|
||||
"Tlak je 100 Pa"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Tání a tuhnutí čisté vody jsou při 0 °C. Var je při 100 °C.",
|
||||
"Vypařování je povrchové a děje se i pod teplotou varu.",
|
||||
"Na horách je nižší tlak, proto voda vře při nižší teplotě.",
|
||||
"Rosný bod je teplota, při níž relativní vlhkost dosáhne 100 %.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 5, "fyz2unit6", "fyz2_ex6_title", "fyz2_quiz6_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit7_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Oscilátor", "Perioda a frekvence",
|
||||
"Tip: frekvence je převrácená hodnota periody.",
|
||||
{
|
||||
"Kmitání je pohyb, který se po periodě opakuje.",
|
||||
"Perioda T je doba jednoho kmitu. Frekvence f = 1 / T.",
|
||||
"Jednotka frekvence je hertz, Hz.",
|
||||
"Harmonické kmitání popisuje sinus nebo kosinus.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Dva oscilátory", "Pružina a kyvadlo",
|
||||
"Tip: perioda kyvadla nezávisí na hmotnosti závaží.",
|
||||
{
|
||||
"Pružinový oscilátor má T = 2π·√(m / k).",
|
||||
"Matematické kyvadlo má pro malé výchylky T = 2π·√(l / g).",
|
||||
"Delší kyvadlo kmitá pomaleji.",
|
||||
"Větší g znamená kratší periodu kyvadla.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Rezonance", "Vlastní a nucené kmitání",
|
||||
"Tip: rezonance nastane, když budicí frekvence souhlasí s vlastní.",
|
||||
{
|
||||
"Vlastní frekvence patří volnému oscilátoru.",
|
||||
"Nucené kmitání udržuje vnější síla.",
|
||||
"Při rezonanci amplituda silně vzroste.",
|
||||
"Tlumení energii kmitů odebírá a amplitudu zmenšuje.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[6], "fyz2_unit7", "fyz2_unit7_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit7_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak spolu souvisí frekvence a perioda?",
|
||||
{"f = T", "f = 1 / T", "f = T²", "f = 2π·T"},
|
||||
4, 1},
|
||||
{"Na čem závisí perioda matematického kyvadla?",
|
||||
{"Na hmotnosti závaží a na barvě",
|
||||
"Na délce a na tíhovém zrychlení",
|
||||
"Jen na amplitudě při velkých úhlech jako jediném údaji",
|
||||
"Na tlaku vzduchu jako na hlavní veličině"},
|
||||
4, 1},
|
||||
{"Jak se změní perioda, když kyvadlo prodloužíme?",
|
||||
{"Zkrátí se", "Prodlouží se", "Nezmění se", "Stane se nulovou"},
|
||||
4, 1},
|
||||
{"Kdy nastane rezonance?",
|
||||
{"Když je budicí frekvence rovna vlastní frekvenci",
|
||||
"Když je tlumení nekonečné",
|
||||
"Když oscilátor stojí",
|
||||
"Když je perioda rovna vlnové délce"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"10 Hz znamená 10 kmitů za sekundu, perioda je 0,1 s.",
|
||||
"Vzorec T = 2π·√(l / g) hmotnost neobsahuje.",
|
||||
"Pod odmocninou je délka. Delší l znamená větší T.",
|
||||
"Rezonance může stavbu nebo most rozkmitat nebezpečně.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 6, "fyz2unit7", "fyz2_ex7_title", "fyz2_quiz7_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit8_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Vlna", "Vlnová délka",
|
||||
"Tip: v = λ·f platí pro každou vlnu.",
|
||||
{
|
||||
"Vlnění přenáší energii, ne látku jako celek.",
|
||||
"Vlnová délka λ je vzdálenost dvou sousedních bodů ve stejné fázi.",
|
||||
"Rychlost vlny je v = λ·f.",
|
||||
"Postupné vlnění se šíří prostředím. Stojaté vzniká skládáním.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Druhy", "Příčné a podélné",
|
||||
"Tip: zvuk ve vzduchu je podélné vlnění.",
|
||||
{
|
||||
"U příčného vlnění kmitají částice kolmo ke směru šíření.",
|
||||
"U podélného vlnění kmitají ve směru šíření.",
|
||||
"Na hladině vody je vlnění příčné, zvuk v plynu podélný.",
|
||||
"Odraz, lom a ohyb patří k vlnění obecně.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Zvuk", "Výška, hlasitost, barva",
|
||||
"Tip: zdravé ucho slyší zhruba od 20 Hz do 20 kHz.",
|
||||
{
|
||||
"Zvuk je mechanické vlnění, které vnímáme sluchem.",
|
||||
"Výška tónu odpovídá frekvenci. Hlasitost souvisí s amplitudou.",
|
||||
"Infrazvuk je pod 20 Hz, ultrazvuk nad 20 kHz.",
|
||||
"Ve vzduchu při pokojové teplotě je rychlost zvuku asi 340 m/s.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(1, &fyz2_lessons[7], "fyz2_unit8", "fyz2_unit8_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz2_unit8_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá rychlost vlny?",
|
||||
{"v = λ / f", "v = λ·f", "v = f / λ", "v = T·λ²"},
|
||||
4, 1},
|
||||
{"Jaké vlnění je zvuk ve vzduchu?",
|
||||
{"Příčné elektromagnetické", "Podélné mechanické",
|
||||
"Stojaté jen na hladině", "Příčné jako světlo"},
|
||||
4, 1},
|
||||
{"Které frekvence člověk obvykle slyší?",
|
||||
{"Od 20 Hz do 20 kHz", "Jen nad 20 kHz",
|
||||
"Jen pod 20 Hz", "Od 340 Hz do 340 kHz"},
|
||||
4, 0},
|
||||
{"Jak rychle se šíří zvuk ve vzduchu při pokojové teplotě?",
|
||||
{"Asi 340 m/s", "Asi 3·10⁸ m/s", "Asi 9,81 m/s", "Asi 1500 km/s"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Vyšší frekvence při stejné rychlosti znamená kratší vlnovou délku.",
|
||||
"Světlo je příčné elektromagnetické. Zvuk potřebuje látkové prostředí.",
|
||||
"Pod 20 Hz je infrazvuk, nad 20 kHz ultrazvuk.",
|
||||
"Ve vodě je zvuk rychlejší, zhruba 1500 m/s. Světlo má 3·10⁸ m/s.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(1, 7, "fyz2unit8", "fyz2_ex8_title", "fyz2_quiz8_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
void add_fyz2_pages(GtkStack *stack) {
|
||||
typedef GtkWidget *(*FyzBuilder)(void);
|
||||
static const struct {
|
||||
const char *unit_name;
|
||||
const char *ex_name;
|
||||
FyzBuilder build_unit;
|
||||
FyzBuilder build_ex;
|
||||
} pages[] = {
|
||||
{"fyz2unit1", "fyz2ex1", build_fyz2_unit1_page, build_fyz2_unit1_exercise_page},
|
||||
{"fyz2unit2", "fyz2ex2", build_fyz2_unit2_page, build_fyz2_unit2_exercise_page},
|
||||
{"fyz2unit3", "fyz2ex3", build_fyz2_unit3_page, build_fyz2_unit3_exercise_page},
|
||||
{"fyz2unit4", "fyz2ex4", build_fyz2_unit4_page, build_fyz2_unit4_exercise_page},
|
||||
{"fyz2unit5", "fyz2ex5", build_fyz2_unit5_page, build_fyz2_unit5_exercise_page},
|
||||
{"fyz2unit6", "fyz2ex6", build_fyz2_unit6_page, build_fyz2_unit6_exercise_page},
|
||||
{"fyz2unit7", "fyz2ex7", build_fyz2_unit7_page, build_fyz2_unit7_exercise_page},
|
||||
{"fyz2unit8", "fyz2ex8", build_fyz2_unit8_page, build_fyz2_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);
|
||||
}
|
||||
}
|
||||
618
src/fyz_year3.c
Normal file
618
src/fyz_year3.c
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
#include "graduately.h"
|
||||
|
||||
/* Year 3: electricity and magnetism. Charge, current, circuits,
|
||||
* matter in electric field, magnetic field, induction, alternating
|
||||
* current and electromagnetic waves. */
|
||||
|
||||
NetLesson fyz3_lessons[FYZ_N] = {
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit1", .ex_page = "fyz3ex1" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit2", .ex_page = "fyz3ex2" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit3", .ex_page = "fyz3ex3" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit4", .ex_page = "fyz3ex4" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit5", .ex_page = "fyz3ex5" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit6", .ex_page = "fyz3ex6" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit7", .ex_page = "fyz3ex7" },
|
||||
{ .n_slides = 3, .unit_page = "fyz3unit8", .ex_page = "fyz3ex8" },
|
||||
};
|
||||
|
||||
static GtkWidget *build_fyz3_unit1_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Náboj", "Dva druhy",
|
||||
"Tip: souhlasné náboje se odpuzují, nesouhlasné přitahují.",
|
||||
{
|
||||
"Elektrický náboj je kladný nebo záporný.",
|
||||
"Elementární náboj je e ≈ 1,6·10⁻¹⁹ C.",
|
||||
"Náboj se zachovává a je celistvým násobkem e.",
|
||||
"Třením se náboje rozdělují, nevznikají z ničeho.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Coulomb", "Síla mezi náboji",
|
||||
"Tip: síla klesá s druhou mocninou vzdálenosti.",
|
||||
{
|
||||
"Coulombův zákon: Fe = k·|Q₁·Q₂| / r².",
|
||||
"k je asi 9·10⁹ N·m²/C².",
|
||||
"Vodič má volné náboje, izolant je nemá.",
|
||||
"Elektrické pole je kolem každého náboje.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Pole", "Intenzita a napětí",
|
||||
"Tip: napětí je práce na jednotkový náboj.",
|
||||
{
|
||||
"Intenzita E = F / q ukazuje sílu na kladný jednotkový náboj.",
|
||||
"Homogenní pole má všude stejnou intenzitu, třeba mezi deskami.",
|
||||
"Napětí U = W / Q. Jednotka je volt.",
|
||||
"Ekvipotenciální hladina je množina bodů se stejným potenciálem.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[0], "fyz3_unit1", "fyz3_unit1_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit1_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak na sebe působí souhlasné náboje?",
|
||||
{"Přitahují se", "Odpuzují se", "Nepůsobí", "Jen při stejné hmotnosti"},
|
||||
4, 1},
|
||||
{"Jak velký je elementární náboj?",
|
||||
{"Asi 1,6·10⁻¹⁹ C", "Asi 9·10⁹ C", "1 C přesně jako proton", "Asi 6,67·10⁻¹¹ C"},
|
||||
4, 0},
|
||||
{"Jak závisí Coulombova síla na vzdálenosti?",
|
||||
{"Přímo úměrně", "Nepřímo úměrně druhé mocnině vzdálenosti",
|
||||
"Nezávisí na ní", "Přímo úměrně druhé mocnině"},
|
||||
4, 1},
|
||||
{"Co je elektrické napětí?",
|
||||
{"Síla na jednotkovou hmotnost",
|
||||
"Práce na jednotkový náboj",
|
||||
"Náboj za čas",
|
||||
"Odpor krát plocha"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Nesouhlasné náboje se přitahují. Neutrální těleso má vyrovnané náboje.",
|
||||
"Proton má +e, elektron −e. Coulomb je velmi velký náboj.",
|
||||
"Stejný tvar má i gravitační zákon, jen konstanta je jiná.",
|
||||
"1 V = 1 J/C. Intenzita se měří v N/C nebo V/m.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 0, "fyz3unit1", "fyz3_ex1_title", "fyz3_quiz1_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit2_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Proud", "Náboj v pohybu",
|
||||
"Tip: dohodnutý směr proudu je směr pohybu kladného náboje.",
|
||||
{
|
||||
"Elektrický proud je usměrněný pohyb nabitých částic.",
|
||||
"Proud I = Q / t. Jednotka je ampér.",
|
||||
"V kovech proud nesou volné elektrony.",
|
||||
"Dohodnutý směr proudu je opačný než směr pohybu elektronů.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Ohm", "Odpor",
|
||||
"Tip: větší délka vodiče znamená větší odpor, větší průřez menší.",
|
||||
{
|
||||
"Ohmův zákon pro část obvodu: U = R·I.",
|
||||
"Odpor R závisí na materiálu, délce a průřezu.",
|
||||
"R = ρ·l / S. ρ je měrný elektrický odpor.",
|
||||
"S rostoucí teplotou odpor kovů obvykle roste.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Zdroj", "Svorkové napětí",
|
||||
"Tip: vnitřní odpor zdroje snižuje napětí při odběru proudu.",
|
||||
{
|
||||
"Zdroj má elektromotorické napětí a vnitřní odpor.",
|
||||
"Svorkové napětí je menší než elektromotorické, když obvodem teče proud.",
|
||||
"Zkrat je spojení s velmi malým odporem. Proud je nebezpečně velký.",
|
||||
"Ampérmetr se řadí sériově, voltmetr paralelně.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[1], "fyz3_unit2", "fyz3_unit2_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit2_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá proud?",
|
||||
{"I = Q·t", "I = Q / t", "I = U·R", "I = R / U"},
|
||||
4, 1},
|
||||
{"Jak zní Ohmův zákon pro část obvodu?",
|
||||
{"U = R / I", "U = R·I", "U = I / R", "R = U·I"},
|
||||
4, 1},
|
||||
{"Kdy má kovový vodič větší odpor?",
|
||||
{"Když je kratší a tlustší",
|
||||
"Když je delší a tenčí",
|
||||
"Když má větší průřez při stejné délce",
|
||||
"Když je z látky s nulovým měrným odporem"},
|
||||
4, 1},
|
||||
{"Jak se zapojuje ampérmetr?",
|
||||
{"Paralelně ke spotřebiči", "Sériově do obvodu",
|
||||
"Jen místo voltmetru paralelně", "Mimo obvod"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Ampér je coulomb za sekundu.",
|
||||
"Odpor je U/I. Větší odpor při stejném napětí znamená menší proud.",
|
||||
"R = ρ·l / S. Měrný odpor ρ je vlastnost látky.",
|
||||
"Voltmetr má mít velký odpor a měří napětí vedle spotřebiče.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 1, "fyz3unit2", "fyz3_ex2_title", "fyz3_quiz2_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit3_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Spojení", "Sériově a paralelně",
|
||||
"Tip: sériově se odpory sčítají, proud je všude stejný.",
|
||||
{
|
||||
"Při sériovém spojení je proud stejný a napětí se sčítají.",
|
||||
"Výsledný odpor sériově je R = R₁ + R₂ + …",
|
||||
"Při paralelním spojení je napětí stejné a proudy se sčítají.",
|
||||
"Pro dva paralelní odpory je 1/R = 1/R₁ + 1/R₂.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Kirchhoff", "Uzly a smyčky",
|
||||
"Tip: v uzlu je součet přitékajících proudů roven součtu odtékajících.",
|
||||
{
|
||||
"První Kirchhoffův zákon je o proudu v uzlu.",
|
||||
"Druhý Kirchhoffův zákon: součet napětí ve smyčce je nulový.",
|
||||
"Zdroj ve smyčce dodává napětí, spotřebiče ho ubírají.",
|
||||
"Zákony stačí na jednoduché obvody se dvěma smyčkami.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Výkon", "Práce proudu",
|
||||
"Tip: příkon je P = U·I.",
|
||||
{
|
||||
"Práce elektrického proudu je W = U·I·t.",
|
||||
"Příkon je P = U·I = R·I² = U² / R.",
|
||||
"Kilowatthodina je jednotka energie, ne výkonu.",
|
||||
"Jouleovo teplo ve vodiči je Q = R·I²·t.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[2], "fyz3_unit3", "fyz3_unit3_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit3_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jaký je výsledný odpor dvou sériově spojených rezistorů?",
|
||||
{"R = R₁ + R₂", "1/R = 1/R₁ + 1/R₂", "R = R₁·R₂", "R = R₁ / R₂"},
|
||||
4, 0},
|
||||
{"Co je stejné na paralelně spojených spotřebičích?",
|
||||
{"Proud každým z nich", "Napětí",
|
||||
"Odpor každého z nich", "Jouleovo teplo bez ohledu na odpor"},
|
||||
4, 1},
|
||||
{"Co říká první Kirchhoffův zákon?",
|
||||
{"Součet napětí ve smyčce je nula",
|
||||
"Součet proudů v uzlu je nula",
|
||||
"Odpor roste s teplotou",
|
||||
"Výkon je U děleno I"},
|
||||
4, 1},
|
||||
{"Jak se počítá elektrická práce?",
|
||||
{"W = F·s", "W = U·I·t", "W = R / I", "W = Q·c·Δt"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Paralelní spojení výsledný odpor zmenší. Dva stejné paralelně dají polovinu.",
|
||||
"Větší odpor při stejném napětí bere menší proud.",
|
||||
"Druhý zákon se týká napětí ve smyčce.",
|
||||
"1 kWh = 3,6·10⁶ J. Příkon ve wattech je U·I.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 2, "fyz3unit3", "fyz3_ex3_title", "fyz3_quiz3_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit4_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Polovodič", "Vlastní a příměsová vodivost",
|
||||
"Tip: dioda vede proud hlavně v propustném směru.",
|
||||
{
|
||||
"Polovodič má vodivost mezi vodičem a izolantem.",
|
||||
"S teplotou jeho odpor obvykle klesá, na rozdíl od kovu.",
|
||||
"Typ N má příměs s volnými elektrony, typ P s dírami.",
|
||||
"Přechod PN je základ diody. V závěrném směru téměř nevede.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Kapaliny", "Elektrolyt",
|
||||
"Tip: v elektrolytu nesou proud ionty, ne volné elektrony jako v kovu.",
|
||||
{
|
||||
"Elektrolyt je roztok nebo tavenina, která vede proud ionty.",
|
||||
"Kationty putují ke katodě, anionty k anodě.",
|
||||
"Elektrolýza vylučuje látku na elektrodách.",
|
||||
"Hmotnost vyloučené látky je úměrná náboji, který prošel.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Plyny", "Výboj",
|
||||
"Tip: plyn za běžných podmínek nevede, dokud se neionizuje.",
|
||||
{
|
||||
"Samostatný výboj udržuje ionizaci sám, nesamostatný potřebuje vnější ionizátor.",
|
||||
"Jiskra, oblouk a doutnavý výboj jsou druhy výboje.",
|
||||
"Blesk je jiskrový výboj v atmosféře.",
|
||||
"Výbojka a zářivka využívají záření výboje v plynu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[3], "fyz3_unit4", "fyz3_unit4_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit4_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se s teplotou obvykle mění odpor polovodiče?",
|
||||
{"Roste jako u kovu", "Klesá", "Nemění se", "Skokem se stane nulovým vždy"},
|
||||
4, 1},
|
||||
{"Co je polovodič typu N?",
|
||||
{"Má převahu děr", "Má převahu volných elektronů z příměsi",
|
||||
"Je izolant bez náboje", "Vede jen ionty"},
|
||||
4, 1},
|
||||
{"Čím je nesen proud v elektrolytu?",
|
||||
{"Jen volnými elektrony jako v mědi", "Ionty",
|
||||
"Fotony", "Neutrony"},
|
||||
4, 1},
|
||||
{"Kdy plyn začne výrazně vést proud?",
|
||||
{"Až když je ionizovaný", "Vždy stejně jako kov",
|
||||
"Jen pod absolutní nulou", "Jen když je to vakuum bez částic"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Termistor s klesajícím odporem při zahřátí je typické užití.",
|
||||
"Typ P má díry. Dioda je jeden přechod PN.",
|
||||
"Katoda přitahuje kationty. Faradayův zákon váže hmotnost a náboj.",
|
||||
"Nesamostatný výboj zanikne, když zmizí vnější ionizátor.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 3, "fyz3unit4", "fyz3_ex4_title", "fyz3_quiz4_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit5_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Magnet", "Pole magnetu",
|
||||
"Tip: souhlasné póly se odpuzují.",
|
||||
{
|
||||
"Souhlasné magnetické póly se odpuzují, nesouhlasné přitahují.",
|
||||
"Severní pól střelky ukazuje k jižnímu magnetickému pólu Země.",
|
||||
"Magnetické indukční čáry jsou uzavřené.",
|
||||
"Zemské pole odklání část nabitých částic z vesmíru.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Proud", "Magnetické pole vodiče",
|
||||
"Tip: cívka s proudem se chová jako magnet.",
|
||||
{
|
||||
"Kolem přímého vodiče s proudem jsou indukční čáry kružnice.",
|
||||
"Cívka, solenoid, má uvnitř téměř homogenní pole.",
|
||||
"Na vodič s proudem v magnetickém poli působí síla F = B·I·l·sin α.",
|
||||
"B je magnetická indukce. Jednotka je tesla, T.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Užití", "Motor a měřidlo",
|
||||
"Tip: elektromotor mění elektrickou energii na pohybovou.",
|
||||
{
|
||||
"Stejnosměrný motor využívá sílu na závit s proudem v magnetickém poli.",
|
||||
"Komutátor mění směr proudu v závitu, aby se točil dál.",
|
||||
"Částice s nábojem v magnetickém poli zatáčí, pokud má složku rychlosti kolmou k poli.",
|
||||
"Magnetický záznam a elektromagnet jsou běžné užití pole.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[4], "fyz3_unit5", "fyz3_unit5_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit5_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jaký tvar mají magnetické indukční čáry?",
|
||||
{"Začínají na severním pólu a končí v nekonečnu jako přímky",
|
||||
"Jsou uzavřené",
|
||||
"Jsou vždy rovnoběžné s vodičem",
|
||||
"Existují jen ve vakuu"},
|
||||
4, 1},
|
||||
{"Jak se počítá síla na přímý vodič s proudem v magnetickém poli?",
|
||||
{"F = B·I·l·sin α", "F = k·Q₁·Q₂ / r²", "F = m·g", "F = U / R"},
|
||||
4, 0},
|
||||
{"Jaká je jednotka magnetické indukce?",
|
||||
{"Volt", "Tesla", "Henry jen jako indukce B", "Ampér"},
|
||||
4, 1},
|
||||
{"K čemu je v stejnosměrném motoru komutátor?",
|
||||
{"Aby zvýšil odpor na nekonečno",
|
||||
"Aby měnil směr proudu v závitu a motor se točil dál",
|
||||
"Aby zrušil magnetické pole",
|
||||
"Aby měřil napětí"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Elektrické siločáry začínají a končí na nábojích. Magnetické jsou uzavřené.",
|
||||
"Když je vodič rovnoběžný s polem, sin α je 0 a síla je nulová.",
|
||||
"Tesla je N/(A·m). Henry je jednotka indukčnosti.",
|
||||
"Bez komutátoru by se závit po půl otáčce zastavil.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 4, "fyz3unit5", "fyz3_ex5_title", "fyz3_quiz5_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit6_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Faraday", "Indukované napětí",
|
||||
"Tip: napětí vzniká, jen když se magnetický tok mění.",
|
||||
{
|
||||
"Elektromagnetická indukce vzniká při změně magnetického toku plochou smyčky.",
|
||||
"Magnetický tok je Φ = B·S·cos α.",
|
||||
"Indukované napětí je tím větší, čím rychleji se tok mění.",
|
||||
"Stálé pole a klidná smyčka napětí neindukují.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Lenz", "Směr proudu",
|
||||
"Tip: indukovaný proud působí proti změně, která ho vyvolala.",
|
||||
{
|
||||
"Lenzův zákon určuje směr indukovaného proudu.",
|
||||
"Proud vytváří pole, které brání změně toku.",
|
||||
"Proto se magnet padající měděnou trubkou brzdí.",
|
||||
"Vlastní indukce brání změně proudu v cívce.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Transformátor", "Změna napětí",
|
||||
"Tip: poměr napětí je poměr počtů závitů.",
|
||||
{
|
||||
"Transformátor má dvě cívky na společném jádře.",
|
||||
"U₁ / U₂ = N₁ / N₂.",
|
||||
"Zvyšovací transformátor má na sekundáru víc závitů.",
|
||||
"U ideálního transformátoru je příkon roven výkonu, proud se mění opačně než napětí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[5], "fyz3_unit6", "fyz3_unit6_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit6_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Kdy se ve smyčce indukuje napětí?",
|
||||
{"Když je magnetický tok stálý",
|
||||
"Když se magnetický tok plochou smyčky mění",
|
||||
"Když smyčkou neteče žádný náboj a tok je nulový trvale",
|
||||
"Jen při stejnosměrném proudu v klidném poli"},
|
||||
4, 1},
|
||||
{"Co říká Lenzův zákon?",
|
||||
{"Indukovaný proud podporuje změnu toku",
|
||||
"Indukovaný proud působí proti změně, která ho vyvolala",
|
||||
"Napětí je vždy rovno proudu",
|
||||
"Tok je B děleno S"},
|
||||
4, 1},
|
||||
{"Jaký je poměr napětí na ideálním transformátoru?",
|
||||
{"U₁ / U₂ = N₂ / N₁", "U₁ / U₂ = N₁ / N₂",
|
||||
"U₁ / U₂ = I₁ / I₂ vždy při stejném počtu závitů jen",
|
||||
"Napětí nezávisí na závitech"},
|
||||
4, 1},
|
||||
{"Co platí pro ideální transformátor?",
|
||||
{"Příkon je roven výkonu",
|
||||
"Sekundární proud je vždy nulový",
|
||||
"Funguje i se stejnosměrným stálým proudem",
|
||||
"Napětí na obou cívkách je stejné bez ohledu na závity"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Pohyb magnetu u cívky, nebo změna proudu v primáru, tok mění.",
|
||||
"Zákon zachování energie: indukce nemůže změnu sama zesilovat donekonečna.",
|
||||
"Více závitů na sekundáru znamená vyšší sekundární napětí.",
|
||||
"Stejnosměrný stálý proud tok nemění, proto se netransformuje.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 5, "fyz3unit6", "fyz3_ex6_title", "fyz3_quiz6_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit7_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Střídání", "Perioda a frekvence",
|
||||
"Tip: síť v Česku má frekvenci 50 Hz.",
|
||||
{
|
||||
"Střídavý proud periodicky mění velikost i směr.",
|
||||
"Harmonické napětí popisuje sinus.",
|
||||
"Frekvence sítě je 50 Hz, perioda je 0,02 s.",
|
||||
"Okamžitá hodnota se stále mění. Měří se efektivní hodnota.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Efektivní", "Co ukáže voltmetr",
|
||||
"Tip: efektivní hodnota je maximální dělená odmocninou ze dvou.",
|
||||
{
|
||||
"Efektivní proud vydá na rezistoru stejný výkon jako stejný stejnosměrný proud.",
|
||||
"Pro sinusový průběh je Uef = Umax / √2.",
|
||||
"Síťové napětí 230 V je efektivní hodnota.",
|
||||
"Amplituda je tedy asi 325 V.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Obvod", "Odpor, cívka, kondenzátor",
|
||||
"Tip: na rezistoru jsou napětí a proud ve fázi.",
|
||||
{
|
||||
"Rezistor proud a napětí neposouvá.",
|
||||
"Cívka zpožďuje proud za napětím, kondenzátor ho předbíhá.",
|
||||
"Indukčnost a kapacita závisejí na frekvenci.",
|
||||
"Výkon na rezistoru je P = Uef·Ief.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[6], "fyz3_unit7", "fyz3_unit7_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit7_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jaká je frekvence elektrické sítě v Česku?",
|
||||
{"50 Hz", "230 Hz", "1 Hz", "60 kHz"},
|
||||
4, 0},
|
||||
{"Co znamená síťové napětí 230 V?",
|
||||
{"Maximální hodnotu", "Efektivní hodnotu",
|
||||
"Napětí za jednu periodu jako součet", "Vnitřní odpor"},
|
||||
4, 1},
|
||||
{"Jak spolu souvisí efektivní a maximální hodnota u sinusového napětí?",
|
||||
{"Uef = Umax·√2", "Uef = Umax / √2", "Uef = Umax", "Uef = Umax / 2"},
|
||||
4, 1},
|
||||
{"Jak je to s fází na rezistoru?",
|
||||
{"Proud se zpožďuje o čtvrt periodu",
|
||||
"Napětí a proud jsou ve fázi",
|
||||
"Proud předbíhá o půl periodu",
|
||||
"Fáze závisí jen na barvě rezistoru"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Perioda 50 Hz je 20 ms. V USA je síť 60 Hz.",
|
||||
"Maximální napětí sítě je 230·√2, zhruba 325 V.",
|
||||
"√2 je asi 1,414. Efektivní hodnota je menší než amplituda.",
|
||||
"Fázový posun dělá cívka a kondenzátor, ne samotný rezistor.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 6, "fyz3unit7", "fyz3_ex7_title", "fyz3_quiz7_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit8_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Vznik", "Elektromagnetická vlna",
|
||||
"Tip: ve vakuu se vlna šíří rychlostí světla.",
|
||||
{
|
||||
"Kmitající náboj vyzařuje elektromagnetickou vlnu.",
|
||||
"Elektrická a magnetická složka jsou navzájem kolmé a kolmé ke směru šíření.",
|
||||
"Ve vakuu je rychlost c = 3·10⁸ m/s.",
|
||||
"Vlna přenáší energii a nepotřebuje látkové prostředí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Spektrum", "Od rádia po záření gama",
|
||||
"Tip: viditelné světlo je jen úzká část spektra.",
|
||||
{
|
||||
"Spektrum tvoří rádiové vlny, mikrovlny, infračervené záření, světlo, ultrafialové, rentgenové a gama.",
|
||||
"Větší frekvence znamená kratší vlnovou délku, protože c = λ·f.",
|
||||
"Viditelné světlo je zhruba 400 až 750 nm.",
|
||||
"Za fialovou je ultrafialové záření, před červenou infračervené.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Užití", "Spoje a ohřev",
|
||||
"Tip: mikrovlny rozkmitávají molekuly vody.",
|
||||
{
|
||||
"Rádiové vlny přenášejí rozhlas, televizi i mobilní signál.",
|
||||
"Mikrovlny se používají v radarové technice a v troubě.",
|
||||
"Rentgenové záření prochází měkkými tkáněmi víc než kostmi.",
|
||||
"Všechny tyto vlny jsou totéž elektromagnetické vlnění, liší se frekvencí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(2, &fyz3_lessons[7], "fyz3_unit8", "fyz3_unit8_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz3_unit8_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak rychle se šíří elektromagnetická vlna ve vakuu?",
|
||||
{"Asi 340 m/s", "Asi 3·10⁸ m/s", "Asi 9,81 m/s", "Závisí na hlasitosti"},
|
||||
4, 1},
|
||||
{"Co platí pro vlnovou délku a frekvenci ve vakuu?",
|
||||
{"c = λ / f", "c = λ·f", "c = f / λ", "λ nezávisí na f"},
|
||||
4, 1},
|
||||
{"Kde ve spektru leží viditelné světlo?",
|
||||
{"Mezi rádiovými vlnami a mikrovlnami",
|
||||
"Mezi infračerveným a ultrafialovým zářením",
|
||||
"Za zářením gama",
|
||||
"Jen jako zvuk"},
|
||||
4, 1},
|
||||
{"Čím se od sebe liší rádiová vlna a rentgenové záření?",
|
||||
{"Rentgen není elektromagnetická vlna",
|
||||
"Mají jinou frekvenci",
|
||||
"Rentgen potřebuje vzduch, rádio vakuum",
|
||||
"Rádiová vlna má vždy vyšší frekvenci"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"340 m/s je zvuk. Světlo je skoro milionkrát rychlejší.",
|
||||
"Stejný vztah jako u mechanické vlny, rychlost je c.",
|
||||
"Fialová má kratší vlnovou délku než červená.",
|
||||
"Gama a rentgen mají vysokou frekvenci a krátkou vlnovou délku.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(2, 7, "fyz3unit8", "fyz3_ex8_title", "fyz3_quiz8_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
void add_fyz3_pages(GtkStack *stack) {
|
||||
typedef GtkWidget *(*FyzBuilder)(void);
|
||||
static const struct {
|
||||
const char *unit_name;
|
||||
const char *ex_name;
|
||||
FyzBuilder build_unit;
|
||||
FyzBuilder build_ex;
|
||||
} pages[] = {
|
||||
{"fyz3unit1", "fyz3ex1", build_fyz3_unit1_page, build_fyz3_unit1_exercise_page},
|
||||
{"fyz3unit2", "fyz3ex2", build_fyz3_unit2_page, build_fyz3_unit2_exercise_page},
|
||||
{"fyz3unit3", "fyz3ex3", build_fyz3_unit3_page, build_fyz3_unit3_exercise_page},
|
||||
{"fyz3unit4", "fyz3ex4", build_fyz3_unit4_page, build_fyz3_unit4_exercise_page},
|
||||
{"fyz3unit5", "fyz3ex5", build_fyz3_unit5_page, build_fyz3_unit5_exercise_page},
|
||||
{"fyz3unit6", "fyz3ex6", build_fyz3_unit6_page, build_fyz3_unit6_exercise_page},
|
||||
{"fyz3unit7", "fyz3ex7", build_fyz3_unit7_page, build_fyz3_unit7_exercise_page},
|
||||
{"fyz3unit8", "fyz3ex8", build_fyz3_unit8_page, build_fyz3_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);
|
||||
}
|
||||
}
|
||||
635
src/fyz_year4.c
Normal file
635
src/fyz_year4.c
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
#include "graduately.h"
|
||||
|
||||
/* Year 4: wave and geometric optics, special relativity, quantum
|
||||
* physics, the atom, the nucleus, nuclear reactions and astrophysics. */
|
||||
|
||||
NetLesson fyz4_lessons[FYZ_N] = {
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit1", .ex_page = "fyz4ex1" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit2", .ex_page = "fyz4ex2" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit3", .ex_page = "fyz4ex3" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit4", .ex_page = "fyz4ex4" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit5", .ex_page = "fyz4ex5" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit6", .ex_page = "fyz4ex6" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit7", .ex_page = "fyz4ex7" },
|
||||
{ .n_slides = 3, .unit_page = "fyz4unit8", .ex_page = "fyz4ex8" },
|
||||
};
|
||||
|
||||
static GtkWidget *build_fyz4_unit1_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Paprsek", "Odraz a lom",
|
||||
"Tip: úhel odrazu se rovná úhlu dopadu.",
|
||||
{
|
||||
"Světlo se v homogenním prostředí šíří přímočaře.",
|
||||
"Úhel odrazu se rovná úhlu dopadu. Oba se měří od kolmice.",
|
||||
"Index lomu je n = c / v. Ve skle je větší než 1.",
|
||||
"Snellův zákon: n₁·sin α = n₂·sin β.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Mez", "Úplný odraz",
|
||||
"Tip: úplný odraz nastane při přechodu do opticky řidšího prostředí.",
|
||||
{
|
||||
"Opticky hustší prostředí má větší index lomu.",
|
||||
"Při přechodu do řidšího prostředí se paprsek láme od kolmice.",
|
||||
"Od mezního úhlu se už neláme a nastane úplný odraz.",
|
||||
"Optická vlákna vedou světlo opakovaným úplným odrazem.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Vlna", "Interference a ohyb",
|
||||
"Tip: světlo je příčné elektromagnetické vlnění.",
|
||||
{
|
||||
"Interference je skládání vln. Světlý pruh vzniká při dráhovém rozdílu k·λ.",
|
||||
"Tmavý pruh vzniká při rozdílu liché poloviny vlnové délky.",
|
||||
"Ohyb je patrný, když je překážka srovnatelná s vlnovou délkou.",
|
||||
"Polarizace dokazuje, že světlo je příčné vlnění.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[0], "fyz4_unit1", "fyz4_unit1_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit1_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak zní zákon odrazu?",
|
||||
{"Úhel odrazu je dvojnásobek úhlu dopadu",
|
||||
"Úhel odrazu se rovná úhlu dopadu",
|
||||
"Úhel odrazu je vždy 90°",
|
||||
"Odraz nezávisí na kolmici"},
|
||||
4, 1},
|
||||
{"Co je index lomu?",
|
||||
{"n = v / c", "n = c / v", "n = λ·f v látce dělené c²", "n = sin α"},
|
||||
4, 1},
|
||||
{"Kdy nastane úplný odraz?",
|
||||
{"Při přechodu do opticky řidšího prostředí nad mezním úhlem",
|
||||
"Při každém dopadu na zrcadlo",
|
||||
"Jen ve vakuu",
|
||||
"Při přechodu do hustšího prostředí"},
|
||||
4, 0},
|
||||
{"Kdy vznikne interferencí světlý pruh?",
|
||||
{"Při dráhovém rozdílu k·λ",
|
||||
"Při dráhovém rozdílu vždy λ/2",
|
||||
"Když se vlny nepotkají",
|
||||
"Jen u podélného zvuku"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Úhly se měří od kolmice dopadu, ne od plochy.",
|
||||
"V látce je světlo pomalejší než ve vakuu, proto n > 1.",
|
||||
"Mezní úhel splňuje sin αm = n₂ / n₁ pro n₁ > n₂.",
|
||||
"Podmínka pro minimum je (2k+1)·λ/2.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 0, "fyz4unit1", "fyz4_ex1_title", "fyz4_quiz1_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit2_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Zrcadla", "Dutá a vypuklá",
|
||||
"Tip: zobrazovací rovnice je 1/a + 1/a' = 1/f.",
|
||||
{
|
||||
"Rovinné zrcadlo dává vzpřímený obraz stejné velikosti, zdánlivě za zrcadlem.",
|
||||
"Duté zrcadlo může dát skutečný převrácený obraz.",
|
||||
"Vypuklé zrcadlo dává zmenšený vzpřímený zdánlivý obraz.",
|
||||
"Ohnisková vzdálenost kulového zrcadla je f = r / 2.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Čočky", "Spojka a rozptylka",
|
||||
"Tip: spojka soustředí rovnoběžné paprsky do ohniska.",
|
||||
{
|
||||
"Spojka je uprostřed tlustší a má kladnou ohniskovou vzdálenost.",
|
||||
"Rozptylka je uprostřed tenčí a paprsky rozbíhá.",
|
||||
"Zobrazovací rovnice je 1/a + 1/a' = 1/f.",
|
||||
"a je vzdálenost předmětu, a' vzdálenost obrazu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Oko", "Vady a přístroje",
|
||||
"Tip: krátkozrakost se koriguje rozptylkou.",
|
||||
{
|
||||
"Oko zobrazuje spojnou soustavou na sítnici.",
|
||||
"Krátkozraké oko zobrazuje před sítnici. Pomůže rozptylka.",
|
||||
"Dalekozraké oko zobrazuje za sítnici. Pomůže spojka.",
|
||||
"Lupa je spojka a předmět je mezi čočkou a ohniskem.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[1], "fyz4_unit2", "fyz4_unit2_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit2_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jaká je ohnisková vzdálenost kulového zrcadla?",
|
||||
{"f = r", "f = r / 2", "f = 2·r", "f = 1 / r²"},
|
||||
4, 1},
|
||||
{"Jak zní zobrazovací rovnice čočky?",
|
||||
{"a + a' = f", "1/a + 1/a' = 1/f", "a·a' = f", "1/a − 1/f = a'"},
|
||||
4, 1},
|
||||
{"Čím se koriguje krátkozrakost?",
|
||||
{"Spojkou", "Rozptylkou", "Dutým zrcadlem v oku", "Clonou bez čočky"},
|
||||
4, 1},
|
||||
{"Jaký obraz dává lupa?",
|
||||
{"Skutečný převrácený, předmět je za ohniskem",
|
||||
"Zvětšený vzpřímený zdánlivý, předmět je mezi čočkou a ohniskem",
|
||||
"Zmenšený obraz v nekonečnu vždy",
|
||||
"Obraz stejný jako rovinné zrcadlo"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Poloměr křivosti je dvojnásobek ohniskové vzdálenosti.",
|
||||
"Když je a = 2f, je i a' = 2f a obraz je stejně velký.",
|
||||
"Dalekozrakost koriguje spojka. Obraz pak padne na sítnici.",
|
||||
"Zdánlivý obraz spojky vzniká, když je předmět uvnitř ohniska.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 1, "fyz4unit2", "fyz4_ex2_title", "fyz4_quiz2_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit3_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Postuláty", "Dva principy",
|
||||
"Tip: rychlost světla ve vakuu je ve všech inerciálních soustavách stejná.",
|
||||
{
|
||||
"Fyzikální zákony mají ve všech inerciálních soustavách stejný tvar.",
|
||||
"Rychlost světla ve vakuu je ve všech inerciálních soustavách c.",
|
||||
"c je mezní rychlost pro přenos informace a pro částice s hmotností.",
|
||||
"Klasické skládání rychlostí u rychlostí blízkých c selhává.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Čas a délka", "Dilatace a kontrakce",
|
||||
"Tip: pohybující se hodiny jdou z hlediska klidné soustavy pomaleji.",
|
||||
{
|
||||
"Dilatace času: pohyblivé hodiny jdou pomaleji.",
|
||||
"Kontrakce délky zkracuje rozměr ve směru pohybu.",
|
||||
"Rozměry kolmé ke směru pohybu se nemění.",
|
||||
"Efekty jsou patrné až při rychlostech srovnatelných s c.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Energie", "E = m·c²",
|
||||
"Tip: klidová energie je energie tělesa v soustavě, kde je v klidu.",
|
||||
{
|
||||
"Klidová energie je E₀ = m·c².",
|
||||
"Celková energie roste s rychlostí.",
|
||||
"Hmotnost a energie jsou dvě stránky téže veličiny.",
|
||||
"Částice s nenulovou klidovou hmotností nikdy nedosáhne rychlosti c.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[2], "fyz4_unit3", "fyz4_unit3_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit3_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co platí o rychlosti světla ve vakuu?",
|
||||
{"Závisí na rychlosti zdroje klasickým součtem",
|
||||
"Je ve všech inerciálních soustavách stejná",
|
||||
"Je 340 m/s",
|
||||
"Je různá podle barvy jako hlavní postulát"},
|
||||
4, 1},
|
||||
{"Co je dilatace času?",
|
||||
{"Pohyblivé hodiny jdou z hlediska klidného pozorovatele pomaleji",
|
||||
"Pohyblivé hodiny jdou rychleji",
|
||||
"Čas se zastaví při každé rychlosti",
|
||||
"Délka se prodlužuje"},
|
||||
4, 0},
|
||||
{"Který rozměr se při kontrakci zkracuje?",
|
||||
{"Rozměr kolmý ke směru pohybu",
|
||||
"Rozměr ve směru pohybu",
|
||||
"Všechny rozměry stejně",
|
||||
"Žádný, zkracuje se jen hmotnost"},
|
||||
4, 1},
|
||||
{"Jak se značí klidová energie?",
|
||||
{"E₀ = m·v² / 2", "E₀ = m·c²", "E₀ = m·g·h", "E₀ = h·f"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Druhý postulát nahrazuje klasické skládání rychlostí světla.",
|
||||
"Vzorec obsahuje √(1 − v²/c²) ve jmenovateli vlastního času.",
|
||||
"Tyč kolmá k pohybu má stejnou délku v obou soustavách.",
|
||||
"c² je obrovské číslo, proto i malá hmotnost znamená velkou energii.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 2, "fyz4unit3", "fyz4_ex3_title", "fyz4_quiz3_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit4_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Foton", "Energie kvanta",
|
||||
"Tip: E = h·f. h je Planckova konstanta.",
|
||||
{
|
||||
"Záření si vyměňuje energii po kvantech, fotonech.",
|
||||
"Energie fotonu je E = h·f.",
|
||||
"h je asi 6,63·10⁻³⁴ J·s.",
|
||||
"Větší frekvence znamená energičtější foton.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Fotoefekt", "Světlo vyráží elektrony",
|
||||
"Tip: pod mezní frekvencí elektrony nevyletí, i když je světlo silné.",
|
||||
{
|
||||
"Fotoelektrický jev: foton předá energii elektronu v kovu.",
|
||||
"Výstupní práce Wv je energie potřebná k opuštění kovu.",
|
||||
"Einsteinova rovnice: h·f = Wv + Ek.",
|
||||
"Počet elektronů roste s intenzitou, jejich maximální energie s frekvencí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Dualita", "Vlna i částice",
|
||||
"Tip: de Broglieho vlnová délka je λ = h / p.",
|
||||
{
|
||||
"Světlo se v interferenci chová jako vlna a ve fotoefektu jako částice.",
|
||||
"I elektrony mají vlnové vlastnosti.",
|
||||
"De Broglie: λ = h / p, kde p je hybnost.",
|
||||
"Čím větší hybnost, tím kratší vlnová délka.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[3], "fyz4_unit4", "fyz4_unit4_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit4_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Jak se počítá energie fotonu?",
|
||||
{"E = m·c² jen pro foton v klidu", "E = h·f", "E = h / f", "E = f / h"},
|
||||
4, 1},
|
||||
{"Co rozhoduje o tom, zda fotoefekt nastane?",
|
||||
{"Jen intenzita světla",
|
||||
"Frekvence musí být aspoň mezní",
|
||||
"Jen barva kovu bez frekvence",
|
||||
"Teplota laboratoře jako jediná podmínka"},
|
||||
4, 1},
|
||||
{"Jak zní Einsteinova rovnice fotoefektu?",
|
||||
{"h·f = Wv + Ek", "h·f = Wv − Ek vždy záporně",
|
||||
"E = m·g·h", "h·f = R·I"},
|
||||
4, 0},
|
||||
{"Co říká de Broglieho vztah?",
|
||||
{"λ = h·p", "λ = h / p", "λ = p / h", "λ = c·p"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Foton nemá klidovou hmotnost. Jeho energie je h·f, hybnost h/λ.",
|
||||
"Silnější světlo stejné nízké frekvence elektrony neuvolní.",
|
||||
"Zbytek energie fotonu po výstupní práci je kinetická energie elektronu.",
|
||||
"Makroskopická tělesa mají obrovskou hybnost, proto nepatrnou vlnovou délku.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 3, "fyz4unit4", "fyz4_ex4_title", "fyz4_quiz4_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit5_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Modely", "Od Rutherforda k Bohrovi",
|
||||
"Tip: Rutherfordův pokus ukázal malé kladné jádro.",
|
||||
{
|
||||
"Thomsonův model měl náboj rozptýlený v celém atomu.",
|
||||
"Rutherford: atom má malé kladné jádro a obal z elektronů.",
|
||||
"Většina objemu atomu je prázdná.",
|
||||
"Bohr doplnil, že elektron je jen na určitých drahách bez vyzařování.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Hladiny", "Emise a absorpce",
|
||||
"Tip: atom vyzáří foton, když elektron klesne na nižší hladinu.",
|
||||
{
|
||||
"Energie elektronu v atomu je kvantovaná.",
|
||||
"Při přeskoku dolů atom vyzáří foton, při přeskoku nahoru ho pohltí.",
|
||||
"Rozdíl hladin je E = h·f.",
|
||||
"Spektrum plynu je čárové, spektrum pevné látky je spojité.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Obal", "Slupky",
|
||||
"Tip: slupky se značí K, L, M a odpovídají hlavnímu kvantovému číslu.",
|
||||
{
|
||||
"Hlavní kvantové číslo n určuje slupku a energii ve vodíku.",
|
||||
"Slupka K je n = 1, L je n = 2, M je n = 3.",
|
||||
"Pauliho princip: v atomu nejsou dva elektrony se všemi kvantovými čísly stejnými.",
|
||||
"Chemická vazba vzniká hlavně elektrony ve vnější slupce.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[4], "fyz4_unit5", "fyz4_unit5_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit5_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co ukázal Rutherfordův pokus?",
|
||||
{"Že atom nemá jádro",
|
||||
"Že kladný náboj je soustředěn v malém jádře",
|
||||
"Že elektron má vlnovou délku nula",
|
||||
"Že spektrum pevné látky je čárové"},
|
||||
4, 1},
|
||||
{"Kdy atom vyzáří foton?",
|
||||
{"Když elektron přejde na nižší hladinu",
|
||||
"Když elektron přejde na vyšší hladinu",
|
||||
"Když se jádro nepohne a elektron stojí",
|
||||
"Při každém oběhu podle klasické fyziky trvale"},
|
||||
4, 0},
|
||||
{"Jaká je energie fotonu při přeskoku?",
|
||||
{"Součet obou hladin", "Rozdíl hladin",
|
||||
"Vždy h·c bez rozdílu", "Klidová energie elektronu"},
|
||||
4, 1},
|
||||
{"Která slupka je nejblíž jádru?",
|
||||
{"M", "L", "K", "Libovolná se stejným n"},
|
||||
4, 2},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Odraz mála částic alfa o velký úhel nešel vysvětlit rozptýleným nábojem.",
|
||||
"Přeskok nahoru je absorpce. Elektron energii fotonu přijme.",
|
||||
"E₂ − E₁ = h·f. Větší skok znamená větší frekvenci.",
|
||||
"n = 1 je K. Vyšší n je dál od jádra a má vyšší energii.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 4, "fyz4unit5", "fyz4_ex5_title", "fyz4_quiz5_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit6_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Jádro", "Protonové a nukleonové číslo",
|
||||
"Tip: nukleonové číslo A je počet protonů a neutronů.",
|
||||
{
|
||||
"Jádro tvoří protony a neutrony, souhrnně nukleony.",
|
||||
"Protonové číslo Z je počet protonů a určuje prvek.",
|
||||
"Nukleonové číslo A je počet nukleonů. Neutronů je A − Z.",
|
||||
"Izotopy mají stejné Z a různé A.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Vazba", "Vazebná energie",
|
||||
"Tip: jádro je lehčí než součet volných nukleonů.",
|
||||
{
|
||||
"Jaderné síly drží nukleony pohromadě a působí na krátkou vzdálenost.",
|
||||
"Vazebná energie je energie, kterou je třeba dodat na rozbití jádra na nukleony.",
|
||||
"Hmotnostní úbytek odpovídá vazebné energii podle E = m·c².",
|
||||
"Nejstabilnější jsou jádra kolem železa.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Rozpad", "Alfa, beta, gama",
|
||||
"Tip: poločas je doba, za kterou se rozpadne polovina jader.",
|
||||
{
|
||||
"Záření alfa je jádro helia, má malý dolet a silné ionizační účinky.",
|
||||
"Záření beta jsou elektrony nebo pozitrony z jádra.",
|
||||
"Záření gama je elektromagnetické a proniká nejvíc.",
|
||||
"Poločas rozpadu je pro daný nuklid stálý a nezávisí na okolí.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[5], "fyz4_unit6", "fyz4_unit6_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit6_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co je nukleonové číslo A?",
|
||||
{"Počet protonů", "Počet protonů a neutronů",
|
||||
"Počet elektronů v obalu", "Počet slupek"},
|
||||
4, 1},
|
||||
{"Co jsou izotopy?",
|
||||
{"Jádra se stejným Z a různým A",
|
||||
"Jádra se stejným A a různým Z",
|
||||
"Jádra bez neutronů",
|
||||
"Atomy bez elektronů"},
|
||||
4, 0},
|
||||
{"Co je záření alfa?",
|
||||
{"Elektromagnetická vlna", "Jádro helia",
|
||||
"Volný neutron", "Foton z obalu"},
|
||||
4, 1},
|
||||
{"Co je poločas rozpadu?",
|
||||
{"Doba, za kterou se rozpadne polovina jader",
|
||||
"Doba jednoho oběhu elektronu",
|
||||
"Doba, za kterou vznikne jádro železa",
|
||||
"Doba života jednoho neutronu mimo každou látku jako jediný údaj"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Zapiš uhlík 14 jako A = 14, Z = 6, neutronů 8.",
|
||||
"Stejné protonové číslo znamená stejný prvek.",
|
||||
"Beta je elektron nebo pozitron. Gama je foton.",
|
||||
"Po dvou poločasech zbývá čtvrtina původních jader.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 5, "fyz4unit6", "fyz4_ex6_title", "fyz4_quiz6_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit7_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Štěpení", "Těžká jádra",
|
||||
"Tip: štěpení uranu uvolní neutrony, které mohou štěpit dál.",
|
||||
{
|
||||
"Štěpení rozdělí těžké jádro na dvě středně těžká.",
|
||||
"Uvolní se energie, protože produkty mají větší vazebnou energii na nukleon.",
|
||||
"Při štěpení uranu 235 vznikají i neutrony.",
|
||||
"Řetězová reakce pokračuje, když každý krok uvolní aspoň jeden další neutron.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Reaktor", "Řízená reakce",
|
||||
"Tip: moderátor neutrony zpomaluje, regulační tyče je pohlcují.",
|
||||
{
|
||||
"V reaktoru je řetězová reakce řízená.",
|
||||
"Moderátor, třeba voda, zpomaluje neutrony.",
|
||||
"Regulační tyče neutrony zachycují a výkon tím klesá.",
|
||||
"Teplo z reaktoru ohřívá vodu a pohání turbínu.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Syntéza", "Slučování lehkých jader",
|
||||
"Tip: fúze pohání Slunce. Potřebuje vysokou teplotu.",
|
||||
{
|
||||
"Jaderná syntéza slučuje lehká jádra, třeba vodík na helium.",
|
||||
"Uvolní víc energie na nukleon než štěpení.",
|
||||
"K překonání odpudivé síly je potřeba velmi vysoká teplota.",
|
||||
"Ochrana před zářením stojí na čase, vzdálenosti a stínění.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[6], "fyz4_unit7", "fyz4_unit7_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit7_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Co je řetězová reakce?",
|
||||
{"Jedno štěpení, které se dál nešíří",
|
||||
"Štěpení udržované neutrony z předchozích štěpení",
|
||||
"Slučování elektronů",
|
||||
"Rozpad alfa bez neutronů"},
|
||||
4, 1},
|
||||
{"K čemu je v reaktoru moderátor?",
|
||||
{"Aby neutrony zpomalil",
|
||||
"Aby všechna jádra okamžitě rozbil",
|
||||
"Aby pohltil všechno teplo bez užitku",
|
||||
"Aby zvýšil protonové číslo paliva"},
|
||||
4, 0},
|
||||
{"Co dělají regulační tyče?",
|
||||
{"Neutrony zachycují a reakci brzdí",
|
||||
"Neutrony jen vyrábějí",
|
||||
"Slouží jako palivo místo uranu",
|
||||
"Zvyšují teplotu fúze"},
|
||||
4, 0},
|
||||
{"Proč fúze potřebuje vysokou teplotu?",
|
||||
{"Aby jádra překonala elektrické odpuzování",
|
||||
"Aby se jádra ochladila",
|
||||
"Aby vznikl moderátor",
|
||||
"Aby poločas klesl k nule"},
|
||||
4, 0},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Kritické množství znamená, že neutrony nestačí utéct a reakce běží.",
|
||||
"Pomalý neutron štěpí uran 235 ochotněji než rychlý.",
|
||||
"Zasunutí tyčí výkon sníží. Vysunutí ho zvýší.",
|
||||
"Ve Slunci fúzi pomáhá i obrovský tlak. Záření se stíní olovem a betonem.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 6, "fyz4unit7", "fyz4_ex7_title", "fyz4_quiz7_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit8_page(void) {
|
||||
static const NetSlide slides[] = {
|
||||
{
|
||||
"1 / 3 • Slunce", "Hvězda",
|
||||
"Tip: Slunce získává energii fúzí vodíku na helium.",
|
||||
{
|
||||
"Slunce je hvězda. Svítí díky jaderné syntéze v jádře.",
|
||||
"Světlo ze Slunce letí na Zemi asi 8 minut.",
|
||||
"Svítivost a teplota povrchu řadí hvězdy do Hertzsprungova–Russellova diagramu.",
|
||||
"Většina hvězd leží na hlavní posloupnosti.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"2 / 3 • Vývoj", "Od oblaku k závěru",
|
||||
"Tip: hmotnější hvězda žije kratší dobu.",
|
||||
{
|
||||
"Hvězda vzniká smršťováním oblaku plynu a prachu.",
|
||||
"Po vyčerpání vodíku se mění stavba hvězdy.",
|
||||
"Hvězda podobná Slunci skončí jako bílý trpaslík.",
|
||||
"Velmi hmotná hvězda může skončit výbuchem supernovy a zbyde neutronová hvězda nebo černá díra.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
"3 / 3 • Vesmír", "Galaxie a rozpínání",
|
||||
"Tip: světelný rok je vzdálenost, ne čas.",
|
||||
{
|
||||
"Galaxie je soustava hvězd, plynu a prachu. Slunce je v Mléčné dráze.",
|
||||
"Světelný rok je dráha, kterou světlo urazí za rok.",
|
||||
"Vzdálené galaxie mají spektrum posunuté k červené. To znamená, že se vzdalují.",
|
||||
"Rudý posuv podporuje obraz rozpínajícího se vesmíru.",
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return fyz_unit_page(3, &fyz4_lessons[7], "fyz4_unit8", "fyz4_unit8_sub",
|
||||
slides, G_N_ELEMENTS(slides));
|
||||
}
|
||||
|
||||
static GtkWidget *build_fyz4_unit8_exercise_page(void) {
|
||||
static const ChoiceQ qs[] = {
|
||||
{"Odkud bere Slunce energii?",
|
||||
{"Z hoření uhlí", "Z fúze vodíku na helium",
|
||||
"Z štěpení uranu v kůře", "Z odrazu světla planet"},
|
||||
4, 1},
|
||||
{"Co je hlavní posloupnost?",
|
||||
{"Pás, na kterém leží většina hvězd v HR diagramu",
|
||||
"Dráha Země kolem Slunce",
|
||||
"Řada planet podle velikosti",
|
||||
"Spektrum jen bílých trpaslíků"},
|
||||
4, 0},
|
||||
{"Co je světelný rok?",
|
||||
{"Doba oběhu Země", "Vzdálenost, kterou světlo urazí za rok",
|
||||
"Rychlost světla", "Stáří Slunce"},
|
||||
4, 1},
|
||||
{"Co znamená rudý posuv vzdálených galaxií?",
|
||||
{"Galaxie se přibližují",
|
||||
"Galaxie se vzdalují",
|
||||
"Galaxie přestaly svítit",
|
||||
"Světlo změnilo rychlost ve vakuu"},
|
||||
4, 1},
|
||||
};
|
||||
static const char *hints[] = {
|
||||
"Fúze v jádře Slunce mění hmotnost na energii podle E = m·c².",
|
||||
"Obři a bílí trpaslíci leží mimo hlavní posloupnost.",
|
||||
"Rok je tu doba letu světla, výsledek je délka.",
|
||||
"Posuv k delší vlnové délce je Dopplerův jev rozpínání.",
|
||||
};
|
||||
|
||||
return fyz_mcq_page(3, 7, "fyz4unit8", "fyz4_ex8_title", "fyz4_quiz8_head",
|
||||
qs, hints, 4);
|
||||
}
|
||||
|
||||
void add_fyz4_pages(GtkStack *stack) {
|
||||
typedef GtkWidget *(*FyzBuilder)(void);
|
||||
static const struct {
|
||||
const char *unit_name;
|
||||
const char *ex_name;
|
||||
FyzBuilder build_unit;
|
||||
FyzBuilder build_ex;
|
||||
} pages[] = {
|
||||
{"fyz4unit1", "fyz4ex1", build_fyz4_unit1_page, build_fyz4_unit1_exercise_page},
|
||||
{"fyz4unit2", "fyz4ex2", build_fyz4_unit2_page, build_fyz4_unit2_exercise_page},
|
||||
{"fyz4unit3", "fyz4ex3", build_fyz4_unit3_page, build_fyz4_unit3_exercise_page},
|
||||
{"fyz4unit4", "fyz4ex4", build_fyz4_unit4_page, build_fyz4_unit4_exercise_page},
|
||||
{"fyz4unit5", "fyz4ex5", build_fyz4_unit5_page, build_fyz4_unit5_exercise_page},
|
||||
{"fyz4unit6", "fyz4ex6", build_fyz4_unit6_page, build_fyz4_unit6_exercise_page},
|
||||
{"fyz4unit7", "fyz4ex7", build_fyz4_unit7_page, build_fyz4_unit7_exercise_page},
|
||||
{"fyz4unit8", "fyz4ex8", build_fyz4_unit8_page, build_fyz4_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);
|
||||
}
|
||||
}
|
||||
720
src/fyzika.c
Normal file
720
src/fyzika.c
Normal file
|
|
@ -0,0 +1,720 @@
|
|||
#include "graduately.h"
|
||||
|
||||
/* Physics across four secondary-school years. Each year is a list of
|
||||
* lessons, then slides and a quiz. The syllabus follows the gymnasium
|
||||
* outline: mechanics, thermal physics and waves, electromagnetism,
|
||||
* then optics, relativity, the micro-world and astrophysics. */
|
||||
|
||||
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[FYZ_N];
|
||||
const char *sub_keys[FYZ_N];
|
||||
GtkWidget *nodes[FYZ_N];
|
||||
int note_last_w;
|
||||
} FyzTrack;
|
||||
|
||||
static FyzTrack fyz_tracks[4];
|
||||
static gboolean fyz_ready;
|
||||
|
||||
static void fyz_ensure(void) {
|
||||
static const char *keys0[] = {
|
||||
"fyz_unit1", "fyz_unit2", "fyz_unit3", "fyz_unit4",
|
||||
"fyz_unit5", "fyz_unit6", "fyz_unit7", "fyz_unit8",
|
||||
};
|
||||
static const char *subs0[] = {
|
||||
"fyz_unit1_sub", "fyz_unit2_sub", "fyz_unit3_sub", "fyz_unit4_sub",
|
||||
"fyz_unit5_sub", "fyz_unit6_sub", "fyz_unit7_sub", "fyz_unit8_sub",
|
||||
};
|
||||
static const char *keys1[] = {
|
||||
"fyz2_unit1", "fyz2_unit2", "fyz2_unit3", "fyz2_unit4",
|
||||
"fyz2_unit5", "fyz2_unit6", "fyz2_unit7", "fyz2_unit8",
|
||||
};
|
||||
static const char *subs1[] = {
|
||||
"fyz2_unit1_sub", "fyz2_unit2_sub", "fyz2_unit3_sub", "fyz2_unit4_sub",
|
||||
"fyz2_unit5_sub", "fyz2_unit6_sub", "fyz2_unit7_sub", "fyz2_unit8_sub",
|
||||
};
|
||||
static const char *keys2[] = {
|
||||
"fyz3_unit1", "fyz3_unit2", "fyz3_unit3", "fyz3_unit4",
|
||||
"fyz3_unit5", "fyz3_unit6", "fyz3_unit7", "fyz3_unit8",
|
||||
};
|
||||
static const char *subs2[] = {
|
||||
"fyz3_unit1_sub", "fyz3_unit2_sub", "fyz3_unit3_sub", "fyz3_unit4_sub",
|
||||
"fyz3_unit5_sub", "fyz3_unit6_sub", "fyz3_unit7_sub", "fyz3_unit8_sub",
|
||||
};
|
||||
static const char *keys3[] = {
|
||||
"fyz4_unit1", "fyz4_unit2", "fyz4_unit3", "fyz4_unit4",
|
||||
"fyz4_unit5", "fyz4_unit6", "fyz4_unit7", "fyz4_unit8",
|
||||
};
|
||||
static const char *subs3[] = {
|
||||
"fyz4_unit1_sub", "fyz4_unit2_sub", "fyz4_unit3_sub", "fyz4_unit4_sub",
|
||||
"fyz4_unit5_sub", "fyz4_unit6_sub", "fyz4_unit7_sub", "fyz4_unit8_sub",
|
||||
};
|
||||
static const char *const *all_keys[4] = {keys0, keys1, keys2, keys3};
|
||||
static const char *const *all_subs[4] = {subs0, subs1, subs2, subs3};
|
||||
static const char *maps[] = {"fyzmap", "fyz2map", "fyz3map", "fyz4map"};
|
||||
static const char *titles[] = {
|
||||
"fyz_year1", "fyz_year2", "fyz_year3", "fyz_year4",
|
||||
};
|
||||
static const char *subs[] = {"fyz_sub", "fyz2_sub", "fyz3_sub", "fyz4_sub"};
|
||||
NetLesson *lessons[4] = {
|
||||
fyz_lessons, fyz2_lessons, fyz3_lessons, fyz4_lessons,
|
||||
};
|
||||
char **paths[4] = {
|
||||
&app_progress_fyz, &app_progress_fyz2,
|
||||
&app_progress_fyz3, &app_progress_fyz4,
|
||||
};
|
||||
|
||||
if (fyz_ready)
|
||||
return;
|
||||
for (int y = 0; y < 4; y++) {
|
||||
FyzTrack *T = &fyz_tracks[y];
|
||||
|
||||
T->map_page = maps[y];
|
||||
T->back_page = "fyzyears";
|
||||
T->title_key = titles[y];
|
||||
T->sub_key = subs[y];
|
||||
T->progress_path = paths[y];
|
||||
T->lessons = lessons[y];
|
||||
T->note_last_w = -1;
|
||||
for (int i = 0; i < FYZ_N; i++) {
|
||||
T->unit_keys[i] = all_keys[y][i];
|
||||
T->sub_keys[i] = all_subs[y][i];
|
||||
}
|
||||
}
|
||||
fyz_ready = TRUE;
|
||||
}
|
||||
|
||||
static void fyz_save(FyzTrack *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 < FYZ_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 fyz_load_one(FyzTrack *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 < FYZ_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 fyz_load_progress(void) {
|
||||
fyz_ensure();
|
||||
for (int y = 0; y < 4; y++)
|
||||
fyz_load_one(&fyz_tracks[y]);
|
||||
}
|
||||
|
||||
void fyz_rail_theme_reset(void) {
|
||||
}
|
||||
|
||||
static void fyz_refresh(FyzTrack *T) {
|
||||
for (int i = 0; i < FYZ_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 fyz_mark_done(FyzTrack *T, int lesson_id) {
|
||||
if (lesson_id < 0 || lesson_id >= FYZ_N)
|
||||
return;
|
||||
if (T->lessons[lesson_id].done)
|
||||
return;
|
||||
T->lessons[lesson_id].done = TRUE;
|
||||
fyz_save(T);
|
||||
fyz_refresh(T);
|
||||
refresh_stats_ui();
|
||||
}
|
||||
|
||||
void progress_for_fyz(ProgressSum *out) {
|
||||
if (!out)
|
||||
return;
|
||||
fyz_ensure();
|
||||
for (int y = 0; y < 4; y++) {
|
||||
FyzTrack *T = &fyz_tracks[y];
|
||||
|
||||
out->total_ex += FYZ_N;
|
||||
out->open_units += FYZ_N;
|
||||
for (int i = 0; i < FYZ_N; i++) {
|
||||
if (T->lessons[i].done) {
|
||||
out->done_ex++;
|
||||
out->done_units++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fyz_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 *fyz_lesson_button(FyzTrack *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(fyz_open_unit),
|
||||
&T->lessons[index]);
|
||||
return btn;
|
||||
}
|
||||
|
||||
static GtkWidget *fyz_build_list(FyzTrack *T) {
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *list;
|
||||
|
||||
fyz_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 < FYZ_N; i++)
|
||||
gtk_box_append(GTK_BOX(list), fyz_lesson_button(T, i));
|
||||
fyz_refresh(T);
|
||||
return page;
|
||||
}
|
||||
|
||||
GtkWidget *build_fyzmap_page(void) { return fyz_build_list(&fyz_tracks[0]); }
|
||||
GtkWidget *build_fyz2map_page(void) { return fyz_build_list(&fyz_tracks[1]); }
|
||||
GtkWidget *build_fyz3map_page(void) { return fyz_build_list(&fyz_tracks[2]); }
|
||||
GtkWidget *build_fyz4map_page(void) { return fyz_build_list(&fyz_tracks[3]); }
|
||||
|
||||
static GtkWidget *fyz_year_button(int year, const char *target,
|
||||
const char *title_key, const char *sub_key) {
|
||||
GtkWidget *btn;
|
||||
GtkWidget *row;
|
||||
GtkWidget *num;
|
||||
GtkWidget *texts;
|
||||
GtkWidget *title;
|
||||
GtkWidget *sub;
|
||||
char *num_text;
|
||||
|
||||
btn = gtk_button_new();
|
||||
gtk_widget_add_css_class(btn, "unit-node");
|
||||
gtk_widget_add_css_class(btn, "current");
|
||||
gtk_widget_set_can_focus(btn, FALSE);
|
||||
gtk_widget_set_hexpand(btn, TRUE);
|
||||
gtk_widget_set_size_request(btn, -1, 84);
|
||||
|
||||
row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14);
|
||||
gtk_widget_set_halign(row, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign(row, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_margin_start(row, 18);
|
||||
gtk_widget_set_margin_end(row, 18);
|
||||
gtk_button_set_child(GTK_BUTTON(btn), row);
|
||||
|
||||
num_text = g_strdup_printf("%d", year);
|
||||
num = gtk_label_new(num_text);
|
||||
g_free(num_text);
|
||||
gtk_widget_add_css_class(num, "unit-number");
|
||||
gtk_widget_set_valign(num, GTK_ALIGN_CENTER);
|
||||
gtk_box_append(GTK_BOX(row), num);
|
||||
|
||||
texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
|
||||
gtk_widget_set_halign(texts, GTK_ALIGN_START);
|
||||
gtk_widget_set_hexpand(texts, TRUE);
|
||||
gtk_box_append(GTK_BOX(row), texts);
|
||||
|
||||
title = gtk_label_new(NULL);
|
||||
i18n_bind(title, title_key, 0);
|
||||
gtk_widget_set_halign(title, GTK_ALIGN_START);
|
||||
gtk_widget_add_css_class(title, "unit-name");
|
||||
gtk_box_append(GTK_BOX(texts), title);
|
||||
|
||||
sub = gtk_label_new(NULL);
|
||||
i18n_bind(sub, sub_key, 0);
|
||||
gtk_widget_set_halign(sub, GTK_ALIGN_START);
|
||||
gtk_label_set_wrap(GTK_LABEL(sub), TRUE);
|
||||
gtk_label_set_xalign(GTK_LABEL(sub), 0.0);
|
||||
gtk_widget_add_css_class(sub, "hint");
|
||||
gtk_box_append(GTK_BOX(texts), sub);
|
||||
|
||||
g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free);
|
||||
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
|
||||
return btn;
|
||||
}
|
||||
|
||||
GtkWidget *build_fyzyears_page(void) {
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *list;
|
||||
static const char *targets[] = {"fyzmap", "fyz2map", "fyz3map", "fyz4map"};
|
||||
static const char *titles[] = {
|
||||
"fyz_year1", "fyz_year2", "fyz_year3", "fyz_year4",
|
||||
};
|
||||
static const char *subs[] = {"fyz_sub", "fyz2_sub", "fyz3_sub", "fyz4_sub"};
|
||||
|
||||
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_hexpand(page, TRUE);
|
||||
gtk_widget_set_vexpand(page, TRUE);
|
||||
gtk_widget_set_margin_start(page, 32);
|
||||
gtk_widget_set_margin_end(page, 32);
|
||||
gtk_widget_set_margin_top(page, 24);
|
||||
gtk_widget_set_margin_bottom(page, 24);
|
||||
|
||||
gtk_box_append(GTK_BOX(page),
|
||||
top_bar("subjects", "Fyzika", "fyz_years_sub"));
|
||||
|
||||
scroll = gtk_scrolled_window_new();
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_widget_set_vexpand(scroll, TRUE);
|
||||
gtk_widget_set_margin_top(scroll, 18);
|
||||
gtk_box_append(GTK_BOX(page), scroll);
|
||||
|
||||
list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_widget_set_halign(list, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign(list, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_size_request(list, 480, -1);
|
||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list);
|
||||
|
||||
for (int y = 0; y < 4; y++)
|
||||
gtk_box_append(GTK_BOX(list),
|
||||
fyz_year_button(y + 1, targets[y], titles[y], subs[y]));
|
||||
return page;
|
||||
}
|
||||
|
||||
static void fyz_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 fyz_slide_prev(GtkButton *button, gpointer data) {
|
||||
NetLesson *L = data;
|
||||
|
||||
(void)button;
|
||||
if (!L || L->idx == 0)
|
||||
return;
|
||||
L->idx--;
|
||||
fyz_slide_apply(L);
|
||||
}
|
||||
|
||||
static void fyz_slide_next(GtkButton *button, gpointer data) {
|
||||
NetLesson *L = data;
|
||||
|
||||
(void)button;
|
||||
if (!L)
|
||||
return;
|
||||
if (L->idx + 1 < L->n_slides) {
|
||||
L->idx++;
|
||||
fyz_slide_apply(L);
|
||||
} else {
|
||||
gtk_stack_set_visible_child_name(main_stack, L->ex_page);
|
||||
}
|
||||
}
|
||||
|
||||
static void fyz_rescale(FyzTrack *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 < FYZ_N; i++)
|
||||
net_rescale_lesson_notes(&T->lessons[i], body, head, kick);
|
||||
}
|
||||
|
||||
static gboolean fyz_note_tick(GtkWidget *w, GdkFrameClock *clock,
|
||||
gpointer data) {
|
||||
FyzTrack *T = data;
|
||||
int width = gtk_widget_get_allocated_width(w);
|
||||
|
||||
(void)clock;
|
||||
if (width != T->note_last_w) {
|
||||
T->note_last_w = width;
|
||||
fyz_rescale(T, width);
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
GtkWidget *fyz_unit_page(int year, NetLesson *L, const char *title_key,
|
||||
const char *sub_key, const NetSlide *slides,
|
||||
guint n_slides) {
|
||||
FyzTrack *T;
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *nav;
|
||||
|
||||
fyz_ensure();
|
||||
if (year < 0 || year > 3)
|
||||
year = 0;
|
||||
T = &fyz_tracks[year];
|
||||
|
||||
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, fyz_note_tick, T, NULL);
|
||||
T->note_last_w = -1;
|
||||
fyz_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(fyz_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(fyz_slide_next), L);
|
||||
gtk_box_append(GTK_BOX(nav), L->next_btn);
|
||||
|
||||
L->idx = 0;
|
||||
fyz_slide_apply(L);
|
||||
return page;
|
||||
}
|
||||
|
||||
void fyz_lessons_apply_lang(void) {
|
||||
fyz_ensure();
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int i = 0; i < FYZ_N; i++)
|
||||
fyz_slide_apply(&fyz_tracks[y].lessons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const ChoiceQ *qs;
|
||||
int n;
|
||||
int n_opts;
|
||||
FyzTrack *track;
|
||||
int lesson_id;
|
||||
GtkWidget *feedback;
|
||||
GtkToggleButton **toggles;
|
||||
GtkWidget **hints;
|
||||
} FyzMcqCtx;
|
||||
|
||||
static void fyz_mcq_check(GtkButton *button, gpointer data) {
|
||||
FyzMcqCtx *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"));
|
||||
fyz_mark_done(ctx->track, ctx->lesson_id);
|
||||
} else {
|
||||
set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short"));
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *fyz_mcq_page(int year, int lesson_id, const char *back_page,
|
||||
const char *title_key, const char *heading_key,
|
||||
const ChoiceQ *qs, const char **hints, int n) {
|
||||
GtkWidget *page;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *body;
|
||||
GtkWidget *check;
|
||||
GtkWidget *btns;
|
||||
GtkWidget *head;
|
||||
GtkWidget *intro;
|
||||
FyzMcqCtx *ctx = g_new0(FyzMcqCtx, 1);
|
||||
int n_opts = qs[0].n_options;
|
||||
|
||||
fyz_ensure();
|
||||
if (year < 0 || year > 3)
|
||||
year = 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 = &fyz_tracks[year];
|
||||
ctx->lesson_id = lesson_id;
|
||||
ctx->toggles = g_new0(GtkToggleButton *, n * n_opts);
|
||||
ctx->hints = g_new0(GtkWidget *, n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
GtkWidget *card = mcq_append_question(body, i + 1, &qs[i],
|
||||
&ctx->toggles[i * n_opts]);
|
||||
|
||||
ctx->hints[i] = meaning_add(card, hints[i]);
|
||||
}
|
||||
|
||||
btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_widget_set_margin_top(btns, 8);
|
||||
gtk_widget_set_margin_bottom(btns, 8);
|
||||
gtk_box_append(GTK_BOX(body), btns);
|
||||
|
||||
check = gtk_button_new();
|
||||
i18n_bind(check, "check", 1);
|
||||
gtk_widget_add_css_class(check, "btn-primary");
|
||||
gtk_widget_set_halign(check, GTK_ALIGN_START);
|
||||
gtk_box_append(GTK_BOX(btns), check);
|
||||
g_signal_connect(check, "clicked", G_CALLBACK(fyz_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;
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#define HW_SUBJ 2 /* index of "Technické vybavení" */
|
||||
#define CZ_SUBJ 3 /* index of "Český jazyk a literatura" */
|
||||
#define ON_SUBJ 4 /* index of "Občanská nauka" */
|
||||
#define PHY_SUBJ 7 /* index of "Fyzika" */
|
||||
#define SCI_SUBJ 8 /* index of "Základy Přírodopisných věd" */
|
||||
#define CSS_FILE "style.css"
|
||||
#define CHANGELOG_FILE "changelog.txt"
|
||||
|
|
@ -62,6 +63,10 @@ extern char *app_progress_lit3;
|
|||
extern char *app_progress_lit4;
|
||||
extern char *app_progress_chem;
|
||||
extern char *app_progress_bio;
|
||||
extern char *app_progress_fyz;
|
||||
extern char *app_progress_fyz2;
|
||||
extern char *app_progress_fyz3;
|
||||
extern char *app_progress_fyz4;
|
||||
#define PROGRESS_DIR app_progress_dir
|
||||
#define PROGRESS_U1 app_progress_u1
|
||||
#define PROGRESS_U2 app_progress_u2
|
||||
|
|
@ -140,6 +145,7 @@ extern char *app_progress_bio;
|
|||
#define ON4_LESSONS 16
|
||||
#define LIT_N 8
|
||||
#define SCI_N 8
|
||||
#define FYZ_N 8
|
||||
#define HW_SLIDES 3
|
||||
#define HW2_SLIDES 6
|
||||
#define HW3_SLIDES 2
|
||||
|
|
@ -950,6 +956,29 @@ 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 fyz_load_progress(void);
|
||||
void fyz_rail_theme_reset(void);
|
||||
void fyz_lessons_apply_lang(void);
|
||||
void progress_for_fyz(ProgressSum *out);
|
||||
GtkWidget *fyz_unit_page(int year, NetLesson *L, const char *title_key,
|
||||
const char *sub_key, const NetSlide *slides,
|
||||
guint n_slides);
|
||||
GtkWidget *fyz_mcq_page(int year, int lesson_id, const char *back_page,
|
||||
const char *title_key, const char *heading_key,
|
||||
const ChoiceQ *qs, const char **hints, int n);
|
||||
GtkWidget *build_fyzyears_page(void);
|
||||
GtkWidget *build_fyzmap_page(void);
|
||||
GtkWidget *build_fyz2map_page(void);
|
||||
GtkWidget *build_fyz3map_page(void);
|
||||
GtkWidget *build_fyz4map_page(void);
|
||||
void add_fyz_pages(GtkStack *stack);
|
||||
void add_fyz2_pages(GtkStack *stack);
|
||||
void add_fyz3_pages(GtkStack *stack);
|
||||
void add_fyz4_pages(GtkStack *stack);
|
||||
extern NetLesson fyz_lessons[FYZ_N];
|
||||
extern NetLesson fyz2_lessons[FYZ_N];
|
||||
extern NetLesson fyz3_lessons[FYZ_N];
|
||||
extern NetLesson fyz4_lessons[FYZ_N];
|
||||
void hw_lessons_apply_lang(void);
|
||||
GtkWidget *build_hwyears_page(void);
|
||||
GtkWidget *build_hwmap_page(void);
|
||||
|
|
@ -1039,6 +1068,8 @@ void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr,
|
|||
int width, int height, gpointer data);
|
||||
void draw_science_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||
int width, int height, gpointer data);
|
||||
void draw_physics_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||
int width, int height, gpointer data);
|
||||
void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,
|
||||
int width, int height, gpointer data);
|
||||
void draw_book_icon(GtkDrawingArea *area, cairo_t *cr,
|
||||
|
|
|
|||
187
src/i18n.c
187
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.",
|
||||
"Exercises, hints and vocabulary drills. The app remembers where you left off."},
|
||||
{"welcome_feat1_link", "Začít procvičovat", "Start practicing"},
|
||||
{"welcome_feat2_title", "Šest otevřených předmětů", "Six open subjects"},
|
||||
{"welcome_feat2_title", "Sedm otevřených předmětů", "Seven open subjects"},
|
||||
{"welcome_feat2_body",
|
||||
"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, Czech, civics and natural sciences. The other subjects are still locked."},
|
||||
"Deutsch, sítě, hardware, čeština, občanská nauka, fyzika a přírodní vědy. Ostatní předměty čekají na svůj obsah.",
|
||||
"German, networks, hardware, Czech, civics, physics and natural sciences. The other subjects are still locked."},
|
||||
{"welcome_feat2_link", "Jaké předměty jsou otevřené?", "Which subjects are open?"},
|
||||
{"welcome_stat_value", "6", "6"},
|
||||
{"welcome_stat_value", "7", "7"},
|
||||
{"welcome_stat_label", "otevřené\npředměty", "open\nsubjects"},
|
||||
{"continue", "Pokračuj", "Continue"},
|
||||
{"roadmap_title", "Učební plán", "Learning path"},
|
||||
|
|
@ -1396,6 +1396,183 @@ const TrEntry tr_ui[] = {
|
|||
{"bio_ex8_title", "Kvíz: ekologie", "Quiz: ecology"},
|
||||
{"bio_quiz8_head", "Ověřte si vztahy v ekosystému",
|
||||
"Check relationships in an ecosystem"},
|
||||
{"fyz_years_sub", "Fyzika podle osnov středních škol. Vyberte ročník.",
|
||||
"Physics from the secondary-school syllabus. Choose a year."},
|
||||
{"fyz_year1", "1. ročník", "Year 1"},
|
||||
{"fyz_year2", "2. ročník", "Year 2"},
|
||||
{"fyz_year3", "3. ročník", "Year 3"},
|
||||
{"fyz_year4", "4. ročník", "Year 4"},
|
||||
{"fyz_sub", "Mechanika: veličiny, pohyb, síly a energie.",
|
||||
"Mechanics: quantities, motion, forces and energy."},
|
||||
{"fyz2_sub", "Molekulová fyzika, teplo, kmity a vlny.",
|
||||
"Molecular physics, heat, oscillations and waves."},
|
||||
{"fyz3_sub", "Elektřina a magnetismus.",
|
||||
"Electricity and magnetism."},
|
||||
{"fyz4_sub", "Optika, relativita, mikročástice a vesmír.",
|
||||
"Optics, relativity, the micro-world and the universe."},
|
||||
{"fyz_unit1", "Fyzikální veličiny", "Physical quantities"},
|
||||
{"fyz_unit1_sub", "SI, skalár a vektor, chyba měření.",
|
||||
"SI, scalar and vector, measurement error."},
|
||||
{"fyz_ex1_title", "Kvíz: veličiny", "Quiz: quantities"},
|
||||
{"fyz_quiz1_head", "Ověřte si jednotky a chyby", "Check units and errors"},
|
||||
{"fyz_unit2", "Kinematika", "Kinematics"},
|
||||
{"fyz_unit2_sub", "Dráha, rychlost a zrychlení.",
|
||||
"Distance, speed and acceleration."},
|
||||
{"fyz_ex2_title", "Kvíz: kinematika", "Quiz: kinematics"},
|
||||
{"fyz_quiz2_head", "Ověřte si pohyb", "Check motion"},
|
||||
{"fyz_unit3", "Newtonovy zákony", "Newton's laws"},
|
||||
{"fyz_unit3_sub", "Setrvačnost, síla a hybnost.",
|
||||
"Inertia, force and momentum."},
|
||||
{"fyz_ex3_title", "Kvíz: Newton", "Quiz: Newton"},
|
||||
{"fyz_quiz3_head", "Ověřte si zákony síly", "Check the laws of force"},
|
||||
{"fyz_unit4", "Síly v běžných situacích", "Everyday forces"},
|
||||
{"fyz_unit4_sub", "Tíha, tření, tlak a výslednice.",
|
||||
"Weight, friction, pressure and the resultant."},
|
||||
{"fyz_ex4_title", "Kvíz: síly", "Quiz: forces"},
|
||||
{"fyz_quiz4_head", "Ověřte si tíhu a tlak", "Check weight and pressure"},
|
||||
{"fyz_unit5", "Práce, energie a výkon", "Work, energy and power"},
|
||||
{"fyz_unit5_sub", "Mechanická práce, energie a účinnost.",
|
||||
"Mechanical work, energy and efficiency."},
|
||||
{"fyz_ex5_title", "Kvíz: energie", "Quiz: energy"},
|
||||
{"fyz_quiz5_head", "Ověřte si práci a výkon", "Check work and power"},
|
||||
{"fyz_unit6", "Gravitační pole", "Gravitational field"},
|
||||
{"fyz_unit6_sub", "Newtonův gravitační zákon a kosmické rychlosti.",
|
||||
"Newton's law of gravitation and cosmic speeds."},
|
||||
{"fyz_ex6_title", "Kvíz: gravitace", "Quiz: gravity"},
|
||||
{"fyz_quiz6_head", "Ověřte si gravitační pole", "Check the gravitational field"},
|
||||
{"fyz_unit7", "Tuhé těleso", "Rigid body"},
|
||||
{"fyz_unit7_sub", "Moment síly, páka a těžiště.",
|
||||
"Moment of a force, the lever and the centre of gravity."},
|
||||
{"fyz_ex7_title", "Kvíz: tuhé těleso", "Quiz: the rigid body"},
|
||||
{"fyz_quiz7_head", "Ověřte si otáčení", "Check rotation"},
|
||||
{"fyz_unit8", "Kapaliny a plyny", "Liquids and gases"},
|
||||
{"fyz_unit8_sub", "Hydrostatika, Archimédés a Bernoulli.",
|
||||
"Hydrostatics, Archimedes and Bernoulli."},
|
||||
{"fyz_ex8_title", "Kvíz: tekutiny", "Quiz: fluids"},
|
||||
{"fyz_quiz8_head", "Ověřte si tlak v kapalině", "Check pressure in a liquid"},
|
||||
{"fyz2_unit1", "Částicová stavba", "Particle structure"},
|
||||
{"fyz2_unit1_sub", "Brownův pohyb, skupenství a vnitřní energie.",
|
||||
"Brownian motion, states of matter and internal energy."},
|
||||
{"fyz2_ex1_title", "Kvíz: částice", "Quiz: particles"},
|
||||
{"fyz2_quiz1_head", "Ověřte si stavbu látky", "Check the structure of matter"},
|
||||
{"fyz2_unit2", "Teplota a teplo", "Temperature and heat"},
|
||||
{"fyz2_unit2_sub", "Kelvin, měrná tepelná kapacita a šíření tepla.",
|
||||
"The kelvin, specific heat capacity and heat transfer."},
|
||||
{"fyz2_ex2_title", "Kvíz: teplo", "Quiz: heat"},
|
||||
{"fyz2_quiz2_head", "Ověřte si teplotu a teplo", "Check temperature and heat"},
|
||||
{"fyz2_unit3", "Kalorimetrie", "Calorimetry"},
|
||||
{"fyz2_unit3_sub", "Směšování, skupenské teplo a první zákon.",
|
||||
"Mixing, latent heat and the first law."},
|
||||
{"fyz2_ex3_title", "Kvíz: kalorimetrie", "Quiz: calorimetry"},
|
||||
{"fyz2_quiz3_head", "Ověřte si tepelnou výměnu", "Check heat exchange"},
|
||||
{"fyz2_unit4", "Ideální plyn", "Ideal gas"},
|
||||
{"fyz2_unit4_sub", "Stavová rovnice a děje.",
|
||||
"The equation of state and processes."},
|
||||
{"fyz2_ex4_title", "Kvíz: plyn", "Quiz: gases"},
|
||||
{"fyz2_quiz4_head", "Ověřte si stavovou rovnici", "Check the equation of state"},
|
||||
{"fyz2_unit5", "Pevné látky a kapaliny", "Solids and liquids"},
|
||||
{"fyz2_unit5_sub", "Hooke, roztažnost a povrchové napětí.",
|
||||
"Hooke, expansion and surface tension."},
|
||||
{"fyz2_ex5_title", "Kvíz: látky", "Quiz: materials"},
|
||||
{"fyz2_quiz5_head", "Ověřte si deformaci a povrch", "Check deformation and surfaces"},
|
||||
{"fyz2_unit6", "Změny skupenství", "Changes of state"},
|
||||
{"fyz2_unit6_sub", "Tání, var a vlhkost vzduchu.",
|
||||
"Melting, boiling and humidity."},
|
||||
{"fyz2_ex6_title", "Kvíz: skupenství", "Quiz: states of matter"},
|
||||
{"fyz2_quiz6_head", "Ověřte si tání a var", "Check melting and boiling"},
|
||||
{"fyz2_unit7", "Mechanické kmitání", "Mechanical oscillations"},
|
||||
{"fyz2_unit7_sub", "Pružina, kyvadlo a rezonance.",
|
||||
"The spring, the pendulum and resonance."},
|
||||
{"fyz2_ex7_title", "Kvíz: kmity", "Quiz: oscillations"},
|
||||
{"fyz2_quiz7_head", "Ověřte si oscilátor", "Check the oscillator"},
|
||||
{"fyz2_unit8", "Vlnění a zvuk", "Waves and sound"},
|
||||
{"fyz2_unit8_sub", "Vlnová délka, frekvence a slyšitelný zvuk.",
|
||||
"Wavelength, frequency and audible sound."},
|
||||
{"fyz2_ex8_title", "Kvíz: zvuk", "Quiz: sound"},
|
||||
{"fyz2_quiz8_head", "Ověřte si vlnění", "Check waves"},
|
||||
{"fyz3_unit1", "Elektrický náboj a pole", "Electric charge and field"},
|
||||
{"fyz3_unit1_sub", "Coulombův zákon a napětí.",
|
||||
"Coulomb's law and voltage."},
|
||||
{"fyz3_ex1_title", "Kvíz: náboj", "Quiz: charge"},
|
||||
{"fyz3_quiz1_head", "Ověřte si elektrické pole", "Check the electric field"},
|
||||
{"fyz3_unit2", "Proud v kovech", "Current in metals"},
|
||||
{"fyz3_unit2_sub", "Ohmův zákon a odpor.",
|
||||
"Ohm's law and resistance."},
|
||||
{"fyz3_ex2_title", "Kvíz: proud", "Quiz: current"},
|
||||
{"fyz3_quiz2_head", "Ověřte si Ohmův zákon", "Check Ohm's law"},
|
||||
{"fyz3_unit3", "Elektrické obvody", "Electric circuits"},
|
||||
{"fyz3_unit3_sub", "Sériové a paralelní spojení, výkon.",
|
||||
"Series and parallel connection, power."},
|
||||
{"fyz3_ex3_title", "Kvíz: obvody", "Quiz: circuits"},
|
||||
{"fyz3_quiz3_head", "Ověřte si zapojení", "Check the connections"},
|
||||
{"fyz3_unit4", "Polovodiče, kapaliny a plyny",
|
||||
"Semiconductors, liquids and gases"},
|
||||
{"fyz3_unit4_sub", "Dioda, elektrolýza a výboj.",
|
||||
"The diode, electrolysis and discharge."},
|
||||
{"fyz3_ex4_title", "Kvíz: vodivost", "Quiz: conduction"},
|
||||
{"fyz3_quiz4_head", "Ověřte si polovodiče a ionty",
|
||||
"Check semiconductors and ions"},
|
||||
{"fyz3_unit5", "Magnetické pole", "Magnetic field"},
|
||||
{"fyz3_unit5_sub", "Indukční čáry a síla na vodič.",
|
||||
"Field lines and the force on a wire."},
|
||||
{"fyz3_ex5_title", "Kvíz: magnetismus", "Quiz: magnetism"},
|
||||
{"fyz3_quiz5_head", "Ověřte si magnetické pole", "Check the magnetic field"},
|
||||
{"fyz3_unit6", "Elektromagnetická indukce", "Electromagnetic induction"},
|
||||
{"fyz3_unit6_sub", "Faraday, Lenz a transformátor.",
|
||||
"Faraday, Lenz and the transformer."},
|
||||
{"fyz3_ex6_title", "Kvíz: indukce", "Quiz: induction"},
|
||||
{"fyz3_quiz6_head", "Ověřte si indukci", "Check induction"},
|
||||
{"fyz3_unit7", "Střídavý proud", "Alternating current"},
|
||||
{"fyz3_unit7_sub", "Efektivní hodnota a fáze.",
|
||||
"The rms value and phase."},
|
||||
{"fyz3_ex7_title", "Kvíz: střídavý proud", "Quiz: alternating current"},
|
||||
{"fyz3_quiz7_head", "Ověřte si síť 230 V", "Check the 230 V grid"},
|
||||
{"fyz3_unit8", "Elektromagnetické vlnění", "Electromagnetic waves"},
|
||||
{"fyz3_unit8_sub", "Rychlost světla a spektrum.",
|
||||
"The speed of light and the spectrum."},
|
||||
{"fyz3_ex8_title", "Kvíz: spektrum", "Quiz: the spectrum"},
|
||||
{"fyz3_quiz8_head", "Ověřte si elektromagnetickou vlnu",
|
||||
"Check the electromagnetic wave"},
|
||||
{"fyz4_unit1", "Vlnová optika", "Wave optics"},
|
||||
{"fyz4_unit1_sub", "Odraz, lom, interference a ohyb.",
|
||||
"Reflection, refraction, interference and diffraction."},
|
||||
{"fyz4_ex1_title", "Kvíz: optika", "Quiz: optics"},
|
||||
{"fyz4_quiz1_head", "Ověřte si lom a odraz", "Check refraction and reflection"},
|
||||
{"fyz4_unit2", "Zobrazování", "Image formation"},
|
||||
{"fyz4_unit2_sub", "Zrcadla, čočky a oko.",
|
||||
"Mirrors, lenses and the eye."},
|
||||
{"fyz4_ex2_title", "Kvíz: čočky", "Quiz: lenses"},
|
||||
{"fyz4_quiz2_head", "Ověřte si zobrazování", "Check image formation"},
|
||||
{"fyz4_unit3", "Speciální relativita", "Special relativity"},
|
||||
{"fyz4_unit3_sub", "Postuláty, dilatace a klidová energie.",
|
||||
"The postulates, dilation and rest energy."},
|
||||
{"fyz4_ex3_title", "Kvíz: relativita", "Quiz: relativity"},
|
||||
{"fyz4_quiz3_head", "Ověřte si dva postuláty", "Check the two postulates"},
|
||||
{"fyz4_unit4", "Kvantové jevy", "Quantum phenomena"},
|
||||
{"fyz4_unit4_sub", "Foton, fotoefekt a de Broglie.",
|
||||
"The photon, the photoelectric effect and de Broglie."},
|
||||
{"fyz4_ex4_title", "Kvíz: kvanta", "Quiz: quanta"},
|
||||
{"fyz4_quiz4_head", "Ověřte si foton", "Check the photon"},
|
||||
{"fyz4_unit5", "Stavba atomu", "Structure of the atom"},
|
||||
{"fyz4_unit5_sub", "Rutherford, Bohr a spektra.",
|
||||
"Rutherford, Bohr and spectra."},
|
||||
{"fyz4_ex5_title", "Kvíz: atom", "Quiz: the atom"},
|
||||
{"fyz4_quiz5_head", "Ověřte si hladiny", "Check the energy levels"},
|
||||
{"fyz4_unit6", "Atomové jádro", "The atomic nucleus"},
|
||||
{"fyz4_unit6_sub", "Nukleony, vazebná energie a radioaktivita.",
|
||||
"Nucleons, binding energy and radioactivity."},
|
||||
{"fyz4_ex6_title", "Kvíz: jádro", "Quiz: the nucleus"},
|
||||
{"fyz4_quiz6_head", "Ověřte si rozpad", "Check radioactive decay"},
|
||||
{"fyz4_unit7", "Jaderné reakce", "Nuclear reactions"},
|
||||
{"fyz4_unit7_sub", "Štěpení, reaktor a fúze.",
|
||||
"Fission, the reactor and fusion."},
|
||||
{"fyz4_ex7_title", "Kvíz: reakce", "Quiz: reactions"},
|
||||
{"fyz4_quiz7_head", "Ověřte si štěpení a fúzi", "Check fission and fusion"},
|
||||
{"fyz4_unit8", "Astrofyzika", "Astrophysics"},
|
||||
{"fyz4_unit8_sub", "Hvězdy, galaxie a rozpínání vesmíru.",
|
||||
"Stars, galaxies and the expanding universe."},
|
||||
{"fyz4_ex8_title", "Kvíz: vesmír", "Quiz: the universe"},
|
||||
{"fyz4_quiz8_head", "Ověřte si hvězdy a galaxie", "Check stars and galaxies"},
|
||||
{"czech_sub", "Vyberte oblast a začněte procvičovat.",
|
||||
"Pick an area and start practicing."},
|
||||
{"Literatura", "Literatura", "Literature"},
|
||||
|
|
@ -2425,6 +2602,7 @@ void on3_lessons_apply_lang(void);
|
|||
void on4_lessons_apply_lang(void);
|
||||
void lit_lessons_apply_lang(void);
|
||||
void sci_lessons_apply_lang(void);
|
||||
void fyz_lessons_apply_lang(void);
|
||||
void net_rail_theme_reset(void);
|
||||
|
||||
void apply_language(void) {
|
||||
|
|
@ -2445,5 +2623,6 @@ void apply_language(void) {
|
|||
on4_lessons_apply_lang();
|
||||
lit_lessons_apply_lang();
|
||||
sci_lessons_apply_lang();
|
||||
fyz_lessons_apply_lang();
|
||||
search_apply_lang();
|
||||
}
|
||||
|
|
|
|||
33
src/icons.c
33
src/icons.c
|
|
@ -228,6 +228,39 @@ void draw_science_icon(GtkDrawingArea *area, cairo_t *cr,
|
|||
cairo_stroke(cr);
|
||||
}
|
||||
|
||||
/* Atom glyph for Fyzika: nucleus and two orbits. */
|
||||
void draw_physics_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 cy = height / 2.0;
|
||||
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_width(cr, MAX(1.6, s * 0.06));
|
||||
cairo_arc(cr, cx, cy, s * 0.10, 0, 2 * G_PI);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_save(cr);
|
||||
cairo_translate(cr, cx, cy);
|
||||
cairo_scale(cr, 1.0, 0.38);
|
||||
cairo_arc(cr, 0, 0, s * 0.34, 0, 2 * G_PI);
|
||||
cairo_restore(cr);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_save(cr);
|
||||
cairo_translate(cr, cx, cy);
|
||||
cairo_rotate(cr, 1.05);
|
||||
cairo_scale(cr, 1.0, 0.38);
|
||||
cairo_arc(cr, 0, 0, s * 0.34, 0, 2 * G_PI);
|
||||
cairo_restore(cr);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
|
||||
/* Open book glyph, painted in the given colour. */
|
||||
static void book_paint(cairo_t *cr, int width, int height, Rgb c) {
|
||||
const double w = width;
|
||||
|
|
|
|||
13
src/main.c
13
src/main.c
|
|
@ -390,6 +390,10 @@ static gboolean run_smoke_test(gpointer data) {
|
|||
"czechmap",
|
||||
"lityears", "litmap", "lit2map", "lit3map", "lit4map",
|
||||
"scimap", "chemmap", "biomap",
|
||||
"fyzyears", "fyzmap", "fyz2map", "fyz3map", "fyz4map",
|
||||
"fyzunit1", "fyzex1", "fyzunit8", "fyzex8",
|
||||
"fyz2unit1", "fyz2ex1", "fyz3unit1", "fyz4unit1",
|
||||
"fyz4unit8", "fyz4ex8",
|
||||
"chemunit1", "chemex1", "chemunit8", "chemex8",
|
||||
"biounit1", "bioex1", "biounit8", "bioex8",
|
||||
"litunit1", "litex1", "litunit8", "litex8",
|
||||
|
|
@ -528,6 +532,15 @@ void activate(GtkApplication *app, gpointer user_data) {
|
|||
add_on3_pages(main_stack);
|
||||
gtk_stack_add_named(main_stack, build_on4map_page(), "on4map");
|
||||
add_on4_pages(main_stack);
|
||||
gtk_stack_add_named(main_stack, build_fyzyears_page(), "fyzyears");
|
||||
gtk_stack_add_named(main_stack, build_fyzmap_page(), "fyzmap");
|
||||
add_fyz_pages(main_stack);
|
||||
gtk_stack_add_named(main_stack, build_fyz2map_page(), "fyz2map");
|
||||
add_fyz2_pages(main_stack);
|
||||
gtk_stack_add_named(main_stack, build_fyz3map_page(), "fyz3map");
|
||||
add_fyz3_pages(main_stack);
|
||||
gtk_stack_add_named(main_stack, build_fyz4map_page(), "fyz4map");
|
||||
add_fyz4_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);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ void load_progress(void) {
|
|||
on4_load_progress();
|
||||
lit_load_progress();
|
||||
sci_load_progress();
|
||||
fyz_load_progress();
|
||||
}
|
||||
|
||||
/* Redraw the exercise rails of every unit that already has a page. */
|
||||
|
|
|
|||
36
src/search.c
36
src/search.c
|
|
@ -23,7 +23,7 @@ static GPtrArray *search_items;
|
|||
|
||||
static gboolean subject_open(int i) {
|
||||
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
||||
|| i == ON_SUBJ || i == SCI_SUBJ;
|
||||
|| i == ON_SUBJ || i == PHY_SUBJ || i == SCI_SUBJ;
|
||||
}
|
||||
|
||||
static const char *subject_page(int i) {
|
||||
|
|
@ -37,6 +37,8 @@ static const char *subject_page(int i) {
|
|||
return "czechmap";
|
||||
if (i == ON_SUBJ)
|
||||
return "onyears";
|
||||
if (i == PHY_SUBJ)
|
||||
return "fyzyears";
|
||||
if (i == SCI_SUBJ)
|
||||
return "scimap";
|
||||
return "subjects";
|
||||
|
|
@ -273,6 +275,38 @@ static void catalog_rebuild(void) {
|
|||
g_snprintf(page, sizeof(page), "lit4ex%d", i);
|
||||
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||
}
|
||||
catalog_add_key("fyz_year1", "search_lesson", "fyzmap", FALSE, 1, "fyzika rocnik");
|
||||
catalog_add_key("fyz_year2", "search_lesson", "fyz2map", FALSE, 1, "fyzika rocnik");
|
||||
catalog_add_key("fyz_year3", "search_lesson", "fyz3map", FALSE, 1, "fyzika rocnik");
|
||||
catalog_add_key("fyz_year4", "search_lesson", "fyz4map", FALSE, 1, "fyzika rocnik");
|
||||
for (i = 1; i <= FYZ_N; i++) {
|
||||
g_snprintf(key, sizeof(key), "fyz_unit%d", i);
|
||||
g_snprintf(page, sizeof(page), "fyzunit%d", i);
|
||||
catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika");
|
||||
g_snprintf(page, sizeof(page), "fyzex%d", i);
|
||||
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||
}
|
||||
for (i = 1; i <= FYZ_N; i++) {
|
||||
g_snprintf(key, sizeof(key), "fyz2_unit%d", i);
|
||||
g_snprintf(page, sizeof(page), "fyz2unit%d", i);
|
||||
catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika");
|
||||
g_snprintf(page, sizeof(page), "fyz2ex%d", i);
|
||||
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||
}
|
||||
for (i = 1; i <= FYZ_N; i++) {
|
||||
g_snprintf(key, sizeof(key), "fyz3_unit%d", i);
|
||||
g_snprintf(page, sizeof(page), "fyz3unit%d", i);
|
||||
catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika");
|
||||
g_snprintf(page, sizeof(page), "fyz3ex%d", i);
|
||||
catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz");
|
||||
}
|
||||
for (i = 1; i <= FYZ_N; i++) {
|
||||
g_snprintf(key, sizeof(key), "fyz4_unit%d", i);
|
||||
g_snprintf(page, sizeof(page), "fyz4unit%d", i);
|
||||
catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika");
|
||||
g_snprintf(page, sizeof(page), "fyz4ex%d", i);
|
||||
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++) {
|
||||
|
|
|
|||
10
src/stats.c
10
src/stats.c
|
|
@ -77,6 +77,8 @@ void refresh_stats_ui(void) {
|
|||
}
|
||||
else if (s == SCI_SUBJ)
|
||||
progress_for_sci(&all);
|
||||
else if (s == PHY_SUBJ)
|
||||
progress_for_fyz(&all);
|
||||
else
|
||||
progress_for_units(sub_unit_start[s], sub_unit_count[s], &all);
|
||||
}
|
||||
|
|
@ -107,7 +109,8 @@ void refresh_stats_ui(void) {
|
|||
ProgressSum sp = {0};
|
||||
gboolean has_content = (s == NET_SUBJ) || (s == HW_SUBJ)
|
||||
|| (s == ON_SUBJ) || (s == CZ_SUBJ)
|
||||
|| (s == SCI_SUBJ) || sub_unit_count[s] > 0;
|
||||
|| (s == SCI_SUBJ) || (s == PHY_SUBJ)
|
||||
|| sub_unit_count[s] > 0;
|
||||
|
||||
if (!count || !bar)
|
||||
continue;
|
||||
|
|
@ -123,6 +126,8 @@ void refresh_stats_ui(void) {
|
|||
}
|
||||
else if (s == SCI_SUBJ)
|
||||
progress_for_sci(&sp);
|
||||
else if (s == PHY_SUBJ)
|
||||
progress_for_fyz(&sp);
|
||||
else
|
||||
progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp);
|
||||
if (has_content) {
|
||||
|
|
@ -393,7 +398,8 @@ GtkWidget *build_stats_page(void) {
|
|||
GtkWidget *bar;
|
||||
gboolean has_units = (s == NET_SUBJ) || (s == HW_SUBJ)
|
||||
|| (s == CZ_SUBJ) || (s == ON_SUBJ)
|
||||
|| (s == SCI_SUBJ) || sub_unit_count[s] > 0;
|
||||
|| (s == SCI_SUBJ) || (s == PHY_SUBJ)
|
||||
|| sub_unit_count[s] > 0;
|
||||
gboolean has_deutsch_units = sub_unit_count[s] > 0;
|
||||
|
||||
subject = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Index 0 (Deutsch), NET_SUBJ (networks), HW_SUBJ (hardware), CZ_SUBJ
|
||||
* (Czech), ON_SUBJ (civics) and SCI_SUBJ (natural sciences) are unlocked. */
|
||||
* (Czech), ON_SUBJ (civics), PHY_SUBJ (physics) and SCI_SUBJ
|
||||
* (natural sciences) are unlocked. */
|
||||
const char *sub_keys[NUM_SUBJECTS] = {
|
||||
"Deutsch",
|
||||
"Správa počítačových sítí",
|
||||
|
|
@ -154,7 +155,7 @@ void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr,
|
|||
|
||||
static gboolean subject_is_open(int i) {
|
||||
return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ
|
||||
|| i == ON_SUBJ || i == SCI_SUBJ;
|
||||
|| i == ON_SUBJ || i == PHY_SUBJ || i == SCI_SUBJ;
|
||||
}
|
||||
|
||||
static GtkWidget *subject_icon(int i) {
|
||||
|
|
@ -177,6 +178,9 @@ static GtkWidget *subject_icon(int i) {
|
|||
else if (i == ON_SUBJ)
|
||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
||||
draw_civics_icon, NULL, NULL);
|
||||
else if (i == PHY_SUBJ)
|
||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
||||
draw_physics_icon, NULL, NULL);
|
||||
else if (i == SCI_SUBJ)
|
||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area),
|
||||
draw_science_icon, NULL, NULL);
|
||||
|
|
@ -196,6 +200,8 @@ static const char *subject_target(int i) {
|
|||
return "czechmap";
|
||||
if (i == ON_SUBJ)
|
||||
return "onyears";
|
||||
if (i == PHY_SUBJ)
|
||||
return "fyzyears";
|
||||
if (i == SCI_SUBJ)
|
||||
return "scimap";
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -433,5 +433,6 @@ void apply_theme(void) {
|
|||
czech_rail_theme_reset();
|
||||
lit_rail_theme_reset();
|
||||
sci_rail_theme_reset();
|
||||
fyz_rail_theme_reset();
|
||||
book_rail_theme_reset();
|
||||
}
|
||||
|
|
|
|||
12
src/util.c
12
src/util.c
|
|
@ -32,6 +32,10 @@ char *app_progress_lit3;
|
|||
char *app_progress_lit4;
|
||||
char *app_progress_chem;
|
||||
char *app_progress_bio;
|
||||
char *app_progress_fyz;
|
||||
char *app_progress_fyz2;
|
||||
char *app_progress_fyz3;
|
||||
char *app_progress_fyz4;
|
||||
|
||||
static char *dup_dirname(const char *path) {
|
||||
char *tmp = g_strdup(path);
|
||||
|
|
@ -180,6 +184,10 @@ static void set_progress_paths(const char *write_root) {
|
|||
g_free(app_progress_lit4);
|
||||
g_free(app_progress_chem);
|
||||
g_free(app_progress_bio);
|
||||
g_free(app_progress_fyz);
|
||||
g_free(app_progress_fyz2);
|
||||
g_free(app_progress_fyz3);
|
||||
g_free(app_progress_fyz4);
|
||||
|
||||
app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL);
|
||||
app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL);
|
||||
|
|
@ -200,6 +208,10 @@ static void set_progress_paths(const char *write_root) {
|
|||
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);
|
||||
app_progress_fyz = g_build_filename(app_progress_dir, "fyz.conf", NULL);
|
||||
app_progress_fyz2 = g_build_filename(app_progress_dir, "fyz2.conf", NULL);
|
||||
app_progress_fyz3 = g_build_filename(app_progress_dir, "fyz3.conf", NULL);
|
||||
app_progress_fyz4 = g_build_filename(app_progress_dir, "fyz4.conf", NULL);
|
||||
}
|
||||
|
||||
/* Resolve read-only asset root, chdir there, and point progress at a writable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue