Open presentation graphics as four years from Photoshop to the exam campaign.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-10-11 18:12:17 +02:00
commit ec7aa63159
84 changed files with 3328 additions and 4 deletions

View file

@ -32,6 +32,8 @@ 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.PgQuizScreen
import org.maturita.maturita.ui.PgYearsScreen
import org.maturita.maturita.ui.TgQuizScreen
import org.maturita.maturita.ui.TgYearsScreen
import org.maturita.maturita.ui.MathPracticeScreen
@ -586,6 +588,63 @@ private fun MaturitaAppBody(vm: AppViewModel) {
}
}
is Route.Tg4Ex -> TgQuizScreen(vm, 4, r.id)
Route.PgYears -> PgYearsScreen(vm)
Route.PgMap -> LessonListScreen(
vm, vm.tr("pg_year1"), vm.tr("pg_sub"),
vm.content.pg.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.pgDone(id), Route.PgLesson(id))
},
)
is Route.PgLesson -> {
val l = vm.content.pgLesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.PgEx(r.id))
}
}
is Route.PgEx -> PgQuizScreen(vm, 1, r.id)
Route.Pg2Map -> LessonListScreen(
vm, vm.tr("pg_year2"), vm.tr("pg2_sub"),
vm.content.pg2.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.pg2Done(id), Route.Pg2Lesson(id))
},
)
is Route.Pg2Lesson -> {
val l = vm.content.pg2Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Pg2Ex(r.id))
}
}
is Route.Pg2Ex -> PgQuizScreen(vm, 2, r.id)
Route.Pg3Map -> LessonListScreen(
vm, vm.tr("pg_year3"), vm.tr("pg3_sub"),
vm.content.pg3.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.pg3Done(id), Route.Pg3Lesson(id))
},
)
is Route.Pg3Lesson -> {
val l = vm.content.pg3Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Pg3Ex(r.id))
}
}
is Route.Pg3Ex -> PgQuizScreen(vm, 3, r.id)
Route.Pg4Map -> LessonListScreen(
vm, vm.tr("pg_year4"), vm.tr("pg4_sub"),
vm.content.pg4.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.pg4Done(id), Route.Pg4Lesson(id))
},
)
is Route.Pg4Lesson -> {
val l = vm.content.pg4Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Pg4Ex(r.id))
}
}
is Route.Pg4Ex -> PgQuizScreen(vm, 4, r.id)
Route.CsYears -> CsYearsScreen(vm)
Route.CsMap -> LessonListScreen(
vm, vm.tr("cs_year1"), vm.tr("cs_sub"),

View file

@ -262,6 +262,26 @@ class AppViewModel(val content: Content, val platform: Platform) {
refresh()
}
fun markPg(id: Int) {
progress.markPg(id)
refresh()
}
fun markPg2(id: Int) {
progress.markPg2(id)
refresh()
}
fun markPg3(id: Int) {
progress.markPg3(id)
refresh()
}
fun markPg4(id: Int) {
progress.markPg4(id)
refresh()
}
fun markCs(id: Int) {
progress.markCs(id)
refresh()

View file

@ -118,6 +118,19 @@ sealed class Route(val page: String) {
data object Tg4Map : Route("tg4map")
data class Tg4Lesson(val id: Int) : Route("tg4unit$id")
data class Tg4Ex(val id: Int) : Route("tg4ex$id")
data object PgYears : Route("pgyears")
data object PgMap : Route("pgmap")
data class PgLesson(val id: Int) : Route("pgunit$id")
data class PgEx(val id: Int) : Route("pgex$id")
data object Pg2Map : Route("pg2map")
data class Pg2Lesson(val id: Int) : Route("pg2unit$id")
data class Pg2Ex(val id: Int) : Route("pg2ex$id")
data object Pg3Map : Route("pg3map")
data class Pg3Lesson(val id: Int) : Route("pg3unit$id")
data class Pg3Ex(val id: Int) : Route("pg3ex$id")
data object Pg4Map : Route("pg4map")
data class Pg4Lesson(val id: Int) : Route("pg4unit$id")
data class Pg4Ex(val id: Int) : Route("pg4ex$id")
data object CsYears : Route("csyears")
data object CsMap : Route("csmap")
data class CsLesson(val id: Int) : Route("csunit$id")
@ -272,6 +285,19 @@ sealed class Route(val page: String) {
Tg4Map -> listOf(Subjects, TgYears, Tg4Map)
is Tg4Lesson -> listOf(Subjects, TgYears, Tg4Map, this)
is Tg4Ex -> listOf(Subjects, TgYears, Tg4Map, Tg4Lesson(id), this)
PgYears -> listOf(Subjects, PgYears)
PgMap -> listOf(Subjects, PgYears, PgMap)
is PgLesson -> listOf(Subjects, PgYears, PgMap, this)
is PgEx -> listOf(Subjects, PgYears, PgMap, PgLesson(id), this)
Pg2Map -> listOf(Subjects, PgYears, Pg2Map)
is Pg2Lesson -> listOf(Subjects, PgYears, Pg2Map, this)
is Pg2Ex -> listOf(Subjects, PgYears, Pg2Map, Pg2Lesson(id), this)
Pg3Map -> listOf(Subjects, PgYears, Pg3Map)
is Pg3Lesson -> listOf(Subjects, PgYears, Pg3Map, this)
is Pg3Ex -> listOf(Subjects, PgYears, Pg3Map, Pg3Lesson(id), this)
Pg4Map -> listOf(Subjects, PgYears, Pg4Map)
is Pg4Lesson -> listOf(Subjects, PgYears, Pg4Map, this)
is Pg4Ex -> listOf(Subjects, PgYears, Pg4Map, Pg4Lesson(id), this)
CsYears -> listOf(Subjects, CsYears)
CsMap -> listOf(Subjects, CsYears, CsMap)
is CsLesson -> listOf(Subjects, CsYears, CsMap, this)
@ -338,6 +364,11 @@ fun routeFromPage(page: String): Route? = when (page) {
"tg2map" -> Route.Tg2Map
"tg3map" -> Route.Tg3Map
"tg4map" -> Route.Tg4Map
"pgyears" -> Route.PgYears
"pgmap" -> Route.PgMap
"pg2map" -> Route.Pg2Map
"pg3map" -> Route.Pg3Map
"pg4map" -> Route.Pg4Map
"csyears" -> Route.CsYears
"csmap" -> Route.CsMap
"cs2map" -> Route.Cs2Map
@ -464,6 +495,30 @@ fun routeFromPage(page: String): Route? = when (page) {
Regex("""tgex(\d+)""").matchEntire(page)?.let {
return Route.TgEx(it.groupValues[1].toInt())
}
Regex("""pg4unit(\d+)""").matchEntire(page)?.let {
return Route.Pg4Lesson(it.groupValues[1].toInt())
}
Regex("""pg4ex(\d+)""").matchEntire(page)?.let {
return Route.Pg4Ex(it.groupValues[1].toInt())
}
Regex("""pg3unit(\d+)""").matchEntire(page)?.let {
return Route.Pg3Lesson(it.groupValues[1].toInt())
}
Regex("""pg3ex(\d+)""").matchEntire(page)?.let {
return Route.Pg3Ex(it.groupValues[1].toInt())
}
Regex("""pg2unit(\d+)""").matchEntire(page)?.let {
return Route.Pg2Lesson(it.groupValues[1].toInt())
}
Regex("""pg2ex(\d+)""").matchEntire(page)?.let {
return Route.Pg2Ex(it.groupValues[1].toInt())
}
Regex("""pgunit(\d+)""").matchEntire(page)?.let {
return Route.PgLesson(it.groupValues[1].toInt())
}
Regex("""pgex(\d+)""").matchEntire(page)?.let {
return Route.PgEx(it.groupValues[1].toInt())
}
Regex("""cs4unit(\d+)""").matchEntire(page)?.let {
return Route.Cs4Lesson(it.groupValues[1].toInt())
}

View file

@ -60,6 +60,10 @@ class Content(root: JSONObject) {
val tg2 = raw.arr("tg2")
val tg3 = raw.arr("tg3")
val tg4 = raw.arr("tg4")
val pg = raw.arr("pg")
val pg2 = raw.arr("pg2")
val pg3 = raw.arr("pg3")
val pg4 = raw.arr("pg4")
val cs = raw.arr("cs")
val cs2 = raw.arr("cs2")
val cs3 = raw.arr("cs3")
@ -120,6 +124,10 @@ class Content(root: JSONObject) {
fun tg2Lesson(id: Int) = tg2.firstOrNull { it.int("id") == id }
fun tg3Lesson(id: Int) = tg3.firstOrNull { it.int("id") == id }
fun tg4Lesson(id: Int) = tg4.firstOrNull { it.int("id") == id }
fun pgLesson(id: Int) = pg.firstOrNull { it.int("id") == id }
fun pg2Lesson(id: Int) = pg2.firstOrNull { it.int("id") == id }
fun pg3Lesson(id: Int) = pg3.firstOrNull { it.int("id") == id }
fun pg4Lesson(id: Int) = pg4.firstOrNull { it.int("id") == id }
fun csLesson(id: Int) = cs.firstOrNull { it.int("id") == id }
fun cs2Lesson(id: Int) = cs2.firstOrNull { it.int("id") == id }
fun cs3Lesson(id: Int) = cs3.firstOrNull { it.int("id") == id }

View file

@ -99,6 +99,14 @@ class ProgressStore(private val prefs: Prefs, content: Content) {
fun markTg3(id: Int) { mark("tg3.$id") }
fun tg4Done(id: Int) = done("tg4.$id")
fun markTg4(id: Int) { mark("tg4.$id") }
fun pgDone(id: Int) = done("pg.$id")
fun markPg(id: Int) { mark("pg.$id") }
fun pg2Done(id: Int) = done("pg2.$id")
fun markPg2(id: Int) { mark("pg2.$id") }
fun pg3Done(id: Int) = done("pg3.$id")
fun markPg3(id: Int) { mark("pg3.$id") }
fun pg4Done(id: Int) = done("pg4.$id")
fun markPg4(id: Int) { mark("pg4.$id") }
fun csDone(id: Int) = done("cs.$id")
fun markCs(id: Int) { mark("cs.$id") }
fun cs2Done(id: Int) = done("cs2.$id")
@ -328,6 +336,38 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
sum.doneUnits += 1
}
}
content.pg.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.pgDone(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.pg2.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.pg2Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.pg3.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.pg3Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.pg4.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.pg4Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.cs.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1

View file

@ -1106,6 +1106,30 @@ fun TgQuizScreen(vm: AppViewModel, year: Int, id: Int) {
}
}
@Composable
fun PgQuizScreen(vm: AppViewModel, year: Int, id: Int) {
val lesson = when (year) {
2 -> vm.content.pg2Lesson(id)
3 -> vm.content.pg3Lesson(id)
4 -> vm.content.pg4Lesson(id)
else -> vm.content.pgLesson(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.markPg2(id)
3 -> vm.markPg3(id)
4 -> vm.markPg4(id)
else -> vm.markPg(id)
}
}
}
@Composable
fun FyzQuizScreen(vm: AppViewModel, year: Int, id: Int) {
val lesson = when (year) {

View file

@ -29,6 +29,7 @@ import androidx.compose.material.icons.filled.Architecture
import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.filled.AutoStories
import androidx.compose.material.icons.filled.Bolt
import androidx.compose.material.icons.filled.Brush
import androidx.compose.material.icons.filled.Eco
import androidx.compose.material.icons.filled.Functions
import androidx.compose.material.icons.filled.Check
@ -246,6 +247,7 @@ private fun SubjectIcon(icon: String, open: Boolean) {
"function" -> Icon(Icons.Filled.Functions, null, tint = tint, modifier = Modifier.size(26.dp))
"ruler" -> Icon(Icons.Filled.Architecture, null, tint = tint, modifier = Modifier.size(26.dp))
"code" -> Icon(Icons.Filled.Terminal, null, tint = tint, modifier = Modifier.size(26.dp))
"brush" -> Icon(Icons.Filled.Brush, null, tint = tint, modifier = Modifier.size(26.dp))
else -> Icon(Icons.Filled.Lock, null, tint = tint)
}
}
@ -363,6 +365,10 @@ fun routeProgress(vm: AppViewModel, r: Route): Pair<Int, Int>? {
Route.Tg2Map -> tally(c.tg2, p::tg2Done)
Route.Tg3Map -> tally(c.tg3, p::tg3Done)
Route.Tg4Map -> tally(c.tg4, p::tg4Done)
Route.PgMap -> tally(c.pg, p::pgDone)
Route.Pg2Map -> tally(c.pg2, p::pg2Done)
Route.Pg3Map -> tally(c.pg3, p::pg3Done)
Route.Pg4Map -> tally(c.pg4, p::pg4Done)
Route.CsMap -> tally(c.cs, p::csDone)
Route.Cs2Map -> tally(c.cs2, p::cs2Done)
Route.Cs3Map -> tally(c.cs3, p::cs3Done)
@ -444,6 +450,13 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
vm.content.tg3.count { vm.progress.tg3Done(it.int("id")) } +
vm.content.tg4.count { vm.progress.tg4Done(it.int("id")) }
}
"pgyears", "pgmap", "pg2map", "pg3map", "pg4map" -> {
sum.totalEx = vm.content.pg.size + vm.content.pg2.size + vm.content.pg3.size + vm.content.pg4.size
sum.doneEx = vm.content.pg.count { vm.progress.pgDone(it.int("id")) } +
vm.content.pg2.count { vm.progress.pg2Done(it.int("id")) } +
vm.content.pg3.count { vm.progress.pg3Done(it.int("id")) } +
vm.content.pg4.count { vm.progress.pg4Done(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")) } +
@ -745,6 +758,27 @@ private fun buildSearch(vm: AppViewModel): List<Hit> {
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("Prezentační grafika"), vm.tr("search_lesson"), "pgyears", extra = "photoshop premiere illustrator")
add(vm.tr("pg_year1"), vm.tr("search_lesson"), "pgmap", extra = "rocnik")
add(vm.tr("pg_year2"), vm.tr("search_lesson"), "pg2map", extra = "rocnik")
add(vm.tr("pg_year3"), vm.tr("search_lesson"), "pg3map", extra = "rocnik")
add(vm.tr("pg_year4"), vm.tr("search_lesson"), "pg4map", extra = "rocnik")
vm.content.pg.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "pgunit${l.int("id")}", extra = "photoshop")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "pgex${l.int("id")}")
}
vm.content.pg2.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "pg2unit${l.int("id")}", extra = "photoshop")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "pg2ex${l.int("id")}")
}
vm.content.pg3.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "pg3unit${l.int("id")}", extra = "premiere")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "pg3ex${l.int("id")}")
}
vm.content.pg4.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "pg4unit${l.int("id")}", extra = "illustrator")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "pg4ex${l.int("id")}")
}
add(vm.tr("Technická grafika"), vm.tr("search_lesson"), "tgyears", extra = "autocad grafika")
add(vm.tr("tg_year1"), vm.tr("search_lesson"), "tgmap", extra = "rocnik")
add(vm.tr("tg_year2"), vm.tr("search_lesson"), "tg2map", extra = "rocnik")
@ -998,6 +1032,20 @@ fun CsYearsScreen(vm: AppViewModel) {
}
}
@Composable
fun PgYearsScreen(vm: AppViewModel) {
DetailScaffold(vm, vm.tr("Prezentační grafika"), vm.tr("pg_years_sub")) { inner ->
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
item {
NavRow(title = vm.tr("pg_year1"), subtitle = vm.tr("pg_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.PgMap)) { vm.go(Route.PgMap) }
NavRow(title = vm.tr("pg_year2"), subtitle = vm.tr("pg2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Pg2Map)) { vm.go(Route.Pg2Map) }
NavRow(title = vm.tr("pg_year3"), subtitle = vm.tr("pg3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Pg3Map)) { vm.go(Route.Pg3Map) }
NavRow(title = vm.tr("pg_year4"), subtitle = vm.tr("pg4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Pg4Map)) { vm.go(Route.Pg4Map) }
}
}
}
}
@Composable
fun TgYearsScreen(vm: AppViewModel) {
DetailScaffold(vm, vm.tr("Technická grafika"), vm.tr("tg_years_sub")) { inner ->