mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 07:04:35 +00:00
Open technical graphics as four years of AutoCAD.
Each lesson has a method, a dimensioned assignment and a quiz, from the drawing sheet through the exam model. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
b50835fcd5
commit
6662eb185e
84 changed files with 3355 additions and 6 deletions
|
|
@ -30,6 +30,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.TgQuizScreen
|
||||
import org.maturita.maturita.ui.TgYearsScreen
|
||||
import org.maturita.maturita.ui.MathPracticeScreen
|
||||
import org.maturita.maturita.ui.MatYearsScreen
|
||||
import org.maturita.maturita.ui.FyzYearsScreen
|
||||
|
|
@ -525,6 +527,63 @@ private fun MaturitaAppBody(vm: AppViewModel) {
|
|||
}
|
||||
}
|
||||
is Route.Fyz4Ex -> FyzQuizScreen(vm, 4, r.id)
|
||||
Route.TgYears -> TgYearsScreen(vm)
|
||||
Route.TgMap -> LessonListScreen(
|
||||
vm, vm.tr("tg_year1"), vm.tr("tg_sub"),
|
||||
vm.content.tg.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.tgDone(id), Route.TgLesson(id))
|
||||
},
|
||||
)
|
||||
is Route.TgLesson -> {
|
||||
val l = vm.content.tgLesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.TgEx(r.id))
|
||||
}
|
||||
}
|
||||
is Route.TgEx -> TgQuizScreen(vm, 1, r.id)
|
||||
Route.Tg2Map -> LessonListScreen(
|
||||
vm, vm.tr("tg_year2"), vm.tr("tg2_sub"),
|
||||
vm.content.tg2.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.tg2Done(id), Route.Tg2Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Tg2Lesson -> {
|
||||
val l = vm.content.tg2Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Tg2Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Tg2Ex -> TgQuizScreen(vm, 2, r.id)
|
||||
Route.Tg3Map -> LessonListScreen(
|
||||
vm, vm.tr("tg_year3"), vm.tr("tg3_sub"),
|
||||
vm.content.tg3.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.tg3Done(id), Route.Tg3Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Tg3Lesson -> {
|
||||
val l = vm.content.tg3Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Tg3Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Tg3Ex -> TgQuizScreen(vm, 3, r.id)
|
||||
Route.Tg4Map -> LessonListScreen(
|
||||
vm, vm.tr("tg_year4"), vm.tr("tg4_sub"),
|
||||
vm.content.tg4.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.tg4Done(id), Route.Tg4Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Tg4Lesson -> {
|
||||
val l = vm.content.tg4Lesson(r.id)
|
||||
if (l != null) SlidesScreen(vm, vm.tr(l.str("titleKey")), vm.tr(l.str("subKey")), l.arr("slides")) {
|
||||
vm.replace(Route.Tg4Ex(r.id))
|
||||
}
|
||||
}
|
||||
is Route.Tg4Ex -> TgQuizScreen(vm, 4, r.id)
|
||||
Route.SciMap -> SciMapScreen(vm)
|
||||
Route.ChemMap -> LessonListScreen(
|
||||
vm, vm.tr("Chemie"), vm.tr("chem_sub"),
|
||||
|
|
|
|||
|
|
@ -242,6 +242,26 @@ class AppViewModel(val content: Content, val platform: Platform) {
|
|||
refresh()
|
||||
}
|
||||
|
||||
fun markTg(id: Int) {
|
||||
progress.markTg(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markTg2(id: Int) {
|
||||
progress.markTg2(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markTg3(id: Int) {
|
||||
progress.markTg3(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markTg4(id: Int) {
|
||||
progress.markTg4(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markMluv(n: Int) {
|
||||
progress.markMluv(n)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -105,6 +105,19 @@ sealed class Route(val page: String) {
|
|||
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 TgYears : Route("tgyears")
|
||||
data object TgMap : Route("tgmap")
|
||||
data class TgLesson(val id: Int) : Route("tgunit$id")
|
||||
data class TgEx(val id: Int) : Route("tgex$id")
|
||||
data object Tg2Map : Route("tg2map")
|
||||
data class Tg2Lesson(val id: Int) : Route("tg2unit$id")
|
||||
data class Tg2Ex(val id: Int) : Route("tg2ex$id")
|
||||
data object Tg3Map : Route("tg3map")
|
||||
data class Tg3Lesson(val id: Int) : Route("tg3unit$id")
|
||||
data class Tg3Ex(val id: Int) : Route("tg3ex$id")
|
||||
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 CzechMap : Route("czechmap")
|
||||
data object Mluvnice : Route("mluvnice")
|
||||
data class MluvEx(val n: Int) : Route("mluve$n")
|
||||
|
|
@ -237,6 +250,19 @@ sealed class Route(val page: String) {
|
|||
Fyz4Map -> listOf(Subjects, FyzYears, Fyz4Map)
|
||||
is Fyz4Lesson -> listOf(Subjects, FyzYears, Fyz4Map, this)
|
||||
is Fyz4Ex -> listOf(Subjects, FyzYears, Fyz4Map, Fyz4Lesson(id), this)
|
||||
TgYears -> listOf(Subjects, TgYears)
|
||||
TgMap -> listOf(Subjects, TgYears, TgMap)
|
||||
is TgLesson -> listOf(Subjects, TgYears, TgMap, this)
|
||||
is TgEx -> listOf(Subjects, TgYears, TgMap, TgLesson(id), this)
|
||||
Tg2Map -> listOf(Subjects, TgYears, Tg2Map)
|
||||
is Tg2Lesson -> listOf(Subjects, TgYears, Tg2Map, this)
|
||||
is Tg2Ex -> listOf(Subjects, TgYears, Tg2Map, Tg2Lesson(id), this)
|
||||
Tg3Map -> listOf(Subjects, TgYears, Tg3Map)
|
||||
is Tg3Lesson -> listOf(Subjects, TgYears, Tg3Map, this)
|
||||
is Tg3Ex -> listOf(Subjects, TgYears, Tg3Map, Tg3Lesson(id), this)
|
||||
Tg4Map -> listOf(Subjects, TgYears, Tg4Map)
|
||||
is Tg4Lesson -> listOf(Subjects, TgYears, Tg4Map, this)
|
||||
is Tg4Ex -> listOf(Subjects, TgYears, Tg4Map, Tg4Lesson(id), this)
|
||||
CzechMap -> listOf(Subjects, CzechMap)
|
||||
Mluvnice -> listOf(Subjects, CzechMap, Mluvnice)
|
||||
is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this)
|
||||
|
|
@ -289,6 +315,11 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
"fyz2map" -> Route.Fyz2Map
|
||||
"fyz3map" -> Route.Fyz3Map
|
||||
"fyz4map" -> Route.Fyz4Map
|
||||
"tgyears" -> Route.TgYears
|
||||
"tgmap" -> Route.TgMap
|
||||
"tg2map" -> Route.Tg2Map
|
||||
"tg3map" -> Route.Tg3Map
|
||||
"tg4map" -> Route.Tg4Map
|
||||
"czechmap" -> Route.CzechMap
|
||||
"mluvnice" -> Route.Mluvnice
|
||||
"readinglist" -> Route.ReadingList
|
||||
|
|
@ -386,6 +417,30 @@ fun routeFromPage(page: String): Route? = when (page) {
|
|||
Regex("""fyzex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.FyzEx(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg4unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg4Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg4ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg4Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg3unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg3Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg3ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg3Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg2unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg2Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tg2ex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Tg2Ex(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tgunit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.TgLesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""tgex(\d+)""").matchEntire(page)?.let {
|
||||
return Route.TgEx(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""lit4unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Lit4Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ class Content(root: JSONObject) {
|
|||
val fyz2 = raw.arr("fyz2")
|
||||
val fyz3 = raw.arr("fyz3")
|
||||
val fyz4 = raw.arr("fyz4")
|
||||
val tg = raw.arr("tg")
|
||||
val tg2 = raw.arr("tg2")
|
||||
val tg3 = raw.arr("tg3")
|
||||
val tg4 = raw.arr("tg4")
|
||||
val mat0 = raw.arr("mat0")
|
||||
val mat = raw.arr("mat")
|
||||
val mat2 = raw.arr("mat2")
|
||||
|
|
@ -108,6 +112,10 @@ class Content(root: JSONObject) {
|
|||
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 tgLesson(id: Int) = tg.firstOrNull { it.int("id") == id }
|
||||
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 mat0Lesson(id: Int) = mat0.firstOrNull { it.int("id") == id }
|
||||
fun matLesson(id: Int) = mat.firstOrNull { it.int("id") == id }
|
||||
fun mat2Lesson(id: Int) = mat2.firstOrNull { it.int("id") == id }
|
||||
|
|
|
|||
|
|
@ -91,6 +91,14 @@ class ProgressStore(private val prefs: Prefs, content: Content) {
|
|||
fun markFyz3(id: Int) { mark("fyz3.$id") }
|
||||
fun fyz4Done(id: Int) = done("fyz4.$id")
|
||||
fun markFyz4(id: Int) { mark("fyz4.$id") }
|
||||
fun tgDone(id: Int) = done("tg.$id")
|
||||
fun markTg(id: Int) { mark("tg.$id") }
|
||||
fun tg2Done(id: Int) = done("tg2.$id")
|
||||
fun markTg2(id: Int) { mark("tg2.$id") }
|
||||
fun tg3Done(id: Int) = done("tg3.$id")
|
||||
fun markTg3(id: Int) { mark("tg3.$id") }
|
||||
fun tg4Done(id: Int) = done("tg4.$id")
|
||||
fun markTg4(id: Int) { mark("tg4.$id") }
|
||||
fun mat0Done(id: Int) = done("mat0.$id")
|
||||
fun markMat0(id: Int) { mark("mat0.$id") }
|
||||
fun matDone(id: Int) = done("mat.$id")
|
||||
|
|
@ -280,6 +288,38 @@ fun summarize(content: Content, p: ProgressStore): ProgressSum {
|
|||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.tg.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.tgDone(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.tg2.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.tg2Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.tg3.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.tg3Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.tg4.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.tg4Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.mat0.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
|
|
|
|||
|
|
@ -1082,6 +1082,30 @@ fun ChoiceLessonScreen(vm: AppViewModel, lesson: J?, onDone: () -> Unit) {
|
|||
DispatchExercise(vm, spec, vm.tr(lesson.str("exTitleKey")), onDone)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TgQuizScreen(vm: AppViewModel, year: Int, id: Int) {
|
||||
val lesson = when (year) {
|
||||
2 -> vm.content.tg2Lesson(id)
|
||||
3 -> vm.content.tg3Lesson(id)
|
||||
4 -> vm.content.tg4Lesson(id)
|
||||
else -> vm.content.tgLesson(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.markTg2(id)
|
||||
3 -> vm.markTg3(id)
|
||||
4 -> vm.markTg4(id)
|
||||
else -> vm.markTg(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FyzQuizScreen(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.Architecture
|
||||
import androidx.compose.material.icons.filled.Bolt
|
||||
import androidx.compose.material.icons.filled.Functions
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
|
|
@ -225,6 +226,7 @@ private fun SubjectIcon(icon: String, open: Boolean) {
|
|||
"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))
|
||||
"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))
|
||||
else -> Icon(Icons.Filled.Lock, null, tint = tint)
|
||||
}
|
||||
}
|
||||
|
|
@ -348,6 +350,13 @@ private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
|
|||
vm.content.fyz3.count { vm.progress.fyz3Done(it.int("id")) } +
|
||||
vm.content.fyz4.count { vm.progress.fyz4Done(it.int("id")) }
|
||||
}
|
||||
"tgyears", "tgmap", "tg2map", "tg3map", "tg4map" -> {
|
||||
sum.totalEx = vm.content.tg.size + vm.content.tg2.size + vm.content.tg3.size + vm.content.tg4.size
|
||||
sum.doneEx = vm.content.tg.count { vm.progress.tgDone(it.int("id")) } +
|
||||
vm.content.tg2.count { vm.progress.tg2Done(it.int("id")) } +
|
||||
vm.content.tg3.count { vm.progress.tg3Done(it.int("id")) } +
|
||||
vm.content.tg4.count { vm.progress.tg4Done(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")) } +
|
||||
|
|
@ -649,6 +658,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("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")
|
||||
add(vm.tr("tg_year3"), vm.tr("search_lesson"), "tg3map", extra = "rocnik")
|
||||
add(vm.tr("tg_year4"), vm.tr("search_lesson"), "tg4map", extra = "rocnik")
|
||||
vm.content.tg.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "tgunit${l.int("id")}", extra = "autocad")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "tgex${l.int("id")}")
|
||||
}
|
||||
vm.content.tg2.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "tg2unit${l.int("id")}", extra = "autocad")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "tg2ex${l.int("id")}")
|
||||
}
|
||||
vm.content.tg3.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "tg3unit${l.int("id")}", extra = "autocad")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "tg3ex${l.int("id")}")
|
||||
}
|
||||
vm.content.tg4.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "tg4unit${l.int("id")}", extra = "autocad")
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_exercise"), "tg4ex${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 ->
|
||||
|
|
@ -848,6 +878,20 @@ fun MatYearsScreen(vm: AppViewModel) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TgYearsScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Technická grafika"), vm.tr("tg_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("tg_year1"), subtitle = vm.tr("tg_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.TgMap) }
|
||||
NavRow(title = vm.tr("tg_year2"), subtitle = vm.tr("tg2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Tg2Map) }
|
||||
NavRow(title = vm.tr("tg_year3"), subtitle = vm.tr("tg3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Tg3Map) }
|
||||
NavRow(title = vm.tr("tg_year4"), subtitle = vm.tr("tg4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Tg4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FyzYearsScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Fyzika"), vm.tr("fyz_years_sub")) { inner ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue