Open software as four years from Windows and Office to policy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-10-11 19:25:48 +02:00
commit 264f4a73d8
84 changed files with 3327 additions and 4 deletions

View file

@ -34,6 +34,8 @@ 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.SwQuizScreen
import org.maturita.maturita.ui.SwYearsScreen
import org.maturita.maturita.ui.TgQuizScreen
import org.maturita.maturita.ui.TgYearsScreen
import org.maturita.maturita.ui.MathPracticeScreen
@ -645,6 +647,63 @@ private fun MaturitaAppBody(vm: AppViewModel) {
}
}
is Route.Pg4Ex -> PgQuizScreen(vm, 4, r.id)
Route.SwYears -> SwYearsScreen(vm)
Route.SwMap -> LessonListScreen(
vm, vm.tr("sw_year1"), vm.tr("sw_sub"),
vm.content.sw.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.swDone(id), Route.SwLesson(id))
},
)
is Route.SwLesson -> {
val l = vm.content.swLesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.SwEx(r.id))
}
}
is Route.SwEx -> SwQuizScreen(vm, 1, r.id)
Route.Sw2Map -> LessonListScreen(
vm, vm.tr("sw_year2"), vm.tr("sw2_sub"),
vm.content.sw2.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.sw2Done(id), Route.Sw2Lesson(id))
},
)
is Route.Sw2Lesson -> {
val l = vm.content.sw2Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Sw2Ex(r.id))
}
}
is Route.Sw2Ex -> SwQuizScreen(vm, 2, r.id)
Route.Sw3Map -> LessonListScreen(
vm, vm.tr("sw_year3"), vm.tr("sw3_sub"),
vm.content.sw3.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.sw3Done(id), Route.Sw3Lesson(id))
},
)
is Route.Sw3Lesson -> {
val l = vm.content.sw3Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Sw3Ex(r.id))
}
}
is Route.Sw3Ex -> SwQuizScreen(vm, 3, r.id)
Route.Sw4Map -> LessonListScreen(
vm, vm.tr("sw_year4"), vm.tr("sw4_sub"),
vm.content.sw4.map { l ->
val id = l.int("id")
LessonRow(vm.tr(l.str("titleKey")), vm.progress.sw4Done(id), Route.Sw4Lesson(id))
},
)
is Route.Sw4Lesson -> {
val l = vm.content.sw4Lesson(r.id)
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
vm.replace(Route.Sw4Ex(r.id))
}
}
is Route.Sw4Ex -> SwQuizScreen(vm, 4, r.id)
Route.CsYears -> CsYearsScreen(vm)
Route.CsMap -> LessonListScreen(
vm, vm.tr("cs_year1"), vm.tr("cs_sub"),

View file

@ -282,6 +282,26 @@ class AppViewModel(val content: Content, val platform: Platform) {
refresh()
}
fun markSw(id: Int) {
progress.markSw(id)
refresh()
}
fun markSw2(id: Int) {
progress.markSw2(id)
refresh()
}
fun markSw3(id: Int) {
progress.markSw3(id)
refresh()
}
fun markSw4(id: Int) {
progress.markSw4(id)
refresh()
}
fun markCs(id: Int) {
progress.markCs(id)
refresh()

View file

@ -131,6 +131,19 @@ sealed class Route(val page: String) {
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 SwYears : Route("swyears")
data object SwMap : Route("swmap")
data class SwLesson(val id: Int) : Route("swunit$id")
data class SwEx(val id: Int) : Route("swex$id")
data object Sw2Map : Route("sw2map")
data class Sw2Lesson(val id: Int) : Route("sw2unit$id")
data class Sw2Ex(val id: Int) : Route("sw2ex$id")
data object Sw3Map : Route("sw3map")
data class Sw3Lesson(val id: Int) : Route("sw3unit$id")
data class Sw3Ex(val id: Int) : Route("sw3ex$id")
data object Sw4Map : Route("sw4map")
data class Sw4Lesson(val id: Int) : Route("sw4unit$id")
data class Sw4Ex(val id: Int) : Route("sw4ex$id")
data object CsYears : Route("csyears")
data object CsMap : Route("csmap")
data class CsLesson(val id: Int) : Route("csunit$id")
@ -298,6 +311,19 @@ sealed class Route(val page: String) {
Pg4Map -> listOf(Subjects, PgYears, Pg4Map)
is Pg4Lesson -> listOf(Subjects, PgYears, Pg4Map, this)
is Pg4Ex -> listOf(Subjects, PgYears, Pg4Map, Pg4Lesson(id), this)
SwYears -> listOf(Subjects, SwYears)
SwMap -> listOf(Subjects, SwYears, SwMap)
is SwLesson -> listOf(Subjects, SwYears, SwMap, this)
is SwEx -> listOf(Subjects, SwYears, SwMap, SwLesson(id), this)
Sw2Map -> listOf(Subjects, SwYears, Sw2Map)
is Sw2Lesson -> listOf(Subjects, SwYears, Sw2Map, this)
is Sw2Ex -> listOf(Subjects, SwYears, Sw2Map, Sw2Lesson(id), this)
Sw3Map -> listOf(Subjects, SwYears, Sw3Map)
is Sw3Lesson -> listOf(Subjects, SwYears, Sw3Map, this)
is Sw3Ex -> listOf(Subjects, SwYears, Sw3Map, Sw3Lesson(id), this)
Sw4Map -> listOf(Subjects, SwYears, Sw4Map)
is Sw4Lesson -> listOf(Subjects, SwYears, Sw4Map, this)
is Sw4Ex -> listOf(Subjects, SwYears, Sw4Map, Sw4Lesson(id), this)
CsYears -> listOf(Subjects, CsYears)
CsMap -> listOf(Subjects, CsYears, CsMap)
is CsLesson -> listOf(Subjects, CsYears, CsMap, this)
@ -369,6 +395,11 @@ fun routeFromPage(page: String): Route? = when (page) {
"pg2map" -> Route.Pg2Map
"pg3map" -> Route.Pg3Map
"pg4map" -> Route.Pg4Map
"swyears" -> Route.SwYears
"swmap" -> Route.SwMap
"sw2map" -> Route.Sw2Map
"sw3map" -> Route.Sw3Map
"sw4map" -> Route.Sw4Map
"csyears" -> Route.CsYears
"csmap" -> Route.CsMap
"cs2map" -> Route.Cs2Map
@ -519,6 +550,30 @@ fun routeFromPage(page: String): Route? = when (page) {
Regex("""pgex(\d+)""").matchEntire(page)?.let {
return Route.PgEx(it.groupValues[1].toInt())
}
Regex("""sw4unit(\d+)""").matchEntire(page)?.let {
return Route.Sw4Lesson(it.groupValues[1].toInt())
}
Regex("""sw4ex(\d+)""").matchEntire(page)?.let {
return Route.Sw4Ex(it.groupValues[1].toInt())
}
Regex("""sw3unit(\d+)""").matchEntire(page)?.let {
return Route.Sw3Lesson(it.groupValues[1].toInt())
}
Regex("""sw3ex(\d+)""").matchEntire(page)?.let {
return Route.Sw3Ex(it.groupValues[1].toInt())
}
Regex("""sw2unit(\d+)""").matchEntire(page)?.let {
return Route.Sw2Lesson(it.groupValues[1].toInt())
}
Regex("""sw2ex(\d+)""").matchEntire(page)?.let {
return Route.Sw2Ex(it.groupValues[1].toInt())
}
Regex("""swunit(\d+)""").matchEntire(page)?.let {
return Route.SwLesson(it.groupValues[1].toInt())
}
Regex("""swex(\d+)""").matchEntire(page)?.let {
return Route.SwEx(it.groupValues[1].toInt())
}
Regex("""cs4unit(\d+)""").matchEntire(page)?.let {
return Route.Cs4Lesson(it.groupValues[1].toInt())
}

View file

@ -64,6 +64,10 @@ class Content(root: JSONObject) {
val pg2 = raw.arr("pg2")
val pg3 = raw.arr("pg3")
val pg4 = raw.arr("pg4")
val sw = raw.arr("sw")
val sw2 = raw.arr("sw2")
val sw3 = raw.arr("sw3")
val sw4 = raw.arr("sw4")
val cs = raw.arr("cs")
val cs2 = raw.arr("cs2")
val cs3 = raw.arr("cs3")
@ -128,6 +132,10 @@ class Content(root: JSONObject) {
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 swLesson(id: Int) = sw.firstOrNull { it.int("id") == id }
fun sw2Lesson(id: Int) = sw2.firstOrNull { it.int("id") == id }
fun sw3Lesson(id: Int) = sw3.firstOrNull { it.int("id") == id }
fun sw4Lesson(id: Int) = sw4.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

@ -107,6 +107,14 @@ class ProgressStore(private val prefs: Prefs, content: Content) {
fun markPg3(id: Int) { mark("pg3.$id") }
fun pg4Done(id: Int) = done("pg4.$id")
fun markPg4(id: Int) { mark("pg4.$id") }
fun swDone(id: Int) = done("sw.$id")
fun markSw(id: Int) { mark("sw.$id") }
fun sw2Done(id: Int) = done("sw2.$id")
fun markSw2(id: Int) { mark("sw2.$id") }
fun sw3Done(id: Int) = done("sw3.$id")
fun markSw3(id: Int) { mark("sw3.$id") }
fun sw4Done(id: Int) = done("sw4.$id")
fun markSw4(id: Int) { mark("sw4.$id") }
fun csDone(id: Int) = done("cs.$id")
fun markCs(id: Int) { mark("cs.$id") }
fun cs2Done(id: Int) = done("cs2.$id")
@ -368,6 +376,38 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
sum.doneUnits += 1
}
}
content.sw.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.swDone(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.sw2.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.sw2Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.sw3.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.sw3Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.sw4.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1
if (p.sw4Done(l.int("id"))) {
sum.doneEx += 1
sum.doneUnits += 1
}
}
content.cs.forEach { l ->
sum.totalEx += 1
sum.openUnits += 1

View file

@ -1130,6 +1130,30 @@ fun PgQuizScreen(vm: AppViewModel, year: Int, id: Int) {
}
}
@Composable
fun SwQuizScreen(vm: AppViewModel, year: Int, id: Int) {
val lesson = when (year) {
2 -> vm.content.sw2Lesson(id)
3 -> vm.content.sw3Lesson(id)
4 -> vm.content.sw4Lesson(id)
else -> vm.content.swLesson(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.markSw2(id)
3 -> vm.markSw3(id)
4 -> vm.markSw4(id)
else -> vm.markSw(id)
}
}
}
@Composable
fun FyzQuizScreen(vm: AppViewModel, year: Int, id: Int) {
val lesson = when (year) {

View file

@ -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.Apps
import androidx.compose.material.icons.filled.Architecture
import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.filled.AutoStories
@ -248,6 +249,7 @@ private fun SubjectIcon(icon: String, open: Boolean) {
"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))
"apps" -> Icon(Icons.Filled.Apps, null, tint = tint, modifier = Modifier.size(26.dp))
else -> Icon(Icons.Filled.Lock, null, tint = tint)
}
}
@ -369,6 +371,10 @@ fun routeProgress(vm: AppViewModel, r: Route): Pair<Int, Int>? {
Route.Pg2Map -> tally(c.pg2, p::pg2Done)
Route.Pg3Map -> tally(c.pg3, p::pg3Done)
Route.Pg4Map -> tally(c.pg4, p::pg4Done)
Route.SwMap -> tally(c.sw, p::swDone)
Route.Sw2Map -> tally(c.sw2, p::sw2Done)
Route.Sw3Map -> tally(c.sw3, p::sw3Done)
Route.Sw4Map -> tally(c.sw4, p::sw4Done)
Route.CsMap -> tally(c.cs, p::csDone)
Route.Cs2Map -> tally(c.cs2, p::cs2Done)
Route.Cs3Map -> tally(c.cs3, p::cs3Done)
@ -457,6 +463,13 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
vm.content.pg3.count { vm.progress.pg3Done(it.int("id")) } +
vm.content.pg4.count { vm.progress.pg4Done(it.int("id")) }
}
"swyears", "swmap", "sw2map", "sw3map", "sw4map" -> {
sum.totalEx = vm.content.sw.size + vm.content.sw2.size + vm.content.sw3.size + vm.content.sw4.size
sum.doneEx = vm.content.sw.count { vm.progress.swDone(it.int("id")) } +
vm.content.sw2.count { vm.progress.sw2Done(it.int("id")) } +
vm.content.sw3.count { vm.progress.sw3Done(it.int("id")) } +
vm.content.sw4.count { vm.progress.sw4Done(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")) } +
@ -758,6 +771,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("Programové vybavení"), vm.tr("search_lesson"), "swyears", extra = "office windows excel mysql")
add(vm.tr("sw_year1"), vm.tr("search_lesson"), "swmap", extra = "rocnik")
add(vm.tr("sw_year2"), vm.tr("search_lesson"), "sw2map", extra = "rocnik")
add(vm.tr("sw_year3"), vm.tr("search_lesson"), "sw3map", extra = "rocnik")
add(vm.tr("sw_year4"), vm.tr("search_lesson"), "sw4map", extra = "rocnik")
vm.content.sw.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "swunit${l.int("id")}", extra = "windows")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "swex${l.int("id")}")
}
vm.content.sw2.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "sw2unit${l.int("id")}", extra = "word excel")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "sw2ex${l.int("id")}")
}
vm.content.sw3.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "sw3unit${l.int("id")}", extra = "access mysql")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "sw3ex${l.int("id")}")
}
vm.content.sw4.forEach { l ->
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "sw4unit${l.int("id")}", extra = "wordpress")
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "sw4ex${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")
@ -1032,6 +1066,20 @@ fun CsYearsScreen(vm: AppViewModel) {
}
}
@Composable
fun SwYearsScreen(vm: AppViewModel) {
DetailScaffold(vm, vm.tr("Programové vybavení"), vm.tr("sw_years_sub")) { inner ->
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
item {
NavRow(title = vm.tr("sw_year1"), subtitle = vm.tr("sw_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.SwMap)) { vm.go(Route.SwMap) }
NavRow(title = vm.tr("sw_year2"), subtitle = vm.tr("sw2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Sw2Map)) { vm.go(Route.Sw2Map) }
NavRow(title = vm.tr("sw_year3"), subtitle = vm.tr("sw3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Sw3Map)) { vm.go(Route.Sw3Map) }
NavRow(title = vm.tr("sw_year4"), subtitle = vm.tr("sw4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Sw4Map)) { vm.go(Route.Sw4Map) }
}
}
}
}
@Composable
fun PgYearsScreen(vm: AppViewModel) {
DetailScaffold(vm, vm.tr("Prezentační grafika"), vm.tr("pg_years_sub")) { inner ->