mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Add four years of German listening, reading and writing beside the textbook.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3b4e7b283a
commit
b822c57875
31 changed files with 3589 additions and 102 deletions
|
|
@ -151,6 +151,11 @@ class AppViewModel(app: Application) : AndroidViewModel(app) {
|
|||
refresh()
|
||||
}
|
||||
|
||||
fun markDe(year: Int, id: Int) {
|
||||
progress.markDe(year, id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markLit(id: Int) {
|
||||
progress.markLit(id)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.maturita.maturita
|
||||
|
||||
import android.os.Bundle
|
||||
import java.util.Locale
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
|
|
@ -50,6 +51,7 @@ import org.maturita.maturita.ui.On4QuizScreen
|
|||
import org.maturita.maturita.ui.OnQuizScreen
|
||||
import org.maturita.maturita.ui.OnYearsScreen
|
||||
import org.maturita.maturita.ui.EnYearsScreen
|
||||
import org.maturita.maturita.ui.DeHomeScreen
|
||||
import org.maturita.maturita.ui.EngExScreen
|
||||
import org.maturita.maturita.ui.PlotScreen
|
||||
import org.maturita.maturita.ui.RoadmapScreen
|
||||
|
|
@ -206,6 +208,23 @@ private fun MaturitaAppBody(vm: AppViewModel) {
|
|||
Route.Welcome, Route.Subjects -> HomeScreen(vm)
|
||||
Route.Stats -> StatsScreen(vm)
|
||||
Route.Settings -> SettingsScreen(vm)
|
||||
Route.DeHome -> DeHomeScreen(vm)
|
||||
is Route.DeMap -> LessonListScreen(
|
||||
vm, vm.tr("de_year${r.year}"), vm.tr("de_y${r.year}_sub"),
|
||||
vm.content.deYear(r.year).map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.deDone(r.year, id), Route.DeLesson(r.year, id))
|
||||
},
|
||||
)
|
||||
is Route.DeLesson -> {
|
||||
val l = vm.content.deLesson(r.year, r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.DeEx(r.year, r.id))
|
||||
}
|
||||
}
|
||||
is Route.DeEx -> EngExScreen(
|
||||
vm, r.year, r.id, Locale.GERMANY, vm.content.deLesson(r.year, r.id),
|
||||
) { vm.markDe(r.year, r.id) }
|
||||
Route.Roadmap -> RoadmapScreen(vm)
|
||||
is Route.UnitMap -> UnitMapScreen(vm, r.unitId)
|
||||
is Route.GermanEx -> GermanExercise(vm, r.unitId, r.ex)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ sealed class Route(val page: String) {
|
|||
data object Stats : Route("stats")
|
||||
data object Settings : Route("settings")
|
||||
data object Roadmap : Route("roadmap")
|
||||
data object DeHome : Route("dehome")
|
||||
data class DeMap(val year: Int) : Route("de${year}map")
|
||||
data class DeLesson(val year: Int, val id: Int) : Route("de${year}unit$id")
|
||||
data class DeEx(val year: Int, val id: Int) : Route("de${year}ex$id")
|
||||
data class UnitMap(val unitId: Int) : Route("unit${unitId + 1}")
|
||||
data class GermanEx(val unitId: Int, val ex: Int) : Route("u${unitId + 1}e$ex")
|
||||
data class Vocab(val unitId: Int) : Route("u${unitId + 1}vocab")
|
||||
|
|
@ -97,7 +101,7 @@ sealed class Route(val page: String) {
|
|||
/** Screens with their own bottom action bar; the navigation bar stays hidden there. */
|
||||
val isExercise: Boolean
|
||||
get() = this is GermanEx || this is Vocab || this is NetEx || this is HwEx ||
|
||||
this is OnEx || this is On2Ex || this is On3Ex || this is On4Ex || this is EnLesson || this is EnEx || this is MluvEx || this is BookQuiz || this is BookPlot ||
|
||||
this is OnEx || this is On2Ex || this is On3Ex || this is On4Ex || this is EnLesson || this is EnEx || this is DeLesson || this is DeEx || this is MluvEx || this is BookQuiz || this is BookPlot ||
|
||||
this is NetLesson || this is HwLesson || this is OnLesson || this is On2Lesson || this is On3Lesson || this is On4Lesson ||
|
||||
this is LitLesson || this is LitEx || this is Lit2Lesson || this is Lit2Ex ||
|
||||
this is Lit3Lesson || this is Lit3Ex || this is Lit4Lesson || this is Lit4Ex ||
|
||||
|
|
@ -113,10 +117,14 @@ sealed class Route(val page: String) {
|
|||
Welcome, Subjects -> listOf(Subjects)
|
||||
Stats -> listOf(Stats)
|
||||
Settings -> listOf(Settings)
|
||||
Roadmap -> listOf(Subjects, Roadmap)
|
||||
is UnitMap -> listOf(Subjects, Roadmap, this)
|
||||
is GermanEx -> listOf(Subjects, Roadmap, UnitMap(unitId), this)
|
||||
is Vocab -> listOf(Subjects, Roadmap, UnitMap(unitId), this)
|
||||
DeHome -> listOf(Subjects, DeHome)
|
||||
is DeMap -> listOf(Subjects, DeHome, this)
|
||||
is DeLesson -> listOf(Subjects, DeHome, DeMap(year), this)
|
||||
is DeEx -> listOf(Subjects, DeHome, DeMap(year), DeLesson(year, id), this)
|
||||
Roadmap -> listOf(Subjects, DeHome, Roadmap)
|
||||
is UnitMap -> listOf(Subjects, DeHome, Roadmap, this)
|
||||
is GermanEx -> listOf(Subjects, DeHome, Roadmap, UnitMap(unitId), this)
|
||||
is Vocab -> listOf(Subjects, DeHome, Roadmap, UnitMap(unitId), this)
|
||||
NetYears -> listOf(Subjects, NetYears)
|
||||
NetMap -> listOf(Subjects, NetYears, NetMap)
|
||||
is NetLesson -> listOf(Subjects, NetYears, NetMap, this)
|
||||
|
|
@ -207,6 +215,7 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
"stats" -> Route.Stats
|
||||
"settings" -> Route.Settings
|
||||
"roadmap" -> Route.Roadmap
|
||||
"dehome" -> Route.DeHome
|
||||
"netyears" -> Route.NetYears
|
||||
"netmap" -> Route.NetMap
|
||||
"hwyears" -> Route.HwYears
|
||||
|
|
@ -357,6 +366,15 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
Regex("""litex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.LitEx(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""de(\d)map""").matchEntire(page)?.let {
|
||||
return Route.DeMap(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""de(\d)unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.DeLesson(it.groupValues[1].toInt(), it.groupValues[2].toInt())
|
||||
}
|
||||
Regex("""de(\d)ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.DeEx(it.groupValues[1].toInt(), it.groupValues[2].toInt())
|
||||
}
|
||||
Regex("""en(\d)map""").matchEntire(page)?.let {
|
||||
return Route.EnMap(it.groupValues[1].toInt())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ class Content(root: JSONObject) {
|
|||
val en2 = raw.arr("en2")
|
||||
val en3 = raw.arr("en3")
|
||||
val en4 = raw.arr("en4")
|
||||
val de = raw.arr("de")
|
||||
val de2 = raw.arr("de2")
|
||||
val de3 = raw.arr("de3")
|
||||
val de4 = raw.arr("de4")
|
||||
val lit = raw.arr("lit")
|
||||
val lit2 = raw.arr("lit2")
|
||||
val lit3 = raw.arr("lit3")
|
||||
|
|
@ -70,6 +74,13 @@ class Content(root: JSONObject) {
|
|||
else -> en
|
||||
}
|
||||
fun enLesson(year: Int, id: Int) = enYear(year).firstOrNull { it.int("id") == id }
|
||||
fun deYear(year: Int) = when (year) {
|
||||
2 -> de2
|
||||
3 -> de3
|
||||
4 -> de4
|
||||
else -> de
|
||||
}
|
||||
fun deLesson(year: Int, id: Int) = deYear(year).firstOrNull { it.int("id") == id }
|
||||
fun litLesson(id: Int) = lit.firstOrNull { it.int("id") == id }
|
||||
fun lit2Lesson(id: Int) = lit2.firstOrNull { it.int("id") == id }
|
||||
fun lit3Lesson(id: Int) = lit3.firstOrNull { it.int("id") == id }
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class ProgressStore(context: Context) {
|
|||
|
||||
fun enDone(year: Int, id: Int) = prefs.getBoolean("en.$year.$id", false)
|
||||
fun markEn(year: Int, id: Int) { prefs.edit().putBoolean("en.$year.$id", true).apply() }
|
||||
fun deDone(year: Int, id: Int) = prefs.getBoolean("de.$year.$id", false)
|
||||
fun markDe(year: Int, id: Int) { prefs.edit().putBoolean("de.$year.$id", true).apply() }
|
||||
|
||||
fun litDone(id: Int) = prefs.getBoolean("lit.$id", false)
|
||||
fun markLit(id: Int) { prefs.edit().putBoolean("lit.$id", true).apply() }
|
||||
|
|
@ -158,6 +160,14 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
|
|||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.deYear(year).forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.deDone(year, l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
content.lit.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
|
|
|
|||
|
|
@ -1382,8 +1382,15 @@ fun PlotScreen(vm: AppViewModel, id: String) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun EngExScreen(vm: AppViewModel, year: Int, id: Int) {
|
||||
val lesson = vm.content.enLesson(year, id) ?: return
|
||||
fun EngExScreen(
|
||||
vm: AppViewModel,
|
||||
year: Int,
|
||||
id: Int,
|
||||
locale: Locale = Locale.UK,
|
||||
spec: J? = vm.content.enLesson(year, id),
|
||||
onDone: () -> Unit = { vm.markEn(year, id) },
|
||||
) {
|
||||
val lesson = spec ?: return
|
||||
val readQ = lesson.arr("readQuiz")
|
||||
val listenQ = lesson.arr("listenQuiz")
|
||||
val quiz = lesson.arr("quiz")
|
||||
|
|
@ -1410,7 +1417,7 @@ fun EngExScreen(vm: AppViewModel, year: Int, id: Int) {
|
|||
DisposableEffect(context) {
|
||||
var engine: TextToSpeech? = null
|
||||
engine = TextToSpeech(context) { status ->
|
||||
if (status == TextToSpeech.SUCCESS) engine?.language = Locale.UK
|
||||
if (status == TextToSpeech.SUCCESS) engine?.language = locale
|
||||
}
|
||||
tts = engine
|
||||
onDispose {
|
||||
|
|
@ -1447,7 +1454,7 @@ fun EngExScreen(vm: AppViewModel, year: Int, id: Int) {
|
|||
fb = when {
|
||||
all -> {
|
||||
showModel = true
|
||||
vm.markEn(year, id)
|
||||
onDone()
|
||||
vm.tr("feedback_ok") to "ok"
|
||||
}
|
||||
writing != null && !writeOk && readOk && listenOk && quizOk && gapOk == gapRows.size ->
|
||||
|
|
@ -1472,7 +1479,7 @@ fun EngExScreen(vm: AppViewModel, year: Int, id: Int) {
|
|||
val start = index.coerceIn(0, listening.length)
|
||||
val id = "en-${System.nanoTime()}"
|
||||
utterance = id
|
||||
engine.language = Locale.UK
|
||||
engine.language = locale
|
||||
engine.setSpeechRate(speed)
|
||||
engine.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
|
||||
override fun onStart(utteranceId: String?) {}
|
||||
|
|
|
|||
|
|
@ -294,10 +294,16 @@ private fun Metric(label: String, value: String, modifier: Modifier) {
|
|||
private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
|
||||
val sum = ProgressSum()
|
||||
when (s.str("target")) {
|
||||
"roadmap" -> vm.content.german.filter { it.bool("unlocked") }.forEach { u ->
|
||||
val n = u.strs("names").size
|
||||
sum.totalEx += n
|
||||
sum.doneEx += (1..n).count { vm.progress.germanDone(u.int("id"), it) }
|
||||
"dehome" -> {
|
||||
vm.content.german.filter { it.bool("unlocked") }.forEach { u ->
|
||||
val n = u.strs("names").size
|
||||
sum.totalEx += n
|
||||
sum.doneEx += (1..n).count { vm.progress.germanDone(u.int("id"), it) }
|
||||
}
|
||||
sum.totalEx += (1..4).sumOf { vm.content.deYear(it).size }
|
||||
sum.doneEx += (1..4).sumOf { year ->
|
||||
vm.content.deYear(year).count { vm.progress.deDone(year, it.int("id")) }
|
||||
}
|
||||
}
|
||||
"netyears" -> {
|
||||
sum.totalEx = vm.content.netLessons.size
|
||||
|
|
@ -558,6 +564,11 @@ private fun buildSearch(vm: AppViewModel): List<Hit> {
|
|||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "en${year}unit${l.int("id")}", extra = "anglictina english")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "en${year}ex${l.int("id")}")
|
||||
}
|
||||
add(vm.tr("de_year$year"), vm.tr("search_lesson"), "de${year}map", extra = "nemcina deutsch rocnik")
|
||||
vm.content.deYear(year).forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "de${year}unit${l.int("id")}", extra = "nemcina deutsch")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "de${year}ex${l.int("id")}")
|
||||
}
|
||||
}
|
||||
add(vm.tr("Literatura"), vm.tr("search_lesson"), "lityears", extra = "literatura")
|
||||
add(vm.tr("lit_year1"), vm.tr("search_lesson"), "litmap", extra = "rocnik")
|
||||
|
|
@ -735,6 +746,28 @@ fun HwYearsScreen(vm: AppViewModel) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Composable
|
||||
fun DeHomeScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Deutsch"), vm.tr("de_home_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("de_book_title"), subtitle = vm.tr("de_book_sub"), leading = { Text("U", style = MaterialTheme.typography.titleMedium) }) {
|
||||
vm.go(Route.Roadmap)
|
||||
}
|
||||
}
|
||||
items(4) { index ->
|
||||
val year = index + 1
|
||||
NavRow(
|
||||
title = vm.tr("de_year$year"),
|
||||
subtitle = vm.tr("de_y${year}_sub"),
|
||||
leading = { Text("$year.", style = MaterialTheme.typography.titleMedium) },
|
||||
) { vm.go(Route.DeMap(year)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EnYearsScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("English"), vm.tr("en_years_sub")) { inner ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue