mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Compare commits
No commits in common. "235436dab001272b67f56608babac73da8c0dcdc" and "51101a93e2a9197f6a5f787ef475a32cc6f914a2" have entirely different histories.
235436dab0
...
51101a93e2
293 changed files with 455 additions and 13641 deletions
41
README.md
41
README.md
|
|
@ -11,9 +11,9 @@ Vzdělávací aplikace k přípravě na maturitu (repo `Graduately`). / An educa
|
|||
Rozhraní je v češtině a angličtině. Otevřené předměty jsou v seznamu níže;
|
||||
ostatní jsou zatím zamčené. Aplikace se po instalaci aktualizuje sama.
|
||||
|
||||
| Úvod | Němčina | Neue Freunde |
|
||||
| ---- | -------- | ------------ |
|
||||
|  |  |  |
|
||||
| Úvod | Předměty | Německá cesta |
|
||||
| ---- | -------- | ------------- |
|
||||
|  |  |  |
|
||||
|
||||
### Instalace
|
||||
|
||||
|
|
@ -71,15 +71,6 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
|
|||
- **Technické vybavení** — 4 ročníky: 1. ročník má 29 lekcí
|
||||
(architektura, data, skříň, deska, karty, disky a vstup),
|
||||
ročníky 2–4 po 8 lekcích (monitory, sestavení, RAID, servery, údržba)
|
||||
- **Technická grafika** — 4 ročníky AutoCADu, v každém 8 lekcí:
|
||||
výkres a souřadnice, úpravy a kóty, pohledy a tisk, 3D a maturitní zadání
|
||||
- **Prezentační grafika** — 4 ročníky, v každém 8 lekcí: Photoshop od pixelu
|
||||
po plakát, Premiere Pro a ve čtvrtém ročníku Illustrator, After Effects
|
||||
a InDesign
|
||||
- **Programové vybavení** — 4 ročníky, v každém 8 lekcí: Windows a licence,
|
||||
Word a Excel, Access a MySQL, pak WordPress, Power BI, dávkové soubory a zásady
|
||||
- **Programování** — 4 ročníky C# po vzoru W3Schools. U každé lekce se kód
|
||||
píše a spouští vedle výkladu, od výpisu po třídy, LINQ a async
|
||||
- **Č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)
|
||||
|
|
@ -99,10 +90,10 @@ Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#ses
|
|||
|
||||
### Použití
|
||||
|
||||
1. **Úvod** ukáže postup a mřížku předmětů. Každý předmět spustí svou cestu.
|
||||
2. U němčiny je učebnice (Neue Freunde, Aus aller Welt, Bei uns zu Hause) a čtyři ročníky. Ostatní otevřené předměty mají ročníky, lekce nebo knihy.
|
||||
3. Z cesty se otevře výklad, poslech, čtení, psaní nebo kvíz.
|
||||
4. **Statistiky**, **Nastavení** a **Hledat** jsou v postranním panelu na Macu. Na telefonu a v desktopové aplikaci jsou na záložkách, hledání navíc ikonou lupy. Zkratka je `Cmd/Ctrl+K`.
|
||||
1. **Pokračuj** otevře mapu předmětů.
|
||||
2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka, váhy, funkce, 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.
|
||||
|
||||
### Sestavení ze zdroje
|
||||
|
||||
|
|
@ -207,9 +198,9 @@ Licence: [GPL-3.0](LICENSE).
|
|||
The UI is Czech and English. Open subjects are listed below; the rest are
|
||||
still locked. After install the app updates itself.
|
||||
|
||||
| Welcome | German | Neue Freunde |
|
||||
| ------- | ------ | ----------- |
|
||||
|  |  |  |
|
||||
| Welcome | Subjects | German path |
|
||||
| ------- | -------- | ----------- |
|
||||
|  |  |  |
|
||||
|
||||
### Install
|
||||
|
||||
|
|
@ -268,10 +259,6 @@ Intel Mac, another architecture, or hacking on the code →
|
|||
- **Computer hardware** — 4 years: year 1 has 29 lessons
|
||||
(architecture, data, case, board, cards, drives and input),
|
||||
years 2–4 have 8 lessons each (displays, assembly, RAID, servers, maintenance)
|
||||
- **Technical graphics** — 4 years of AutoCAD, 8 lessons each:
|
||||
the sheet and coordinates, editing and dimensions, views and plotting, 3D and the exam drawing
|
||||
- **Programming** — 4 years of C# in the style of W3Schools. Each lesson has
|
||||
code you edit and run beside the explanation, from output to classes, LINQ and async
|
||||
- **Czech language** — literature (4 years, 32 lessons from the secondary-school
|
||||
syllabus), grammar (20 exercises) and required reading
|
||||
(82 books: notes, quiz, plot ordering)
|
||||
|
|
@ -292,10 +279,10 @@ Intel Mac, another architecture, or hacking on the code →
|
|||
|
||||
### Usage
|
||||
|
||||
1. **Welcome** shows progress and the subject grid. An open subject starts its path. Locked tiles do nothing yet: presentation graphics and software.
|
||||
2. German has the textbook (Neue Freunde, Aus aller Welt, Bei uns zu Hause) and four years. The other open subjects have years, lessons or books.
|
||||
3. A path opens an overview, listening, reading, writing or a quiz.
|
||||
4. **Statistics**, **Settings** and **Search** sit in the sidebar on Mac. On the phone and the desktop app they are tabs, with search also on the magnifier. The shortcut is `Cmd/Ctrl+K`.
|
||||
1. **Continue** opens the subject map.
|
||||
2. An open subject (flag, Wi‑Fi, chip, Czech flag, scales, function, 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.
|
||||
|
||||
### Build from source
|
||||
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
package org.maturita.maturita.desktop
|
||||
|
||||
import org.maturita.maturita.platform.CSharpRun
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/** One cached console project. The student's program replaces Program.cs and `dotnet run` executes it. */
|
||||
object CSharpLab {
|
||||
private val gate = Object()
|
||||
|
||||
fun run(source: String, stdin: String): CSharpRun {
|
||||
if (source.length > 100_000) return CSharpRun("fail", "Program je příliš dlouhý.")
|
||||
val dotnet = findDotnet() ?: return CSharpRun("unavailable", "")
|
||||
synchronized(gate) {
|
||||
return try {
|
||||
execute(dotnet, source, stdin)
|
||||
} catch (e: Exception) {
|
||||
CSharpRun("fail", e.message ?: "Spuštění selhalo.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun execute(dotnet: String, source: String, stdin: String): CSharpRun {
|
||||
val dir = File(System.getProperty("user.home"), ".graduately/csharp-lab")
|
||||
dir.mkdirs()
|
||||
val csproj = File(dir, "Lab.csproj")
|
||||
if (!csproj.isFile) {
|
||||
csproj.writeText(projectFile(targetFramework(dotnet)), StandardCharsets.UTF_8)
|
||||
val restored = command(dotnet, listOf("restore", dir.absolutePath), dir, "", 90)
|
||||
if (restored.status != "ok") return restored
|
||||
}
|
||||
File(dir, "Program.cs").writeText(source, StandardCharsets.UTF_8)
|
||||
val args = mutableListOf("run", "--project", dir.absolutePath, "--verbosity", "quiet")
|
||||
if (File(dir, "obj").isDirectory) args += "--no-restore"
|
||||
return command(dotnet, args, dir, stdin, 20)
|
||||
}
|
||||
|
||||
private fun command(dotnet: String, args: List<String>, dir: File, stdin: String, seconds: Long): CSharpRun {
|
||||
val process = ProcessBuilder(listOf(dotnet) + args)
|
||||
.directory(dir)
|
||||
.redirectErrorStream(true)
|
||||
.apply {
|
||||
environment().clear()
|
||||
environment().putAll(environmentFor(dotnet))
|
||||
}
|
||||
.start()
|
||||
process.outputStream.use { it.write(stdin.toByteArray(StandardCharsets.UTF_8)) }
|
||||
val output = ByteArrayOutputStream()
|
||||
val reader = Thread {
|
||||
process.inputStream.use { it.copyTo(output) }
|
||||
}
|
||||
reader.isDaemon = true
|
||||
reader.start()
|
||||
val finished = process.waitFor(seconds, TimeUnit.SECONDS)
|
||||
if (!finished) {
|
||||
process.descendants().forEach { it.destroyForcibly() }
|
||||
process.destroyForcibly()
|
||||
process.waitFor(2, TimeUnit.SECONDS)
|
||||
reader.join(1000)
|
||||
return CSharpRun("timeout", clip(output.toString(StandardCharsets.UTF_8)))
|
||||
}
|
||||
reader.join(2000)
|
||||
val text = clip(output.toString(StandardCharsets.UTF_8)).trim()
|
||||
return if (process.exitValue() == 0) CSharpRun("ok", text) else CSharpRun("fail", text)
|
||||
}
|
||||
|
||||
private fun clip(text: String): String =
|
||||
if (text.length <= 16_000) text else text.take(16_000) + "\n…"
|
||||
|
||||
private fun environmentFor(dotnet: String): Map<String, String> {
|
||||
val home = System.getProperty("user.home")
|
||||
val root = File(dotnet).parent
|
||||
val path = listOf(root, "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin")
|
||||
.joinToString(File.pathSeparator)
|
||||
val env = mutableMapOf(
|
||||
"PATH" to path,
|
||||
"HOME" to home,
|
||||
"USERPROFILE" to home,
|
||||
"DOTNET_ROOT" to root,
|
||||
"DOTNET_CLI_TELEMETRY_OPTOUT" to "1",
|
||||
"DOTNET_NOLOGO" to "1",
|
||||
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE" to "1",
|
||||
"TEMP" to System.getProperty("java.io.tmpdir"),
|
||||
"TMP" to System.getProperty("java.io.tmpdir"),
|
||||
)
|
||||
System.getenv("SystemRoot")?.let { env["SystemRoot"] = it }
|
||||
System.getenv("ComSpec")?.let { env["ComSpec"] = it }
|
||||
return env
|
||||
}
|
||||
|
||||
private fun targetFramework(dotnet: String): String {
|
||||
val version = command(dotnet, listOf("--version"), File(System.getProperty("java.io.tmpdir")), "", 20)
|
||||
val major = version.output.trim().substringBefore('.').filter { it.isDigit() }
|
||||
return if (major.isEmpty()) "net8.0" else "net$major.0"
|
||||
}
|
||||
|
||||
private fun projectFile(framework: String) = """
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>$framework</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
""".trimIndent()
|
||||
|
||||
private fun findDotnet(): String? {
|
||||
val home = System.getProperty("user.home")
|
||||
val programFiles = System.getenv("ProgramFiles") ?: "C:\\Program Files"
|
||||
val names = listOf(
|
||||
"/usr/local/share/dotnet/dotnet",
|
||||
"/usr/share/dotnet/dotnet",
|
||||
"/opt/homebrew/share/dotnet/dotnet",
|
||||
"$home/.dotnet/dotnet",
|
||||
"$programFiles\\dotnet\\dotnet.exe",
|
||||
)
|
||||
names.firstOrNull { File(it).canExecute() }?.let { return it }
|
||||
val path = System.getenv("PATH") ?: return null
|
||||
return path.split(File.pathSeparator)
|
||||
.map { File(it, if (System.getProperty("os.name").startsWith("Windows")) "dotnet.exe" else "dotnet") }
|
||||
.firstOrNull { it.canExecute() }
|
||||
?.absolutePath
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package org.maturita.maturita.desktop
|
||||
|
||||
import org.maturita.maturita.platform.CSharpRun
|
||||
import org.maturita.maturita.platform.Platform
|
||||
import org.maturita.maturita.platform.Prefs
|
||||
import org.maturita.maturita.platform.Speaker
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
class DesktopPlatform(
|
||||
override val commit: String,
|
||||
|
|
@ -16,11 +14,4 @@ class DesktopPlatform(
|
|||
override val updater = DesktopUpdater(commit, install)
|
||||
|
||||
override fun speaker(): Speaker? = DesktopSpeaker.create()
|
||||
|
||||
override fun runCSharp(source: String, stdin: String, cb: (CSharpRun) -> Unit) {
|
||||
Thread {
|
||||
val result = CSharpLab.run(source, stdin)
|
||||
SwingUtilities.invokeLater { cb(result) }
|
||||
}.apply { isDaemon = true }.start()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ fun main() {
|
|||
val info = Properties().apply { resourceText("build-info.properties")?.let { load(it.reader()) } }
|
||||
val platform = DesktopPlatform(info.getProperty("commit") ?: "dev", prefs, install)
|
||||
val vm = AppViewModel(Content.parse(resourceText("content.json")), platform)
|
||||
// `GRADUATELY_PAGE=u1e3 make run` opens a page, for screenshots.
|
||||
System.getenv("GRADUATELY_PAGE")?.takeIf { it.isNotBlank() }?.let { vm.openPage(it) }
|
||||
val icon = Thread.currentThread().contextClassLoader.getResourceAsStream("icon.png")
|
||||
?.use { ImageIO.read(it) }?.let { BitmapPainter(it.toComposeImageBitmap()) }
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ import org.maturita.maturita.data.ColorMode
|
|||
import org.maturita.maturita.data.Palette
|
||||
import org.maturita.maturita.ui.BookListScreen
|
||||
import org.maturita.maturita.ui.BookScreen
|
||||
import org.maturita.maturita.ui.CodeLessonScreen
|
||||
import org.maturita.maturita.ui.CsYearsScreen
|
||||
import org.maturita.maturita.ui.CzechMapScreen
|
||||
import org.maturita.maturita.ui.GermanExercise
|
||||
import org.maturita.maturita.ui.HomeScreen
|
||||
|
|
@ -32,12 +30,6 @@ 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.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
|
||||
import org.maturita.maturita.ui.MatYearsScreen
|
||||
import org.maturita.maturita.ui.FyzYearsScreen
|
||||
|
|
@ -533,222 +525,6 @@ 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.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.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"),
|
||||
vm.content.cs.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.csDone(id), Route.CsLesson(id))
|
||||
},
|
||||
)
|
||||
is Route.CsLesson -> {
|
||||
val l = vm.content.csLesson(r.id)
|
||||
if (l != null) CodeLessonScreen(vm, l) { vm.markCs(r.id) }
|
||||
}
|
||||
Route.Cs2Map -> LessonListScreen(
|
||||
vm, vm.tr("cs_year2"), vm.tr("cs2_sub"),
|
||||
vm.content.cs2.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.cs2Done(id), Route.Cs2Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Cs2Lesson -> {
|
||||
val l = vm.content.cs2Lesson(r.id)
|
||||
if (l != null) CodeLessonScreen(vm, l) { vm.markCs2(r.id) }
|
||||
}
|
||||
Route.Cs3Map -> LessonListScreen(
|
||||
vm, vm.tr("cs_year3"), vm.tr("cs3_sub"),
|
||||
vm.content.cs3.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.cs3Done(id), Route.Cs3Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Cs3Lesson -> {
|
||||
val l = vm.content.cs3Lesson(r.id)
|
||||
if (l != null) CodeLessonScreen(vm, l) { vm.markCs3(r.id) }
|
||||
}
|
||||
Route.Cs4Map -> LessonListScreen(
|
||||
vm, vm.tr("cs_year4"), vm.tr("cs4_sub"),
|
||||
vm.content.cs4.map { l ->
|
||||
val id = l.int("id")
|
||||
LessonRow(vm.tr(l.str("titleKey")), vm.progress.cs4Done(id), Route.Cs4Lesson(id))
|
||||
},
|
||||
)
|
||||
is Route.Cs4Lesson -> {
|
||||
val l = vm.content.cs4Lesson(r.id)
|
||||
if (l != null) CodeLessonScreen(vm, l) { vm.markCs4(r.id) }
|
||||
}
|
||||
Route.SciMap -> SciMapScreen(vm)
|
||||
Route.ChemMap -> LessonListScreen(
|
||||
vm, vm.tr("Chemie"), vm.tr("chem_sub"),
|
||||
|
|
|
|||
|
|
@ -242,86 +242,6 @@ 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 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 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()
|
||||
}
|
||||
|
||||
fun markCs2(id: Int) {
|
||||
progress.markCs2(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markCs3(id: Int) {
|
||||
progress.markCs3(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markCs4(id: Int) {
|
||||
progress.markCs4(id)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun markMluv(n: Int) {
|
||||
progress.markMluv(n)
|
||||
refresh()
|
||||
|
|
|
|||
|
|
@ -105,54 +105,6 @@ 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 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 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")
|
||||
data object Cs2Map : Route("cs2map")
|
||||
data class Cs2Lesson(val id: Int) : Route("cs2unit$id")
|
||||
data object Cs3Map : Route("cs3map")
|
||||
data class Cs3Lesson(val id: Int) : Route("cs3unit$id")
|
||||
data object Cs4Map : Route("cs4map")
|
||||
data class Cs4Lesson(val id: Int) : Route("cs4unit$id")
|
||||
data object CzechMap : Route("czechmap")
|
||||
data object Mluvnice : Route("mluvnice")
|
||||
data class MluvEx(val n: Int) : Route("mluve$n")
|
||||
|
|
@ -285,54 +237,6 @@ 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)
|
||||
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)
|
||||
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)
|
||||
Cs2Map -> listOf(Subjects, CsYears, Cs2Map)
|
||||
is Cs2Lesson -> listOf(Subjects, CsYears, Cs2Map, this)
|
||||
Cs3Map -> listOf(Subjects, CsYears, Cs3Map)
|
||||
is Cs3Lesson -> listOf(Subjects, CsYears, Cs3Map, this)
|
||||
Cs4Map -> listOf(Subjects, CsYears, Cs4Map)
|
||||
is Cs4Lesson -> listOf(Subjects, CsYears, Cs4Map, this)
|
||||
CzechMap -> listOf(Subjects, CzechMap)
|
||||
Mluvnice -> listOf(Subjects, CzechMap, Mluvnice)
|
||||
is MluvEx -> listOf(Subjects, CzechMap, Mluvnice, this)
|
||||
|
|
@ -385,26 +289,6 @@ 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
|
||||
"pgyears" -> Route.PgYears
|
||||
"pgmap" -> Route.PgMap
|
||||
"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
|
||||
"cs3map" -> Route.Cs3Map
|
||||
"cs4map" -> Route.Cs4Map
|
||||
"czechmap" -> Route.CzechMap
|
||||
"mluvnice" -> Route.Mluvnice
|
||||
"readinglist" -> Route.ReadingList
|
||||
|
|
@ -502,90 +386,6 @@ 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("""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("""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())
|
||||
}
|
||||
Regex("""cs3unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Cs3Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""cs2unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Cs2Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""csunit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.CsLesson(it.groupValues[1].toInt())
|
||||
}
|
||||
Regex("""lit4unit(\d+)""").matchEntire(page)?.let {
|
||||
return Route.Lit4Lesson(it.groupValues[1].toInt())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,22 +56,6 @@ 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 pg = raw.arr("pg")
|
||||
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")
|
||||
val cs4 = raw.arr("cs4")
|
||||
val mat0 = raw.arr("mat0")
|
||||
val mat = raw.arr("mat")
|
||||
val mat2 = raw.arr("mat2")
|
||||
|
|
@ -124,22 +108,6 @@ 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 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 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 }
|
||||
fun cs4Lesson(id: Int) = cs4.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,38 +91,6 @@ 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 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 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")
|
||||
fun markCs2(id: Int) { mark("cs2.$id") }
|
||||
fun cs3Done(id: Int) = done("cs3.$id")
|
||||
fun markCs3(id: Int) { mark("cs3.$id") }
|
||||
fun cs4Done(id: Int) = done("cs4.$id")
|
||||
fun markCs4(id: Int) { mark("cs4.$id") }
|
||||
fun mat0Done(id: Int) = done("mat0.$id")
|
||||
fun markMat0(id: Int) { mark("mat0.$id") }
|
||||
fun matDone(id: Int) = done("mat.$id")
|
||||
|
|
@ -312,134 +280,6 @@ 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.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.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
|
||||
if (p.csDone(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.cs2.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.cs2Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.cs3.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.cs3Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.cs4.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
if (p.cs4Done(l.int("id"))) {
|
||||
sum.doneEx += 1
|
||||
sum.doneUnits += 1
|
||||
}
|
||||
}
|
||||
content.mat0.forEach { l ->
|
||||
sum.totalEx += 1
|
||||
sum.openUnits += 1
|
||||
|
|
|
|||
|
|
@ -18,18 +18,8 @@ interface Platform {
|
|||
|
||||
/** A speech engine for listening exercises, or null when there is none. */
|
||||
fun speaker(): Speaker?
|
||||
|
||||
/**
|
||||
* Compiles and runs a C# program. [cb] runs on the UI thread.
|
||||
* Status is ok, fail, timeout or unavailable.
|
||||
*/
|
||||
fun runCSharp(source: String, stdin: String, cb: (CSharpRun) -> Unit) {
|
||||
cb(CSharpRun("unavailable", ""))
|
||||
}
|
||||
}
|
||||
|
||||
data class CSharpRun(val status: String, val output: String)
|
||||
|
||||
/** The subset of Android's SharedPreferences the app uses. */
|
||||
interface Prefs {
|
||||
fun getBoolean(key: String, fallback: Boolean): Boolean
|
||||
|
|
|
|||
|
|
@ -1,303 +0,0 @@
|
|||
package org.maturita.maturita.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Cancel
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.Code
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.Terminal
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.input.OffsetMapping
|
||||
import androidx.compose.ui.text.input.TransformedText
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.max
|
||||
import androidx.compose.ui.unit.min
|
||||
import androidx.compose.ui.unit.sp
|
||||
import org.maturita.maturita.AppViewModel
|
||||
import org.maturita.maturita.data.J
|
||||
|
||||
/** Explanation on one side, the program and its output on the other. */
|
||||
@Composable
|
||||
fun CodeLessonScreen(vm: AppViewModel, lesson: J, onSuccess: () -> Unit) {
|
||||
val key = lesson.str("key")
|
||||
val starter = lesson.str("code")
|
||||
var code by remember(key) { mutableStateOf(starter) }
|
||||
var stdin by remember(key) { mutableStateOf("") }
|
||||
var output by remember(key) { mutableStateOf("") }
|
||||
var status by remember(key) { mutableStateOf("") }
|
||||
val running = status == "running"
|
||||
val needsInput = "ReadLine" in code
|
||||
|
||||
fun run() {
|
||||
if (running) return
|
||||
status = "running"
|
||||
output = vm.tr("cs_running")
|
||||
vm.platform.runCSharp(code, if (needsInput) stdin else "") { result ->
|
||||
status = result.status
|
||||
output = when (result.status) {
|
||||
"unavailable" -> vm.tr("cs_unavailable")
|
||||
"timeout" -> (result.output + "\n\n" + vm.tr("cs_timeout")).trim()
|
||||
else -> result.output.ifEmpty { vm.tr("cs_empty") }
|
||||
}
|
||||
if (result.status == "ok") onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
code = starter
|
||||
output = ""
|
||||
status = ""
|
||||
}
|
||||
|
||||
DetailScaffold(vm, vm.tr(lesson.str("titleKey")), vm.tr(lesson.str("subKey")), maxContentWidth = 1640.dp) { inner ->
|
||||
BoxWithConstraints(Modifier.fillMaxSize().padding(inner)) {
|
||||
val width = maxWidth
|
||||
val height = maxHeight
|
||||
if (width >= 900.dp) {
|
||||
Row(
|
||||
Modifier.fillMaxSize().padding(horizontal = 24.dp, vertical = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
Column(Modifier.width(min(560.dp, width * 0.4f)).fillMaxHeight().verticalScroll(rememberScrollState())) {
|
||||
Explanation(lesson)
|
||||
}
|
||||
Column(Modifier.weight(1f).fillMaxHeight(), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
EditorCard(vm, code, { code = it }, running, ::run, ::reset, compact = false, Modifier.weight(1f))
|
||||
if (needsInput) InputField(vm, stdin) { stdin = it }
|
||||
OutputCard(vm, output, status, Modifier.height(max(180.dp, height * 0.32f)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
Explanation(lesson)
|
||||
EditorCard(vm, code, { code = it }, running, ::run, ::reset, compact = true, Modifier.height(320.dp))
|
||||
if (needsInput) InputField(vm, stdin) { stdin = it }
|
||||
OutputCard(vm, output, status, Modifier.height(220.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Explanation(lesson: J) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(28.dp)) {
|
||||
lesson.arr("slides").forEach { SlideContent(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditorCard(
|
||||
vm: AppViewModel,
|
||||
code: String,
|
||||
onCode: (String) -> Unit,
|
||||
running: Boolean,
|
||||
onRun: () -> Unit,
|
||||
onReset: () -> Unit,
|
||||
compact: Boolean,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
val dark = MaterialTheme.colorScheme.background.luminance() < 0.5f
|
||||
val highlight = remember(dark) { CSharpHighlight(dark) }
|
||||
Surface(modifier.fillMaxWidth(), shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.surfaceContainerHigh) {
|
||||
Column {
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(horizontal = 14.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Icon(Icons.Filled.Code, null, tint = MaterialTheme.colorScheme.primary)
|
||||
Text("Program.cs", style = MaterialTheme.typography.titleSmall.copy(fontFamily = FontFamily.Monospace))
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (compact) {
|
||||
IconButton(onClick = onReset, enabled = !running) {
|
||||
Icon(Icons.Filled.Refresh, contentDescription = vm.tr("cs_reset"))
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(onClick = onReset, enabled = !running) {
|
||||
Icon(Icons.Filled.Refresh, null, Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(vm.tr("cs_reset"))
|
||||
}
|
||||
}
|
||||
Button(onClick = onRun, enabled = !running) {
|
||||
Icon(Icons.Filled.PlayArrow, null, Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(vm.tr("cs_run"))
|
||||
}
|
||||
}
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
BasicTextField(
|
||||
value = code,
|
||||
onValueChange = onCode,
|
||||
textStyle = codeStyle().copy(color = MaterialTheme.colorScheme.onSurface),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
|
||||
visualTransformation = highlight,
|
||||
modifier = Modifier.fillMaxSize().padding(14.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InputField(vm: AppViewModel, stdin: String, onStdin: (String) -> Unit) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
Text(vm.tr("cs_stdin"), style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
OutlinedTextField(
|
||||
value = stdin,
|
||||
onValueChange = onStdin,
|
||||
textStyle = codeStyle(),
|
||||
minLines = 1,
|
||||
maxLines = 4,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OutputCard(vm: AppViewModel, output: String, status: String, modifier: Modifier) {
|
||||
val muted = output.isEmpty() || status == "running"
|
||||
Surface(modifier.fillMaxWidth(), shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.surfaceContainerHigh) {
|
||||
Column {
|
||||
Row(
|
||||
Modifier.fillMaxWidth().height(48.dp).padding(horizontal = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(Icons.Filled.Terminal, null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(vm.tr("cs_output"), style = MaterialTheme.typography.titleSmall)
|
||||
Spacer(Modifier.weight(1f))
|
||||
StatusBadge(vm, status)
|
||||
}
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
Text(
|
||||
output.ifEmpty { vm.tr("cs_empty") },
|
||||
style = codeStyle(),
|
||||
color = if (muted) MaterialTheme.colorScheme.onSurfaceVariant else MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(14.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatusBadge(vm: AppViewModel, status: String) {
|
||||
when (status) {
|
||||
"running" -> CircularProgressIndicator(Modifier.size(18.dp), strokeWidth = 2.dp)
|
||||
"ok" -> Badge(vm.tr("cs_done"), Icons.Filled.CheckCircle, MaterialTheme.colorScheme.primary)
|
||||
"fail", "timeout" -> Badge(vm.tr("cs_failed"), Icons.Filled.Cancel, MaterialTheme.colorScheme.error)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Badge(text: String, icon: androidx.compose.ui.graphics.vector.ImageVector, color: Color) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(icon, null, tint = color, modifier = Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(text, style = MaterialTheme.typography.labelLarge, color = color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun codeStyle() = TextStyle(fontFamily = FontFamily.Monospace, fontSize = 15.sp, lineHeight = 22.sp)
|
||||
|
||||
/** Colours C# keywords, types, numbers, strings and comments without changing the text. */
|
||||
private class CSharpHighlight(dark: Boolean) : VisualTransformation {
|
||||
private val palette = listOf(
|
||||
Color(if (dark) 0xFFFF7AB2 else 0xFF9B2393),
|
||||
Color(if (dark) 0xFF5DD8FF else 0xFF0B4F79),
|
||||
Color(if (dark) 0xFFD9C97C else 0xFF1C00CF),
|
||||
Color(if (dark) 0xFFFC6A5D else 0xFFC41A16),
|
||||
Color(if (dark) 0xFF7F8C98 else 0xFF5D6C79),
|
||||
)
|
||||
|
||||
override fun filter(text: AnnotatedString): TransformedText =
|
||||
TransformedText(highlight(text.text), OffsetMapping.Identity)
|
||||
|
||||
private fun highlight(code: String): AnnotatedString {
|
||||
val kind = IntArray(code.length) { -1 }
|
||||
RULES.forEachIndexed { index, rule ->
|
||||
rule.findAll(code).forEach { m -> for (i in m.range) kind[i] = index }
|
||||
}
|
||||
return buildAnnotatedString {
|
||||
var start = 0
|
||||
while (start < code.length) {
|
||||
var end = start
|
||||
while (end < code.length && kind[end] == kind[start]) end++
|
||||
val k = kind[start]
|
||||
if (k >= 0) {
|
||||
pushStyle(SpanStyle(color = palette[k]))
|
||||
append(code, start, end)
|
||||
pop()
|
||||
} else {
|
||||
append(code, start, end)
|
||||
}
|
||||
start = end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KEYWORDS = listOf(
|
||||
"abstract", "as", "async", "await", "base", "bool", "break", "case", "catch", "char", "class",
|
||||
"const", "continue", "decimal", "default", "do", "double", "else", "enum", "false", "finally",
|
||||
"float", "for", "foreach", "get", "if", "in", "int", "interface", "internal", "is", "long",
|
||||
"namespace", "new", "null", "object", "out", "override", "private", "protected", "public",
|
||||
"readonly", "record", "ref", "return", "sealed", "set", "static", "string", "struct", "switch",
|
||||
"this", "throw", "true", "try", "using", "var", "virtual", "void", "while",
|
||||
)
|
||||
|
||||
/** Later rules win, so strings and comments override keywords inside them. */
|
||||
private val RULES = listOf(
|
||||
Regex("\\b(?:" + KEYWORDS.joinToString("|") + ")\\b"),
|
||||
Regex("\\b(?:Console|Math|List|Dictionary|File|Task|Exception|Func|Action|String|DateTime|Random)\\b"),
|
||||
Regex("\\b\\d+(?:\\.\\d+)?\\b"),
|
||||
Regex("\\$?@?\"(?:\\\\.|[^\"\\\\\\n])*\"|'(?:\\\\.|[^'\\\\\\n])'"),
|
||||
Regex("//[^\\n]*|/\\*[\\s\\S]*?\\*/"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,22 +8,15 @@ import androidx.compose.animation.fadeIn
|
|||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
|
|
@ -31,17 +24,7 @@ import androidx.compose.foundation.layout.navigationBars
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
|
|
@ -61,6 +44,7 @@ import androidx.compose.material3.FilterChip
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LargeTopAppBar
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -166,19 +150,7 @@ fun AppNavBar(vm: AppViewModel) {
|
|||
private fun navIconColor(selected: Boolean): Color =
|
||||
if (selected) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onSurfaceVariant
|
||||
|
||||
/** Lists and exercises stop growing here so they keep their shape in wide desktop windows. */
|
||||
val ContentMaxWidth = 880.dp
|
||||
val ActionMaxWidth = 560.dp
|
||||
|
||||
/** Caps the width of [content] and centres it; phones are narrower than the cap anyway. */
|
||||
@Composable
|
||||
fun CenteredColumn(maxWidth: Dp = ContentMaxWidth, content: @Composable () -> Unit) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) {
|
||||
Box(Modifier.widthIn(max = maxWidth).fillMaxSize()) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
/** Tab root: large collapsing title on phones, a compact one in wide windows. */
|
||||
/** Tab root: large collapsing title, search action, bottom navigation. */
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun RootScaffold(
|
||||
|
|
@ -187,48 +159,30 @@ fun RootScaffold(
|
|||
showSearch: Boolean = true,
|
||||
content: LazyListScope.() -> Unit,
|
||||
) {
|
||||
BoxWithConstraints {
|
||||
val wide = maxWidth >= 600.dp
|
||||
val scroll = if (wide) {
|
||||
TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
} else {
|
||||
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
|
||||
}
|
||||
val actions: @Composable RowScope.() -> Unit = {
|
||||
if (showSearch) {
|
||||
IconButton(onClick = { vm.searchOpen = true }) {
|
||||
Icon(Icons.Filled.Search, contentDescription = vm.tr("search_placeholder"))
|
||||
}
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scroll.nestedScrollConnection),
|
||||
topBar = {
|
||||
if (wide) {
|
||||
TopAppBar(
|
||||
title = { Text(title, maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.headlineSmall) },
|
||||
actions = actions,
|
||||
scrollBehavior = scroll,
|
||||
)
|
||||
} else {
|
||||
LargeTopAppBar(
|
||||
title = { Text(title, maxLines = 1, overflow = TextOverflow.Ellipsis) },
|
||||
actions = actions,
|
||||
scrollBehavior = scroll,
|
||||
)
|
||||
}
|
||||
},
|
||||
bottomBar = { AppNavBar(vm) },
|
||||
) { inner ->
|
||||
CenteredColumn {
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(
|
||||
top = inner.calculateTopPadding(),
|
||||
bottom = inner.calculateBottomPadding() + 16.dp,
|
||||
),
|
||||
) { content() }
|
||||
}
|
||||
}
|
||||
val scroll = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scroll.nestedScrollConnection),
|
||||
topBar = {
|
||||
LargeTopAppBar(
|
||||
title = { Text(title, maxLines = 1, overflow = TextOverflow.Ellipsis) },
|
||||
actions = {
|
||||
if (showSearch) {
|
||||
IconButton(onClick = { vm.searchOpen = true }) {
|
||||
Icon(Icons.Filled.Search, contentDescription = vm.tr("search_placeholder"))
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scroll,
|
||||
)
|
||||
},
|
||||
bottomBar = { AppNavBar(vm) },
|
||||
) { inner ->
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(
|
||||
top = inner.calculateTopPadding(),
|
||||
bottom = inner.calculateBottomPadding() + 16.dp,
|
||||
),
|
||||
) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,7 +194,6 @@ fun DetailScaffold(
|
|||
title: String,
|
||||
subtitle: String? = null,
|
||||
bottomBar: (@Composable () -> Unit)? = null,
|
||||
maxContentWidth: Dp = ContentMaxWidth,
|
||||
content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
val scroll = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
|
@ -271,9 +224,8 @@ fun DetailScaffold(
|
|||
)
|
||||
},
|
||||
bottomBar = { bottomBar?.invoke() },
|
||||
) { inner ->
|
||||
CenteredColumn(maxContentWidth) { content(inner) }
|
||||
}
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
/** Feedback line plus the primary action, anchored at the bottom of an exercise. */
|
||||
|
|
@ -290,8 +242,6 @@ fun ActionBar(
|
|||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentWidth(Alignment.CenterHorizontally)
|
||||
.widthIn(max = ActionMaxWidth)
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
) {
|
||||
|
|
@ -326,27 +276,6 @@ fun SectionHeader(text: String) {
|
|||
)
|
||||
}
|
||||
|
||||
/** Number or short label in a tinted square, so rows line up whatever the label's width. */
|
||||
@Composable
|
||||
fun LeadingBadge(text: String) {
|
||||
Box(
|
||||
Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(MaterialTheme.colorScheme.primary.copy(alpha = 0.14f)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(text, style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LeadingIcon(icon: ImageVector) {
|
||||
Box(
|
||||
Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(MaterialTheme.colorScheme.primary.copy(alpha = 0.14f)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(icon, null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
/** One navigable row: done/pending/locked state on the left, chevron on the right. */
|
||||
@Composable
|
||||
fun NavRow(
|
||||
|
|
@ -355,33 +284,15 @@ fun NavRow(
|
|||
done: Boolean = false,
|
||||
locked: Boolean = false,
|
||||
leading: (@Composable () -> Unit)? = null,
|
||||
progress: Pair<Int, Int>? = null,
|
||||
onClick: (() -> Unit)?,
|
||||
) {
|
||||
val enabled = !locked && onClick != null
|
||||
val textColor = if (enabled) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurfaceVariant
|
||||
val rowModifier = if (enabled) Modifier.clickable(onClick = onClick!!) else Modifier
|
||||
val shownSubtitle = subtitle?.takeIf { it.isNotBlank() }
|
||||
val shownProgress = progress?.takeIf { it.second > 0 }
|
||||
ListItem(
|
||||
headlineContent = { Text(title, color = textColor) },
|
||||
supportingContent = if (shownSubtitle == null && shownProgress == null) null else {
|
||||
{
|
||||
Column {
|
||||
shownSubtitle?.let { Text(it, color = MaterialTheme.colorScheme.onSurfaceVariant) }
|
||||
shownProgress?.let { (doneCount, total) ->
|
||||
Row(Modifier.padding(top = 8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
SmoothProgress(doneCount / total.toFloat(), Modifier.weight(1f).height(6.dp))
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Text(
|
||||
"$doneCount / $total",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
supportingContent = subtitle?.takeIf { it.isNotBlank() }?.let {
|
||||
{ Text(it, color = MaterialTheme.colorScheme.onSurfaceVariant) }
|
||||
},
|
||||
leadingContent = {
|
||||
when {
|
||||
|
|
@ -417,38 +328,19 @@ fun SmoothProgress(
|
|||
progress: Float,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = MaterialTheme.colorScheme.primary,
|
||||
trackColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f),
|
||||
trackColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
) {
|
||||
val animated by animateFloatAsState(
|
||||
targetValue = progress.coerceIn(0f, 1f),
|
||||
animationSpec = tween(durationMillis = 380),
|
||||
label = "progress",
|
||||
)
|
||||
Box(modifier.heightIn(min = 4.dp).clip(CircleShape).background(trackColor)) {
|
||||
if (animated > 0f) {
|
||||
Box(Modifier.fillMaxHeight().fillMaxWidth(animated).clip(CircleShape).background(color))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Circular progress with a label in the middle. */
|
||||
@Composable
|
||||
fun ProgressRing(progress: Float, modifier: Modifier = Modifier, stroke: Dp = 10.dp, label: @Composable () -> Unit) {
|
||||
val animated by animateFloatAsState(progress.coerceIn(0f, 1f), tween(durationMillis = 380), label = "ring")
|
||||
val track = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)
|
||||
val fill = MaterialTheme.colorScheme.primary
|
||||
Box(modifier, contentAlignment = Alignment.Center) {
|
||||
Canvas(Modifier.fillMaxSize()) {
|
||||
val width = stroke.toPx()
|
||||
val inset = width / 2
|
||||
val arcSize = Size(size.width - width, size.height - width)
|
||||
drawArc(track, 0f, 360f, false, Offset(inset, inset), arcSize, style = Stroke(width))
|
||||
if (animated > 0f) {
|
||||
drawArc(fill, -90f, 360f * animated, false, Offset(inset, inset), arcSize, style = Stroke(width, cap = StrokeCap.Round))
|
||||
}
|
||||
}
|
||||
label()
|
||||
}
|
||||
LinearProgressIndicator(
|
||||
progress = { animated },
|
||||
modifier = modifier,
|
||||
color = color,
|
||||
trackColor = trackColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -1082,78 +1082,6 @@ 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 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 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) {
|
||||
|
|
|
|||
|
|
@ -25,13 +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
|
||||
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
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
|
|
@ -41,7 +35,6 @@ import androidx.compose.material.icons.filled.Groups
|
|||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.filled.Quiz
|
||||
import androidx.compose.material.icons.filled.Science
|
||||
import androidx.compose.material.icons.filled.Terminal
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.outlined.Lightbulb
|
||||
import androidx.compose.material3.Card
|
||||
|
|
@ -106,61 +99,50 @@ fun HomeScreen(vm: AppViewModel) {
|
|||
item {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||
),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer),
|
||||
) {
|
||||
Row(Modifier.padding(20.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
Text(vm.tr("welcome_title"), style = MaterialTheme.typography.headlineMedium)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
vm.tr(vm.platform.welcomeKey),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(16.dp))
|
||||
ProgressRing(pct, Modifier.size(104.dp)) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(vm.fmt("stats_pct_fmt", (pct * 100).toInt()), style = MaterialTheme.typography.titleLarge)
|
||||
Text(
|
||||
vm.fmt("stats_ex_fmt", sum.doneEx, sum.totalEx),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(20.dp)) {
|
||||
Text(
|
||||
vm.tr("welcome_title"),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
vm.tr(vm.platform.welcomeKey),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f),
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
SmoothProgress(
|
||||
progress = pct,
|
||||
modifier = Modifier.fillMaxWidth().height(6.dp).clip(CircleShape),
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
trackColor = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.18f),
|
||||
)
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Text(
|
||||
vm.fmt("stats_ex_fmt", sum.doneEx, sum.totalEx),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vm.update.canInstall || vm.update.status == "downloading" || vm.update.status == "staged") {
|
||||
item { UpdateBanner(vm) }
|
||||
}
|
||||
val open = vm.content.subjects.filter { it.bool("open") }
|
||||
val soon = vm.content.subjects.filter { !it.bool("open") }
|
||||
item { SectionHeader(vm.tr("subjects_title")) }
|
||||
items(open) { s ->
|
||||
val part = subjectSum(vm, s)
|
||||
items(vm.content.subjects) { s ->
|
||||
val open = s.bool("open")
|
||||
NavRow(
|
||||
title = vm.tr(s.str("key")),
|
||||
leading = { SubjectIcon(s.str("icon"), true) },
|
||||
progress = part.doneEx to part.totalEx,
|
||||
onClick = { vm.goPage(s.str("target")) },
|
||||
subtitle = if (open) null else vm.tr("stats_locked"),
|
||||
locked = !open,
|
||||
leading = { SubjectIcon(s.str("icon"), open) },
|
||||
onClick = if (open) ({ vm.goPage(s.str("target")) }) else null,
|
||||
)
|
||||
}
|
||||
if (soon.isNotEmpty()) {
|
||||
item { SectionHeader(vm.tr("subjects_soon")) }
|
||||
items(soon) { s ->
|
||||
NavRow(
|
||||
title = vm.tr(s.str("key")),
|
||||
locked = true,
|
||||
leading = { SubjectIcon(s.str("icon"), false) },
|
||||
onClick = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,18 +152,14 @@ private fun ChangelogCard(vm: AppViewModel) {
|
|||
val blocks = vm.content.changelog.take(3)
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||
),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.tertiaryContainer),
|
||||
) {
|
||||
Column(Modifier.padding(20.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Filled.AutoAwesome, null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
vm.tr("changelog_title"),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
val date = blocks.firstOrNull()?.str("date").orEmpty()
|
||||
|
|
@ -189,7 +167,7 @@ private fun ChangelogCard(vm: AppViewModel) {
|
|||
Text(
|
||||
date,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer.copy(alpha = 0.7f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -200,6 +178,7 @@ private fun ChangelogCard(vm: AppViewModel) {
|
|||
Text(
|
||||
"• $line",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
modifier = Modifier.padding(bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
|
|
@ -246,10 +225,6 @@ 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))
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
|
@ -314,75 +289,6 @@ private fun Metric(label: String, value: String, modifier: Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
/** Done and total exercises behind one row of a years screen, or null when there is no count. */
|
||||
fun routeProgress(vm: AppViewModel, r: Route): Pair<Int, Int>? {
|
||||
val c = vm.content
|
||||
val p = vm.progress
|
||||
fun tally(lessons: List<J>, done: (Int) -> Boolean) = lessons.count { done(it.int("id")) } to lessons.size
|
||||
return when (r) {
|
||||
Route.NetMap -> tally(c.netLessons, p::netDone)
|
||||
Route.Net2Map -> tally(c.itLessons("net2")) { p.courseDone("net2", it) }
|
||||
Route.Net3Map -> tally(c.itLessons("net3")) { p.courseDone("net3", it) }
|
||||
Route.Net4Map -> tally(c.itLessons("net4")) { p.courseDone("net4", it) }
|
||||
Route.HwMap -> tally(c.hw, p::hwDone)
|
||||
Route.Hw2Map -> tally(c.itLessons("hw2")) { p.courseDone("hw2", it) }
|
||||
Route.Hw3Map -> tally(c.itLessons("hw3")) { p.courseDone("hw3", it) }
|
||||
Route.Hw4Map -> tally(c.itLessons("hw4")) { p.courseDone("hw4", it) }
|
||||
Route.OnMap -> tally(c.on, p::onDone)
|
||||
Route.On2Map -> tally(c.on2, p::on2Done)
|
||||
Route.On3Map -> tally(c.on3, p::on3Done)
|
||||
Route.On4Map -> tally(c.on4, p::on4Done)
|
||||
is Route.EnMap -> tally(c.enYear(r.year)) { p.enDone(r.year, it) }
|
||||
is Route.DeMap -> tally(c.deYear(r.year)) { p.deDone(r.year, it) }
|
||||
Route.Roadmap -> {
|
||||
var done = 0
|
||||
var total = 0
|
||||
c.german.filter { it.bool("unlocked") }.forEach { u ->
|
||||
val n = u.strs("names").size
|
||||
total += n
|
||||
done += (1..n).count { p.germanDone(u.int("id"), it) }
|
||||
}
|
||||
done to total
|
||||
}
|
||||
Route.LitYears -> listOf(
|
||||
tally(c.lit, p::litDone), tally(c.lit2, p::lit2Done), tally(c.lit3, p::lit3Done), tally(c.lit4, p::lit4Done),
|
||||
).let { parts -> parts.sumOf { it.first } to parts.sumOf { it.second } }
|
||||
Route.LitMap -> tally(c.lit, p::litDone)
|
||||
Route.Lit2Map -> tally(c.lit2, p::lit2Done)
|
||||
Route.Lit3Map -> tally(c.lit3, p::lit3Done)
|
||||
Route.Lit4Map -> tally(c.lit4, p::lit4Done)
|
||||
Route.Mluvnice -> tally(c.mluvnice, p::mluvDone)
|
||||
Route.ChemMap -> tally(c.chem, p::chemDone)
|
||||
Route.BioMap -> tally(c.bio, p::bioDone)
|
||||
Route.Mat0Map -> tally(c.mat0, p::mat0Done)
|
||||
Route.MatMap -> tally(c.mat, p::matDone)
|
||||
Route.Mat2Map -> tally(c.mat2, p::mat2Done)
|
||||
Route.Mat3Map -> tally(c.mat3, p::mat3Done)
|
||||
Route.Mat4Map -> tally(c.mat4, p::mat4Done)
|
||||
Route.FyzMap -> tally(c.fyz, p::fyzDone)
|
||||
Route.Fyz2Map -> tally(c.fyz2, p::fyz2Done)
|
||||
Route.Fyz3Map -> tally(c.fyz3, p::fyz3Done)
|
||||
Route.Fyz4Map -> tally(c.fyz4, p::fyz4Done)
|
||||
Route.TgMap -> tally(c.tg, p::tgDone)
|
||||
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.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)
|
||||
Route.Cs4Map -> tally(c.cs4, p::cs4Done)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun subjectSum(vm: AppViewModel, s: J): ProgressSum {
|
||||
val sum = ProgressSum()
|
||||
when (s.str("target")) {
|
||||
|
|
@ -442,34 +348,6 @@ 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")) }
|
||||
}
|
||||
"csyears", "csmap", "cs2map", "cs3map", "cs4map" -> {
|
||||
sum.totalEx = vm.content.cs.size + vm.content.cs2.size + vm.content.cs3.size + vm.content.cs4.size
|
||||
sum.doneEx = vm.content.cs.count { vm.progress.csDone(it.int("id")) } +
|
||||
vm.content.cs2.count { vm.progress.cs2Done(it.int("id")) } +
|
||||
vm.content.cs3.count { vm.progress.cs3Done(it.int("id")) } +
|
||||
vm.content.cs4.count { vm.progress.cs4Done(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")) }
|
||||
}
|
||||
"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")) }
|
||||
}
|
||||
"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")) } +
|
||||
|
|
@ -771,86 +649,6 @@ 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")
|
||||
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")
|
||||
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("Programování"), vm.tr("search_lesson"), "csyears", extra = "csharp c#")
|
||||
add(vm.tr("cs_year1"), vm.tr("search_lesson"), "csmap", extra = "rocnik")
|
||||
add(vm.tr("cs_year2"), vm.tr("search_lesson"), "cs2map", extra = "rocnik")
|
||||
add(vm.tr("cs_year3"), vm.tr("search_lesson"), "cs3map", extra = "rocnik")
|
||||
add(vm.tr("cs_year4"), vm.tr("search_lesson"), "cs4map", extra = "rocnik")
|
||||
vm.content.cs.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "csunit${l.int("id")}", extra = "csharp")
|
||||
}
|
||||
vm.content.cs2.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "cs2unit${l.int("id")}", extra = "csharp")
|
||||
}
|
||||
vm.content.cs3.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "cs3unit${l.int("id")}", extra = "csharp")
|
||||
}
|
||||
vm.content.cs4.forEach { l ->
|
||||
add(vm.tr(l.str("titleKey")), vm.tr("search_lesson"), "cs4unit${l.int("id")}", extra = "csharp")
|
||||
}
|
||||
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 ->
|
||||
|
|
@ -947,10 +745,10 @@ fun NetYearsScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("net_years_title"), vm.tr("net_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("net_year1"), subtitle = vm.tr("net_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.NetMap)) { vm.go(Route.NetMap) }
|
||||
NavRow(title = vm.tr("net_year2"), subtitle = vm.tr("net2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Net2Map)) { vm.go(Route.Net2Map) }
|
||||
NavRow(title = vm.tr("net_year3"), subtitle = vm.tr("net3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Net3Map)) { vm.go(Route.Net3Map) }
|
||||
NavRow(title = vm.tr("net_year4"), subtitle = vm.tr("net4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Net4Map)) { vm.go(Route.Net4Map) }
|
||||
NavRow(title = vm.tr("net_year1"), subtitle = vm.tr("net_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.NetMap) }
|
||||
NavRow(title = vm.tr("net_year2"), subtitle = vm.tr("net2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Net2Map) }
|
||||
NavRow(title = vm.tr("net_year3"), subtitle = vm.tr("net3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Net3Map) }
|
||||
NavRow(title = vm.tr("net_year4"), subtitle = vm.tr("net4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Net4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -961,10 +759,10 @@ fun HwYearsScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("Technické vybavení"), vm.tr("hw_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("hw_year1"), subtitle = vm.tr("hw_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.HwMap)) { vm.go(Route.HwMap) }
|
||||
NavRow(title = vm.tr("hw_year2"), subtitle = vm.tr("hw2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Hw2Map)) { vm.go(Route.Hw2Map) }
|
||||
NavRow(title = vm.tr("hw_year3"), subtitle = vm.tr("hw3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Hw3Map)) { vm.go(Route.Hw3Map) }
|
||||
NavRow(title = vm.tr("hw_year4"), subtitle = vm.tr("hw4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Hw4Map)) { vm.go(Route.Hw4Map) }
|
||||
NavRow(title = vm.tr("hw_year1"), subtitle = vm.tr("hw_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.HwMap) }
|
||||
NavRow(title = vm.tr("hw_year2"), subtitle = vm.tr("hw2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Hw2Map) }
|
||||
NavRow(title = vm.tr("hw_year3"), subtitle = vm.tr("hw3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Hw3Map) }
|
||||
NavRow(title = vm.tr("hw_year4"), subtitle = vm.tr("hw4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Hw4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -975,7 +773,7 @@ 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 = { LeadingBadge("U") }, progress = routeProgress(vm, Route.Roadmap)) {
|
||||
NavRow(title = vm.tr("de_book_title"), subtitle = vm.tr("de_book_sub"), leading = { Text("U", style = MaterialTheme.typography.titleMedium) }) {
|
||||
vm.go(Route.Roadmap)
|
||||
}
|
||||
}
|
||||
|
|
@ -984,8 +782,7 @@ fun DeHomeScreen(vm: AppViewModel) {
|
|||
NavRow(
|
||||
title = vm.tr("de_year$year"),
|
||||
subtitle = vm.tr("de_y${year}_sub"),
|
||||
leading = { LeadingBadge("$year") },
|
||||
progress = routeProgress(vm, Route.DeMap(year)),
|
||||
leading = { Text("$year.", style = MaterialTheme.typography.titleMedium) },
|
||||
) { vm.go(Route.DeMap(year)) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1001,8 +798,7 @@ fun EnYearsScreen(vm: AppViewModel) {
|
|||
NavRow(
|
||||
title = vm.tr("en_year$year"),
|
||||
subtitle = vm.tr("en_y${year}_sub"),
|
||||
leading = { LeadingBadge("$year") },
|
||||
progress = routeProgress(vm, Route.EnMap(year)),
|
||||
leading = { Text("$year.", style = MaterialTheme.typography.titleMedium) },
|
||||
) { vm.go(Route.EnMap(year)) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1014,10 +810,10 @@ fun OnYearsScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("Občanská nauka"), vm.tr("on_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("on_year1"), subtitle = vm.tr("on_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.OnMap)) { vm.go(Route.OnMap) }
|
||||
NavRow(title = vm.tr("on_year2"), subtitle = vm.tr("on2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.On2Map)) { vm.go(Route.On2Map) }
|
||||
NavRow(title = vm.tr("on_year3"), subtitle = vm.tr("on3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.On3Map)) { vm.go(Route.On3Map) }
|
||||
NavRow(title = vm.tr("on_year4"), subtitle = vm.tr("on4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.On4Map)) { vm.go(Route.On4Map) }
|
||||
NavRow(title = vm.tr("on_year1"), subtitle = vm.tr("on_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.OnMap) }
|
||||
NavRow(title = vm.tr("on_year2"), subtitle = vm.tr("on2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.On2Map) }
|
||||
NavRow(title = vm.tr("on_year3"), subtitle = vm.tr("on3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.On3Map) }
|
||||
NavRow(title = vm.tr("on_year4"), subtitle = vm.tr("on4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.On4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1028,10 +824,10 @@ fun LitYearsScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("Literatura"), vm.tr("lit_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("lit_year1"), subtitle = vm.tr("lit_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.LitMap)) { vm.go(Route.LitMap) }
|
||||
NavRow(title = vm.tr("lit_year2"), subtitle = vm.tr("lit2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Lit2Map)) { vm.go(Route.Lit2Map) }
|
||||
NavRow(title = vm.tr("lit_year3"), subtitle = vm.tr("lit3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Lit3Map)) { vm.go(Route.Lit3Map) }
|
||||
NavRow(title = vm.tr("lit_year4"), subtitle = vm.tr("lit4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Lit4Map)) { vm.go(Route.Lit4Map) }
|
||||
NavRow(title = vm.tr("lit_year1"), subtitle = vm.tr("lit_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.LitMap) }
|
||||
NavRow(title = vm.tr("lit_year2"), subtitle = vm.tr("lit2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit2Map) }
|
||||
NavRow(title = vm.tr("lit_year3"), subtitle = vm.tr("lit3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit3Map) }
|
||||
NavRow(title = vm.tr("lit_year4"), subtitle = vm.tr("lit4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Lit4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1042,67 +838,11 @@ fun MatYearsScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("Matematika"), vm.tr("mat_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("mat0_year"), subtitle = vm.tr("mat0_sub"), leading = { LeadingBadge("ZŠ") }, progress = routeProgress(vm, Route.Mat0Map)) { vm.go(Route.Mat0Map) }
|
||||
NavRow(title = vm.tr("mat_year1"), subtitle = vm.tr("mat_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.MatMap)) { vm.go(Route.MatMap) }
|
||||
NavRow(title = vm.tr("mat_year2"), subtitle = vm.tr("mat2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Mat2Map)) { vm.go(Route.Mat2Map) }
|
||||
NavRow(title = vm.tr("mat_year3"), subtitle = vm.tr("mat3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Mat3Map)) { vm.go(Route.Mat3Map) }
|
||||
NavRow(title = vm.tr("mat_year4"), subtitle = vm.tr("mat4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Mat4Map)) { vm.go(Route.Mat4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CsYearsScreen(vm: AppViewModel) {
|
||||
DetailScaffold(vm, vm.tr("Programování"), vm.tr("cs_years_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("cs_year1"), subtitle = vm.tr("cs_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.CsMap)) { vm.go(Route.CsMap) }
|
||||
NavRow(title = vm.tr("cs_year2"), subtitle = vm.tr("cs2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Cs2Map)) { vm.go(Route.Cs2Map) }
|
||||
NavRow(title = vm.tr("cs_year3"), subtitle = vm.tr("cs3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Cs3Map)) { vm.go(Route.Cs3Map) }
|
||||
NavRow(title = vm.tr("cs_year4"), subtitle = vm.tr("cs4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Cs4Map)) { vm.go(Route.Cs4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 ->
|
||||
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 ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(title = vm.tr("tg_year1"), subtitle = vm.tr("tg_sub"), leading = { LeadingBadge("1") }, progress = routeProgress(vm, Route.TgMap)) { vm.go(Route.TgMap) }
|
||||
NavRow(title = vm.tr("tg_year2"), subtitle = vm.tr("tg2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Tg2Map)) { vm.go(Route.Tg2Map) }
|
||||
NavRow(title = vm.tr("tg_year3"), subtitle = vm.tr("tg3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Tg3Map)) { vm.go(Route.Tg3Map) }
|
||||
NavRow(title = vm.tr("tg_year4"), subtitle = vm.tr("tg4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Tg4Map)) { vm.go(Route.Tg4Map) }
|
||||
NavRow(title = vm.tr("mat0_year"), subtitle = vm.tr("mat0_sub"), leading = { Text("ZŠ", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Mat0Map) }
|
||||
NavRow(title = vm.tr("mat_year1"), subtitle = vm.tr("mat_sub"), leading = { Text("1.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.MatMap) }
|
||||
NavRow(title = vm.tr("mat_year2"), subtitle = vm.tr("mat2_sub"), leading = { Text("2.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Mat2Map) }
|
||||
NavRow(title = vm.tr("mat_year3"), subtitle = vm.tr("mat3_sub"), leading = { Text("3.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Mat3Map) }
|
||||
NavRow(title = vm.tr("mat_year4"), subtitle = vm.tr("mat4_sub"), leading = { Text("4.", style = MaterialTheme.typography.titleMedium) }) { vm.go(Route.Mat4Map) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1113,10 +853,10 @@ 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 = { LeadingBadge("1") }, progress = routeProgress(vm, Route.FyzMap)) { vm.go(Route.FyzMap) }
|
||||
NavRow(title = vm.tr("fyz_year2"), subtitle = vm.tr("fyz2_sub"), leading = { LeadingBadge("2") }, progress = routeProgress(vm, Route.Fyz2Map)) { vm.go(Route.Fyz2Map) }
|
||||
NavRow(title = vm.tr("fyz_year3"), subtitle = vm.tr("fyz3_sub"), leading = { LeadingBadge("3") }, progress = routeProgress(vm, Route.Fyz3Map)) { vm.go(Route.Fyz3Map) }
|
||||
NavRow(title = vm.tr("fyz_year4"), subtitle = vm.tr("fyz4_sub"), leading = { LeadingBadge("4") }, progress = routeProgress(vm, Route.Fyz4Map)) { vm.go(Route.Fyz4Map) }
|
||||
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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1130,17 +870,11 @@ fun SciMapScreen(vm: AppViewModel) {
|
|||
NavRow(
|
||||
title = vm.tr("Chemie"),
|
||||
subtitle = vm.tr("chem_sub"),
|
||||
leading = { LeadingIcon(Icons.Filled.Science) },
|
||||
progress = routeProgress(vm, Route.ChemMap),
|
||||
leading = { Icon(Icons.Filled.Science, null, tint = MaterialTheme.colorScheme.primary) },
|
||||
) { vm.go(Route.ChemMap) }
|
||||
}
|
||||
item {
|
||||
NavRow(
|
||||
title = vm.tr("Biologie"),
|
||||
subtitle = vm.tr("bio_sub"),
|
||||
leading = { LeadingIcon(Icons.Filled.Eco) },
|
||||
progress = routeProgress(vm, Route.BioMap),
|
||||
) { vm.go(Route.BioMap) }
|
||||
NavRow(title = vm.tr("Biologie"), subtitle = vm.tr("bio_sub")) { vm.go(Route.BioMap) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1151,26 +885,20 @@ fun CzechMapScreen(vm: AppViewModel) {
|
|||
DetailScaffold(vm, vm.tr("Český jazyk a literatura"), vm.tr("czech_sub")) { inner ->
|
||||
LazyColumn(contentPadding = PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding() + 16.dp)) {
|
||||
item {
|
||||
NavRow(
|
||||
title = vm.tr("Literatura"),
|
||||
subtitle = vm.tr("lit_years_sub"),
|
||||
leading = { LeadingIcon(Icons.Filled.AutoStories) },
|
||||
progress = routeProgress(vm, Route.LitYears),
|
||||
) { vm.go(Route.LitYears) }
|
||||
NavRow(title = vm.tr("Literatura"), subtitle = vm.tr("lit_years_sub")) { vm.go(Route.LitYears) }
|
||||
}
|
||||
item {
|
||||
NavRow(
|
||||
title = vm.tr("Mluvnice"),
|
||||
subtitle = vm.tr("mluv_sub"),
|
||||
leading = { LeadingIcon(Icons.Filled.FormatListNumbered) },
|
||||
progress = routeProgress(vm, Route.Mluvnice),
|
||||
leading = { Icon(Icons.Filled.FormatListNumbered, null, tint = MaterialTheme.colorScheme.primary) },
|
||||
) { vm.go(Route.Mluvnice) }
|
||||
}
|
||||
item {
|
||||
NavRow(
|
||||
title = vm.tr("Maturitní četba"),
|
||||
subtitle = vm.tr("reading_sub"),
|
||||
leading = { LeadingIcon(Icons.AutoMirrored.Filled.MenuBook) },
|
||||
leading = { Icon(Icons.AutoMirrored.Filled.MenuBook, null, tint = MaterialTheme.colorScheme.primary) },
|
||||
) { vm.go(Route.ReadingList) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1233,52 +961,6 @@ fun BookScreen(vm: AppViewModel, id: String) {
|
|||
// ---------------------------------------------------------------------------
|
||||
// Lesson slides
|
||||
|
||||
/** One explanation slide: label, title, tip and numbered points. */
|
||||
@Composable
|
||||
fun SlideContent(slide: J) {
|
||||
Column {
|
||||
Text(slide.str("kicker"), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
Text(slide.str("title"), style = MaterialTheme.typography.headlineSmall, modifier = Modifier.padding(top = 4.dp, bottom = 12.dp))
|
||||
slide.strOrNull("tip")?.let { tip ->
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer),
|
||||
) {
|
||||
Row(Modifier.padding(14.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Outlined.Lightbulb, null, tint = MaterialTheme.colorScheme.onSecondaryContainer)
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Text(tip, style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
slide.strs("lines").forEachIndexed { index, line ->
|
||||
val numbered = Regex("""^(\d+)\.\s+(.*)$""").find(line)
|
||||
val badge = numbered?.groupValues?.get(1) ?: "${index + 1}"
|
||||
val text = numbered?.groupValues?.get(2) ?: line
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.45f), androidx.compose.foundation.shape.RoundedCornerShape(16.dp))
|
||||
.padding(horizontal = 14.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(top = 2.dp)
|
||||
.size(28.dp)
|
||||
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.14f), CircleShape),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(badge, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(text, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun SlidesScreen(
|
||||
|
|
@ -1329,13 +1011,52 @@ fun SlidesScreen(
|
|||
},
|
||||
) { inner ->
|
||||
HorizontalPager(state = pager, modifier = Modifier.fillMaxSize().padding(inner)) { page ->
|
||||
val slide = slides[page]
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
) {
|
||||
SlideContent(slides[page])
|
||||
Text(slide.str("kicker"), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
Text(slide.str("title"), style = MaterialTheme.typography.headlineSmall, modifier = Modifier.padding(top = 4.dp, bottom = 12.dp))
|
||||
slide.strOrNull("tip")?.let { tip ->
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer),
|
||||
) {
|
||||
Row(Modifier.padding(14.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Outlined.Lightbulb, null, tint = MaterialTheme.colorScheme.onSecondaryContainer)
|
||||
Spacer(Modifier.width(10.dp))
|
||||
Text(tip, style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
slide.strs("lines").forEachIndexed { index, line ->
|
||||
val numbered = Regex("""^(\d+)\.\s+(.*)$""").find(line)
|
||||
val badge = numbered?.groupValues?.get(1) ?: "${index + 1}"
|
||||
val text = numbered?.groupValues?.get(2) ?: line
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.45f), androidx.compose.foundation.shape.RoundedCornerShape(16.dp))
|
||||
.padding(horizontal = 14.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(top = 2.dp)
|
||||
.size(28.dp)
|
||||
.background(MaterialTheme.colorScheme.primary.copy(alpha = 0.14f), CircleShape),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(badge, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(text, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(24.dp))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 134 KiB |
BIN
assets/germanlection.png
Normal file
BIN
assets/germanlection.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
assets/home.png
BIN
assets/home.png
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 197 KiB |
BIN
assets/subjectsscreen.png
Normal file
BIN
assets/subjectsscreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
assets/welcomescreen.png
Normal file
BIN
assets/welcomescreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
|
|
@ -18,7 +18,7 @@ Skript vypíše počet lekcí, nebo chyby s cestou a číslem řádku
|
|||
|
||||
| Složka | Obsah |
|
||||
|---|---|
|
||||
| `pocitacove-site/`, `technicke-vybaveni/`, `technicka-grafika/`, `prezentacni-grafika/`, `programove-vybaveni/`, `programovani/`, `obcanska-nauka/`, `fyzika/` | `N-rocnik/`, v nich lekce |
|
||||
| `pocitacove-site/`, `technicke-vybaveni/`, `obcanska-nauka/`, `fyzika/` | `N-rocnik/`, v nich lekce |
|
||||
| `prirodni-vedy/chemie`, `prirodni-vedy/biologie` | lekce |
|
||||
| `cestina/literatura/N-rocnik` | lekce literatury |
|
||||
| `cestina/mluvnice` | cvičení z mluvnice |
|
||||
|
|
@ -97,7 +97,7 @@ a smažte `puvodni`.
|
|||
|
||||
## Běžná lekce
|
||||
|
||||
Sítě, hardware, technická grafika, prezentační grafika, programové vybavení, občanka, literatura, chemie, biologie, fyzika.
|
||||
Sítě, hardware, občanka, literatura, chemie, biologie, fyzika.
|
||||
|
||||
```md
|
||||
---
|
||||
|
|
|
|||
|
|
@ -5,30 +5,6 @@
|
|||
# cs: bullet
|
||||
# en: bullet
|
||||
|
||||
--- 2026-10-11
|
||||
cs: Programové vybavení: Windows, Word, Excel, Access, MySQL a správa účtů
|
||||
cs: Čtyři ročníky, od licence a složek po WordPress, Power BI a zásady
|
||||
en: Software: Windows, Word, Excel, Access, MySQL and account administration
|
||||
en: Four years, from licences and folders to WordPress, Power BI and policy
|
||||
|
||||
--- 2026-10-11
|
||||
cs: Prezentační grafika: Photoshop, Premiere Pro a další programy Adobe
|
||||
cs: Čtyři ročníky, v každé lekci postup, zadání a kvíz
|
||||
en: Presentation graphics: Photoshop, Premiere Pro and the other Adobe apps
|
||||
en: Four years, and every lesson has a method, an assignment and a quiz
|
||||
|
||||
--- 2026-10-11
|
||||
cs: Programování: čtyři ročníky C#, od výpisu po LINQ a async
|
||||
cs: Kód se píše v lekci a hned vedle se spustí
|
||||
en: Programming: four years of C#, from output to LINQ and async
|
||||
en: You write the code in the lesson and run it right beside the text
|
||||
|
||||
--- 2026-10-11
|
||||
cs: Technická grafika: čtyři ročníky AutoCADu, od výkresu po 3D
|
||||
cs: V každé lekci je postup, zadání s rozměry a kvíz
|
||||
en: Technical graphics: four years of AutoCAD, from the drawing sheet to 3D
|
||||
en: Every lesson has a method, a dimensioned assignment and a quiz
|
||||
|
||||
--- 2026-10-07
|
||||
cs: Sítě a technické vybavení: doplněné 2. až 4. ročníky, v každém 8 lekcí
|
||||
cs: Výklad a kvíz od VLAN a sestavení počítače po maturitu
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
| Matematika | Matematika | Mathematics | function | matyears | ano |
|
||||
| Fyzika | Fyzika | Physics | bolt | fyzyears | ano |
|
||||
| Základy přírodních věd | Základy přírodních věd | Fundamentals of Natural Sciences | flask | scimap | ano |
|
||||
| Technická grafika | Technická grafika | Technical Graphics | ruler | tgyears | ano |
|
||||
| Prezentační grafika | Prezentační grafika | Presentation Graphics | brush | pgyears | ano |
|
||||
| Programování | Programování | Programming | code | csyears | ano |
|
||||
| Programové vybavení | Programové vybavení | Software | apps | swyears | ano |
|
||||
| Technická grafika | Technická grafika | Technical Drawing | lock | | ne |
|
||||
| Prezentační grafika | Prezentační grafika | Presentation Graphics | lock | | ne |
|
||||
| Programování | Programování | Programming | lock | | ne |
|
||||
| Programové vybavení | Programové vybavení | Software | lock | | ne |
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|---|---|---|
|
||||
| welcome_kicker | Graduately | Graduately |
|
||||
| welcome_title | Maturita?\nTo dáme. | Maturita?\nWe've got this. |
|
||||
| welcome_body | Procvičování k maturitě v jednom okně. Česky i anglicky, napsané studenty ze SSŠVT. | Exam practice in one window. Czech and English, written by students from SSŠVT. |
|
||||
| welcome_body | Procvičování k maturitě v jednom okně. Česky i anglicky, napsané v C studenty ze SSŠVT. | Exam practice in one window. Czech and English, written in C by students from SSŠVT. |
|
||||
| welcome_body_android | Procvičování k maturitě v telefonu. Česky i anglicky, stejný obsah jako na počítači. | Exam practice on your phone. Czech and English, the same content as on the computer. |
|
||||
| welcome_body_desktop | Procvičování k maturitě na počítači. Česky i anglicky, stejný obsah jako v telefonu. | Exam practice on your computer. Czech and English, the same content as on your phone. |
|
||||
| welcome_body_ios | Nativní procvičování na iPhonu. Česky i anglicky, stejný obsah, rozhraní podle iOS. | Native exam practice on iPhone. Czech and English, the same content, adapted to iOS. |
|
||||
|
|
@ -117,7 +117,6 @@
|
|||
| search_page | Stránka | Page |
|
||||
| search_home | Úvod | Welcome |
|
||||
| subjects_title | Předměty | Subjects |
|
||||
| subjects_soon | Připravujeme | Coming soon |
|
||||
| subjects_sub | Otevřený předmět spustí učební cestu. Zamčené zatím jen čekají. | An open subject opens its path. Locked ones are placeholders for now. |
|
||||
|
||||
# Čeština
|
||||
|
|
@ -230,73 +229,6 @@
|
|||
| 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. |
|
||||
|
||||
# Technická grafika
|
||||
|
||||
| Klíč | Česky | Anglicky |
|
||||
|---|---|---|
|
||||
| tg_years_sub | Čtyři ročníky AutoCADu, od výkresu po maturitní zadání. | Four years of AutoCAD, from the drawing sheet to the exam project. |
|
||||
| tg_year1 | 1. ročník | Year 1 |
|
||||
| tg_year2 | 2. ročník | Year 2 |
|
||||
| tg_year3 | 3. ročník | Year 3 |
|
||||
| tg_year4 | 4. ročník | Year 4 |
|
||||
| tg_sub | Výkres, souřadnice a první příkazy. | The sheet, coordinates and the first commands. |
|
||||
| tg2_sub | Úpravy, hladiny, šrafy a kóty. | Editing, layers, hatches and dimensions. |
|
||||
| tg3_sub | Pohledy, řezy, bloky a tisk. | Views, sections, blocks and plotting. |
|
||||
| tg4_sub | 3D model a výkres k maturitě. | A 3D model and the exam drawing. |
|
||||
|
||||
# Prezentační grafika
|
||||
|
||||
| Klíč | Česky | Anglicky |
|
||||
|---|---|---|
|
||||
| pg_years_sub | Od Photoshopu přes Premiere Pro k Illustratoru, After Effects a InDesignu. | From Photoshop through Premiere Pro to Illustrator, After Effects and InDesign. |
|
||||
| pg_year1 | 1. ročník | Year 1 |
|
||||
| pg_year2 | 2. ročník | Year 2 |
|
||||
| pg_year3 | 3. ročník | Year 3 |
|
||||
| pg_year4 | 4. ročník | Year 4 |
|
||||
| pg_sub | Photoshop: pixely, vrstvy, výběr a retuš. | Photoshop: pixels, layers, selections and retouching. |
|
||||
| pg2_sub | Masky, barvy, plakát a export. | Masks, colour, a poster and export. |
|
||||
| pg3_sub | Premiere Pro: střih, zvuk, titulky a video. | Premiere Pro: the cut, sound, titles and the video. |
|
||||
| pg4_sub | Illustrator, After Effects, InDesign a maturitní kampaň. | Illustrator, After Effects, InDesign and the exam campaign. |
|
||||
|
||||
# Programové vybavení
|
||||
|
||||
| Klíč | Česky | Anglicky |
|
||||
|---|---|---|
|
||||
| sw_years_sub | Operační systém, Office, databáze a správa Windows. | The operating system, Office, databases and Windows administration. |
|
||||
| sw_year1 | 1. ročník | Year 1 |
|
||||
| sw_year2 | 2. ročník | Year 2 |
|
||||
| sw_year3 | 3. ročník | Year 3 |
|
||||
| sw_year4 | 4. ročník | Year 4 |
|
||||
| sw_sub | Software, licence a práce ve Windows. | Software, licences and working in Windows. |
|
||||
| sw2_sub | Word a Excel: dokument, vzorce a graf. | Word and Excel: a document, formulas and a chart. |
|
||||
| sw3_sub | Access a MySQL: tabulky, dotazy a vztahy. | Access and MySQL: tables, queries and relationships. |
|
||||
| sw4_sub | WordPress, Power BI, dávkové soubory a zásady. | WordPress, Power BI, batch files and policy. |
|
||||
|
||||
# Programování
|
||||
|
||||
| Klíč | Česky | Anglicky |
|
||||
|---|---|---|
|
||||
| cs_years_sub | C# od prvního výpisu po pokročilejší nástroje. Kód se píše a spouští vedle výkladu. | C# from the first line of output to the later tools. You write the code and run it beside the lesson. |
|
||||
| cs_year1 | 1. ročník | Year 1 |
|
||||
| cs_year2 | 2. ročník | Year 2 |
|
||||
| cs_year3 | 3. ročník | Year 3 |
|
||||
| cs_year4 | 4. ročník | Year 4 |
|
||||
| cs_sub | Výpis, proměnné, typy, operátory a řetězce. | Output, variables, types, operators and strings. |
|
||||
| cs2_sub | Podmínky, cykly, pole a metody. | Conditions, loops, arrays and methods. |
|
||||
| cs3_sub | Třídy, dědičnost, rozhraní a výčty. | Classes, inheritance, interfaces and enums. |
|
||||
| cs4_sub | Výjimky, kolekce, LINQ, soubory a async. | Exceptions, collections, LINQ, files and async. |
|
||||
| cs_code | Kód | Code |
|
||||
| cs_output | Výstup | Output |
|
||||
| cs_stdin | Vstup pro Console.ReadLine | Input for Console.ReadLine |
|
||||
| cs_run | Spustit | Run |
|
||||
| cs_reset | Obnovit ukázku | Reset example |
|
||||
| cs_running | Překládám… | Compiling… |
|
||||
| cs_done | Hotovo | Done |
|
||||
| cs_failed | Chyba | Error |
|
||||
| cs_empty | Zatím nic. Upravte kód a spusťte ho. | Nothing yet. Edit the code and run it. |
|
||||
| cs_timeout | Program běžel příliš dlouho a byl zastaven. | The program ran too long and was stopped. |
|
||||
| cs_unavailable | Tady C# nespustíte. Na počítači s nainstalovaným .NET se výstup objeví vedle kódu. | C# cannot run here. On a computer with .NET installed the output appears beside the code. |
|
||||
|
||||
# Angličtina a němčina
|
||||
|
||||
| Klíč | Česky | Anglicky |
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Bitmap and vector
|
||||
popis: When a picture is pixels and when it is curves.
|
||||
nazev_cviceni: Quiz: bitmap and vector
|
||||
nadpis_kvizu: Tell what goes soft when you enlarge it
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-bitmapa-a-vektor
|
||||
nazev: Bitmapa a vektor
|
||||
popis: Kdy je obrázek z pixelů a kdy z křivek.
|
||||
nazev_cviceni: Kvíz: bitmapa a vektor
|
||||
nadpis_kvizu: Poznejte, co se při zvětšení rozmaže
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Dva druhy obrázku
|
||||
*Pixel a křivka*
|
||||
|
||||
- Bitmapa je mřížka pixelů. Fotka z telefonu je bitmapa a otevírá se ve Photoshopu.
|
||||
- Vektor je popis křivek. Logo a ikona se kreslí v Illustratoru a při zvětšení zůstávají ostré.
|
||||
- Photoshop umí obojí, ale fotku v něm nepřekreslíte na křivky. Naopak Illustrator není na retuš.
|
||||
- Když nevíte, který soubor je který, přibližte ho na 400 %. Bitmapa ukáže čtverečky.
|
||||
|
||||
> Tip: Přípona napoví: JPG a PNG jsou bitmapa, SVG a AI jsou vektor. PSD může obsahovat obojí.
|
||||
|
||||
## Co se stane při zvětšení
|
||||
*Kvalita*
|
||||
|
||||
- Bitmapu 800 px širokou nelze vytisknout ostře na velký plakát. Pixely se jen roztáhnou.
|
||||
- Vektor se zvětší přepočtem křivky. Hranu má pořád hladkou.
|
||||
- Zmenšení bitmapy pixely zahodí. Zvětšení zpět je nevrátí.
|
||||
- Proto se logo neukládá jako malé JPG a fotka se nefotí až ve chvíli, kdy už je pozdě.
|
||||
|
||||
> Tip: Jednou zmenšenou fotku už nedostanete zpátky. Nechte si původní soubor.
|
||||
|
||||
## Který program kdy
|
||||
*Volba*
|
||||
|
||||
- Fotku, retuš a plakát z fotografie berte do Photoshopu.
|
||||
- Logo, piktogram a čisté tvary berte do Illustratoru. Ten přijde ve čtvrtém ročníku.
|
||||
- Video nepatří ani do jednoho. Na střih je Premiere Pro, ve třeťáku.
|
||||
- Hotové logo z Illustratoru se do Photoshopu vloží jako chytrý objekt, ne jako malý JPG.
|
||||
|
||||
> Tip: Chytrý objekt drží původní kvalitu. ZJPG-ované logo už křivky nemá.
|
||||
|
||||
## Zadání: porovnání
|
||||
*Cvičení*
|
||||
|
||||
- Otevřete ve Photoshopu fotku a přibližte ji na 400 %. Okraj předmětu se rozpadne na pixely.
|
||||
- Stejný pohled udělejte u loga ve formátu SVG nebo AI. Hrana zůstane hladká.
|
||||
- Do sešitu napište, který soubor je bitmapa a který vektor, a proč.
|
||||
- Fotku uložte jako porovnani.psd. Logo nepřevádějte na JPG.
|
||||
|
||||
> Tip: Když SVG ve Photoshopu rastruje, zaškrtněte velký rozměr. Malý náhled nic neukáže.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co uvidíte na fotce při zvětšení na 400 %?
|
||||
- Hladkou křivku bez pixelů
|
||||
- [x] Čtverečky pixelů
|
||||
- Jen ořezové značky
|
||||
- Prázdné plátno
|
||||
> Fotka je bitmapa. Zvětšení roztáhne pixely, křivku z ní neudělá.
|
||||
|
||||
## Kam patří nové logo školy?
|
||||
- Do Photoshopu jako malé JPG
|
||||
- [x] Do Illustratoru jako křivky
|
||||
- Do Premiere jako titulek
|
||||
- Do JPG o šířce 80 px
|
||||
> Logo se zvětšuje na plakát i na vizitku. Křivka to zvládne, malé JPG ne.
|
||||
|
||||
## Co se stane, když bitmapu zmenšíte a pak znovu zvětšíte?
|
||||
- Pixely se vrátí
|
||||
- [x] Ostrost se ztratí
|
||||
- Soubor se stane vektorem
|
||||
- Přibude spadávka
|
||||
> Zmenšení pixely zahodí. Zvětšení je neumí vymyslet zpět.
|
||||
|
||||
## Jak se má logo vložit do plakátu ve Photoshopu?
|
||||
- Jako JPG 80 px
|
||||
- [x] Jako chytrý objekt
|
||||
- Vložením snímku obrazovky
|
||||
- Jako zvuková stopa
|
||||
> Chytrý objekt podrží zdroj. JPG logo už nejde zvětšit bez rozmazání.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Resolution and colour
|
||||
popis: Pixels, 300 ppi for print, and RGB against CMYK.
|
||||
nazev_cviceni: Quiz: resolution and colour
|
||||
nadpis_kvizu: Pick the size and the colour mode
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-rozliseni-a-barva
|
||||
nazev: Rozlišení a barva
|
||||
popis: Pixely, tisk 300 ppi a rozdíl mezi RGB a CMYK.
|
||||
nazev_cviceni: Kvíz: rozlišení a barva
|
||||
nadpis_kvizu: Vyberte rozměr a barevný režim
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Pixely a tisk
|
||||
*Rozlišení*
|
||||
|
||||
- Rozměr v pixelech říká, kolik bodů obrázek má. 1920 × 1080 je Full HD.
|
||||
- Rozlišení v ppi říká, kolik pixelů připadne na palec při tisku.
|
||||
- Na obrazovku stačí 72 ppi. Do tisku se připravuje 300 ppi.
|
||||
- Formát A4 při 300 ppi má zhruba 2480 × 3508 px. To je 210 × 297 mm.
|
||||
|
||||
> Tip: 72 ppi na plakát nestačí. 300 ppi na web je zbytečně velký soubor.
|
||||
|
||||
## RGB a CMYK
|
||||
*Režim*
|
||||
|
||||
- RGB je světlo obrazovky: červená, zelená a modrá. Web i video jsou RGB.
|
||||
- CMYK jsou tiskové barvy: azurová, purpurová, žlutá a černá.
|
||||
- Barva, která svítí na monitoru, se v tisku často smrskne. Základní červená v CMYK zešedne.
|
||||
- Fotku upravujte v RGB. Do CMYK ji převádějte až při exportu pro tiskárnu.
|
||||
|
||||
> Tip: Když tiskárna chce PDF v CMYK, převod nechte na export. Pracovní soubor zůstane RGB.
|
||||
|
||||
## Nový dokument
|
||||
*Plátno*
|
||||
|
||||
- Webový obrázek: 1920 × 1080 px, 72 ppi, RGB, 8 bitů na kanál.
|
||||
- Tiskové A4: předvolba A4, 300 ppi, RGB. Ořez řešte až u plakátu ve druháku.
|
||||
- Pozadí nové školní práce nechte průhledné, ať pod ním není bílá omylem.
|
||||
- Pojmenujte dokument hned. nazev-skoly.psd je lepší než Bez názvu-1.
|
||||
|
||||
> Tip: 8 bitů na kanál je běžná fotka. 16 bitů nechte na složitou retuš, soubor je větší.
|
||||
|
||||
## Zadání: dva dokumenty
|
||||
*Cvičení*
|
||||
|
||||
- Založte web.psd: 1920 × 1080 px, 72 ppi, RGB, 8 bitů.
|
||||
- Založte tisk-a4.psd: A4, 300 ppi, RGB, 8 bitů.
|
||||
- U obou zapište do vrstvy poznámku s rozměrem v pixelech. U A4 to má být kolem 2480 × 3508.
|
||||
- Oba soubory uložte jako PSD. Zatím je neexportujte do JPG.
|
||||
|
||||
> Tip: Obraz > Velikost obrazu ukáže pixely i centimetry. Jednotky si přepněte, ať čtete obojí.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jaké rozlišení se bere pro tisk?
|
||||
- 72 ppi
|
||||
- [x] 300 ppi
|
||||
- 25 sn/s
|
||||
- 8 bitů
|
||||
> 72 ppi je obrazovka. Tisk chce 300 ppi, jinak je fotka na papíře měkká.
|
||||
|
||||
## Který režim patří na web a do videa?
|
||||
- CMYK
|
||||
- [x] RGB
|
||||
- Jen černá
|
||||
- Spadávka
|
||||
> Obrazovka skládá barvu ze světla RGB. CMYK je pro tiskárnu.
|
||||
|
||||
## Kolik pixelů má zhruba A4 při 300 ppi?
|
||||
- 1920 × 1080
|
||||
- [x] 2480 × 3508
|
||||
- 210 × 297
|
||||
- 800 × 600
|
||||
> 210 × 297 mm je rozměr papíru. V pixelech při 300 ppi je to asi 2480 × 3508.
|
||||
|
||||
## Kdy se má fotka převést do CMYK?
|
||||
- Hned po otevření
|
||||
- [x] Až při exportu pro tisk
|
||||
- Před každou retuší
|
||||
- Nikdy, ani pro tisk
|
||||
> Úpravy nechte v RGB. CMYK je výstup pro tiskárnu, ne pracovní soubor.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: The Photoshop workspace
|
||||
popis: Panels, zoom and saving a PSD.
|
||||
nazev_cviceni: Quiz: the workspace
|
||||
nadpis_kvizu: Find the shortcut and the right file
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-prostredi
|
||||
nazev: Prostředí Photoshopu
|
||||
popis: Panely, lupa a ukládání PSD.
|
||||
nazev_cviceni: Kvíz: prostředí
|
||||
nadpis_kvizu: Najděte zkratku a správný soubor
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Okno
|
||||
*Panely*
|
||||
|
||||
- Vlevo je panel nástrojů. Nahoře jsou volby vybraného nástroje, mění se s ním.
|
||||
- Vpravo jsou Vrstvy, Barvy a Vlastnosti. Když panel zmizí, vrátí ho Okno a název panelu.
|
||||
- Uprostřed je plátno. Šedé okolí není součást obrázku, netiskne se.
|
||||
- Pracovní plochu Fotografie nebo Základní nastavíte vpravo nahoře. Cizí rozložení si neukládejte přes cizí účet.
|
||||
|
||||
> Tip: Na Macu je Ctrl většinou Cmd. Alt je Option. Zkratky v lekcích jsou windowsové.
|
||||
|
||||
## Pohyb po obraze
|
||||
*Lupa*
|
||||
|
||||
- Mezerník dočasně vezme ručičku a obraz se posouvá.
|
||||
- Ctrl+0 vměstná celé plátno do okna. Ctrl+1 ukáže 100 %, jeden pixel na pixel.
|
||||
- Nástroj lupa je Z. Alt a klik zmenšuje.
|
||||
- Při retuši kontrolujte 100 %. Na celém plátně drobná chyba zanikne.
|
||||
|
||||
> Tip: Ctrl+Alt+Z krokne zpět o víc než jeden krok. Panel Historie ukáže, kam až se dá vrátit.
|
||||
|
||||
## Uložení
|
||||
*PSD a JPG*
|
||||
|
||||
- Pracovní soubor je PSD. Drží vrstvy, masky a text.
|
||||
- JPG je kopie na odevzdání nebo na web. Vrstvy v něm nejsou.
|
||||
- Soubor > Uložit jako nechá PSD. Export > Exportovat jako udělá JPG nebo PNG.
|
||||
- JPG kvalitu 10 (nebo 80 %) berte na fotku. Nižší kvalita dělá kostky.
|
||||
|
||||
> Tip: Jednou uložené JPG znovu neukládejte jako jediný zdroj. Každý export ubere detail.
|
||||
|
||||
## Zadání: první soubor
|
||||
*Cvičení*
|
||||
|
||||
- Otevřete web.psd z minulé lekce, nebo založte nový 1920 × 1080 px.
|
||||
- Přejmenujte první vrstvu na pozadi a uložte soubor jako uvod.psd.
|
||||
- Ctrl+0 a Ctrl+1 si vyzkoušejte. Na 100 % má být vidět pixel, ne celé plátno.
|
||||
- Exportujte kopii uvod.jpg v kvalitě 10. PSD si nechte.
|
||||
|
||||
> Tip: Když Exportovat jako nabídne PNG, přepněte formát na JPG. PNG tu ještě nepotřebujeme.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co udělá Ctrl+1?
|
||||
- Vloží novou vrstvu
|
||||
- [x] Ukáže obraz v měřítku 100 %
|
||||
- Smaže plátno
|
||||
- Převede barvy do CMYK
|
||||
> 100 % je jeden pixel souboru na jeden pixel obrazovky. Ctrl+0 naopak vměstná celé plátno.
|
||||
|
||||
## Který soubor si necháváte jako pracovní?
|
||||
- JPG
|
||||
- [x] PSD
|
||||
- MP4
|
||||
- Jen snímek obrazovky
|
||||
> PSD drží vrstvy. JPG je plochá kopie.
|
||||
|
||||
## Čím se při přiblížení posouvá obraz?
|
||||
- Nástrojem text
|
||||
- [x] Mezerníkem
|
||||
- Klávesou D
|
||||
- Exportem
|
||||
> Mezerník dočasně přepne na ručičku, ať nemusíte měnit nástroj.
|
||||
|
||||
## Jakou kvalitu JPG berete na obyčejnou fotku?
|
||||
- 1
|
||||
- [x] 10, tedy kolem 80 %
|
||||
- JPG se na fotku nehodí
|
||||
- Jen PNG
|
||||
> Kvalita 1 obraz rozbije na kostky. Kolem 10 je rozumný kompromis velikosti a vzhledu.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Layers
|
||||
popis: Order, opacity and groups. An edit does not sit on the photo pixels.
|
||||
nazev_cviceni: Quiz: layers
|
||||
nadpis_kvizu: Put the layers in the right order
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-vrstvy
|
||||
nazev: Vrstvy
|
||||
popis: Pořadí, krytí a skupiny. Úprava nesedí na pixelech fotky.
|
||||
nazev_cviceni: Kvíz: vrstvy
|
||||
nadpis_kvizu: Dejte vrstvy do správného pořadí
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Proč vrstva
|
||||
*Pořádek*
|
||||
|
||||
- Každá úprava má vlastní vrstvu. Fotka vespod zůstane nedotčená.
|
||||
- Horní vrstva překrývá spodní. Text patří nahoru, fotka dolů.
|
||||
- Oko u vrstvy ji skryje. Zámek zabrání posunu.
|
||||
- Vrstvu pojmenujte: fotka, retus, nadpis. Název Vrstva 1 nic neřekne.
|
||||
|
||||
> Tip: Když smažete vrstvu, fotka pod ní zůstane. Když malujete přímo do fotky, už ji neoddělíte.
|
||||
|
||||
## Krytí a pořadí
|
||||
*Vzhled*
|
||||
|
||||
- Krytí 100 % je plná vrstva. Krytí 70 % nechá prosvítat to, co je pod ní.
|
||||
- Pořadí změníte tažením v panelu Vrstvy.
|
||||
- Režim prolnutí nechte na Normální, dokud ho lekce výslovně nezmění.
|
||||
- Jedna věc na jedné vrstvě. Nadpis a stín textu k sobě patří, retuš ne.
|
||||
|
||||
> Tip: Krytí je u horního okraje panelu Vrstvy. Není to totéž co Výplň, tu zatím nechte 100 %.
|
||||
|
||||
## Skupina
|
||||
*Složka*
|
||||
|
||||
- Ctrl+G vloží vybrané vrstvy do skupiny. Skupina je složka v panelu.
|
||||
- Skupina Popisek ať drží nadpis i podnadpis. Skupina Foto ať drží fotku a retuš.
|
||||
- Skrytí skupiny skryje všechno v ní. Jednotlivé vrstvy tím nesmažete.
|
||||
- Rozdělit skupinu jde Ctrl+Shift+G.
|
||||
|
||||
> Tip: Nejdřív vyberte vrstvy se Shiftem, pak Ctrl+G. Prázdná skupina sama nic nesrovná.
|
||||
|
||||
## Zadání: tři patra
|
||||
*Cvičení*
|
||||
|
||||
- V uvod.psd mějte dole vrstvu fotka.
|
||||
- Nad ní vrstvu uprav, krytí 70 %. Zatím na ni stačí jednobarevný obdélník přes spodní třetinu.
|
||||
- Úplně nahoru vrstvu nadpis s textem Školní den.
|
||||
- Vrstvy nadpis a uprav dejte do skupiny popisek. Uložte PSD.
|
||||
|
||||
> Tip: Když text nejde přečíst, není špatně písmo, ale pořadí. Nadpis nesmí skončit pod fotkou.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Kam patří vrstva s fotkou?
|
||||
- Úplně nahoru
|
||||
- [x] Dolu, pod úpravy a text
|
||||
- Mimo panel Vrstvy
|
||||
- Do JPG
|
||||
> Fotka je podklad. Všechno, co se má dát vypnout, leží nad ní.
|
||||
|
||||
## Co znamená krytí 70 %?
|
||||
- Vrstva je o 70 px menší
|
||||
- [x] Vrstva je částečně průhledná
|
||||
- Text má 70 bodů
|
||||
- Soubor má 70 ppi
|
||||
> 100 % je plná vrstva. Nižší krytí nechá prosvítat vrstvy pod ní.
|
||||
|
||||
## Čím se vybrané vrstvy seskupí?
|
||||
- Ctrl+1
|
||||
- [x] Ctrl+G
|
||||
- Klávesou D
|
||||
- Exportem do JPG
|
||||
> Ctrl+G udělá skupinu. Ctrl+Shift+G ji zase rozebere.
|
||||
|
||||
## Proč se nemaluje přímo do vrstvy fotky?
|
||||
- Photoshop to zakazuje
|
||||
- [x] Úprava pak nejde oddělit ani vypnout
|
||||
- Fotka by se stala vektorem
|
||||
- Změní se to na CMYK
|
||||
> Vlastní vrstvu smažete nebo skryjete. Pixely fotky už od malby neočistíte.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Selections
|
||||
popis: Mark part of the picture and copy it to a new layer.
|
||||
nazev_cviceni: Quiz: selections
|
||||
nadpis_kvizu: Pick the tool and the shortcut
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-vybery
|
||||
nazev: Výběry
|
||||
popis: Označení části obrazu a kopie na novou vrstvu.
|
||||
nazev_cviceni: Kvíz: výběry
|
||||
nadpis_kvizu: Vyberte nástroj a zkratku
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Nástroje výběru
|
||||
*Tvar*
|
||||
|
||||
- Obdélníkový a eliptický výběr řežou pravidelný tvar. Hodí se na ořez a banner.
|
||||
- Laso obkreslí nepravidelný okraj rukou. Na vlasy je nepřesné.
|
||||
- Rychlý výběr a předmět malují přes plochu, kterou chcete. Photoshop dopočítá hranu.
|
||||
- Kouzelná hůlka bere souvislou podobnou barvu. Na oblohu ano, na tvář ne.
|
||||
|
||||
> Tip: Shift k výběru přidává, Alt ubírá. Ve volbách nástroje je totéž jako ikony.
|
||||
|
||||
## Hrana
|
||||
*Prolnutí*
|
||||
|
||||
- Tvrdý výběr dělá nalepený obrys. Prolnutí okraje (feather) hranu změkčí.
|
||||
- U postavy stačí prolnutí 1 až 2 px. U oblohy může být větší.
|
||||
- Prolnutí se nastavuje před potvrzením, nebo přes Výběr > Upravit > Prolnout okraj.
|
||||
- Když je kolem vlasů barevný lem, výběr byl moc hrubý. Zpřesněte ho, neschovávejte ho rozmazáním.
|
||||
|
||||
> Tip: Prolnutí 20 px z člověka udělá ducha. Na výřez postavy je to moc.
|
||||
|
||||
## Nová vrstva z výběru
|
||||
*Ctrl+J*
|
||||
|
||||
- Ctrl+J zkopíruje výběr na novou vrstvu. Původní fotka zůstane vespod.
|
||||
- Tak se postava oddělí od pozadí, aniž byste pozadí mazali.
|
||||
- Výběr zrušíte Ctrl+D. Když ho nezrušíte, další malování se ořeže jen do něj.
|
||||
- Vrstvu s postavou pojmenujte osoba. Vrstvu pod ní pozadi.
|
||||
|
||||
> Tip: Ctrl+J bez výběru zkopíruje celou vrstvu. Nejdřív musí běžet mravenci kolem výběru.
|
||||
|
||||
## Zadání: osoba bokem
|
||||
*Cvičení*
|
||||
|
||||
- Vyberte postavu rychlým výběrem. Okraj doplňte se Shiftem a Alt.
|
||||
- Dejte prolnutí 2 px a Ctrl+J. Vznikne vrstva osoba.
|
||||
- Vrstvu pozadi ztmavte tak, aby šla vypnout. Postava zůstane ve své vrstvě světlá.
|
||||
- Uložte vyber.psd. Výběr před uložením zrušte Ctrl+D.
|
||||
|
||||
> Tip: Když ztmavení sedí i na postavě, malovali jste do špatné vrstvy. Ztmavení patří jen na pozadi.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Který nástroj bere souvislou podobnou barvu, třeba oblohu?
|
||||
- Text
|
||||
- [x] Kouzelná hůlka
|
||||
- Ořez
|
||||
- Pero v Illustratoru
|
||||
> Hůlka skočí po podobné barvě. Na tvář, která má víc odstínů, se nehodí.
|
||||
|
||||
## Co udělá Ctrl+J, když je něco vybrané?
|
||||
- Smaže výběr
|
||||
- [x] Zkopíruje výběr na novou vrstvu
|
||||
- Převede obraz do CMYK
|
||||
- Založí video
|
||||
> Původní vrstva zůstane. Nová obsahuje jen vybranou část.
|
||||
|
||||
## Jaké prolnutí okraje dává smysl u postavy?
|
||||
- [x] 2 px
|
||||
- 80 px
|
||||
- 300 ppi
|
||||
- Žádné, ale 40 px stín na celé fotce
|
||||
> 1 až 2 px hranu změkčí. Desítky pixelů postavu rozmažou.
|
||||
|
||||
## Čím se výběr zruší?
|
||||
- [x] Ctrl+D
|
||||
- Ctrl+0
|
||||
- Exportem JPG
|
||||
- Krytím 70 %
|
||||
> Nezrušený výběr omezí další malování jen dovnitř mravenců.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Retouching
|
||||
popis: The clone stamp and the healing brush on their own layer.
|
||||
nazev_cviceni: Quiz: retouching
|
||||
nadpis_kvizu: Pick the tool and the layer
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-retus
|
||||
nazev: Retuš
|
||||
popis: Klonovací razítko a opravný štětec na vlastní vrstvě.
|
||||
nazev_cviceni: Kvíz: retuš
|
||||
nadpis_kvizu: Vyberte nástroj a vrstvu
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Dva nástroje
|
||||
*Razítko a štětec*
|
||||
|
||||
- Klonovací razítko kopíruje konkrétní místo. Nejdřív Alt+klik do zdroje, pak malujete cíl.
|
||||
- Opravný štětec bere texturu z okolí sám. Hodí se na pupínek, prach a malou skvrnu.
|
||||
- Razítko berte tam, kde musí sedět vzor: plot, spára, textura zdi.
|
||||
- Na velkou plochu oblohy je často rychlejší výběr a výplň než hodina razítka.
|
||||
|
||||
> Tip: Alt+klik není obyčejný klik. Bez zdroje razítko neví, odkud brát.
|
||||
|
||||
## Vrstva retus
|
||||
*Nesahejte na fotku*
|
||||
|
||||
- Nad fotku přidejte prázdnou vrstvu retus.
|
||||
- Ve volbách razítka i štětce zapněte Vzorkovat všechny vrstvy, jinak prázdná vrstva nemá co kopírovat.
|
||||
- Retuš pak jde ztlumit krytím nebo vypnout okem. Fotka vespod zůstane.
|
||||
- Když se vzor opakuje jako razítko, vezměte zdroj z jiného místa. Jedna cihla pětkrát je vidět.
|
||||
|
||||
> Tip: Tvrdost štětce kolem 50 % a krytí 100 %. Měkké razítko na hraně předmětu rozmaže obrys.
|
||||
|
||||
## Co retušovat
|
||||
*Míra*
|
||||
|
||||
- Pryč patří prach, datum z fotoaparátu, koš v záběru a drát, který tam nemá být.
|
||||
- Nepatří pryč pihy, jizva ani rys, který dělá člověka. To už není oprava, ale jiná tvář.
|
||||
- Datum vypálené v rohu je pixel, ne vrstva. Musí se přemalovat z okolí oblohy nebo zdi.
|
||||
- Po retuši se podívejte na 100 %. Opakovaný vzor a šmouha jsou vidět zblízka.
|
||||
|
||||
> Tip: Jedna školní fotka, tři konkrétní chyby. Celou kůži nepřemalovávejte.
|
||||
|
||||
## Zadání: tři chyby
|
||||
*Cvičení*
|
||||
|
||||
- Najděte na fotce tři rušivé věci: třeba koš, drát a datum, nebo tři skvrny.
|
||||
- Odstraňte je na vrstvě retus. Razítko i štětec vzorkují všechny vrstvy.
|
||||
- Vrstvu fotka nezamykejte malbou. Po vypnutí retus musí být chyby zpátky.
|
||||
- Uložte retus.psd a do názvů si poznamenejte, který nástroj byl na které chybě.
|
||||
|
||||
> Tip: Když po vypnutí vrstvy retus obraz vypadá stejně, malovali jste do fotky. Vezměte to z historie zpět.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak se u klonovacího razítka určí zdroj?
|
||||
- Ctrl+J
|
||||
- [x] Alt+klik do místa, které se má kopírovat
|
||||
- Exportem
|
||||
- Krytím 70 %
|
||||
> Alt+klik vezme zdroj. Další tahy ho kopírují do cíle.
|
||||
|
||||
## Kam se retuš maluje?
|
||||
- Přímo do vrstvy fotky
|
||||
- [x] Na prázdnou vrstvu nad fotkou
|
||||
- Do textové vrstvy
|
||||
- Do JPG
|
||||
> Vlastní vrstva jde vypnout. Fotka zůstane původní.
|
||||
|
||||
## Který nástroj si bere texturu z okolí sám?
|
||||
- [x] Opravný štětec
|
||||
- Text
|
||||
- Ořez na 1920 px
|
||||
- Pero
|
||||
> Štětec dopočítá okolí. Razítko kopíruje přesně to místo, které jste označili.
|
||||
|
||||
## Co musí být zapnuté, když razítko maluje do prázdné vrstvy?
|
||||
- CMYK
|
||||
- [x] Vzorkovat všechny vrstvy
|
||||
- Spadávka 3 mm
|
||||
- 25 sn/s
|
||||
> Bez vzorkování všech vrstev je zdroj prázdný a razítko nemá co kopírovat.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Type and colour
|
||||
popis: A headline, the eyedropper and the foreground colour.
|
||||
nazev_cviceni: Quiz: type and colour
|
||||
nadpis_kvizu: Name the colour shortcuts
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-text-a-barvy
|
||||
nazev: Text a barvy
|
||||
popis: Nápis, kapátko a barva popředí.
|
||||
nazev_cviceni: Kvíz: text a barvy
|
||||
nadpis_kvizu: Poznejte zkratky barev
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Barva popředí
|
||||
*Kapátko*
|
||||
|
||||
- Levý horní čtvereček je barva popředí, pravý dolní je pozadí.
|
||||
- D vrátí černou a bílou. X je prohodí.
|
||||
- Kapátko je I. Klik do fotky vezme barvu, která už v obraze je.
|
||||
- Barvu nadpisu berte z fotky, ne náhodnou jedovatou zelenou, která se s ní pere.
|
||||
|
||||
> Tip: Na světlé nebe patří tmavý text, na tmavý kabát světlý. Stejná šedá na obojí zanikne.
|
||||
|
||||
## Nástroj text
|
||||
*Písmo*
|
||||
|
||||
- Jedno kliknutí založí bodový text. Tažení myší založí odstavcový rámeček.
|
||||
- Nadpis školní práce je bodový text. Delší odstavec patří do rámečku.
|
||||
- Velikost nadpisu na plátně 1920 px je kolem 72 pt. Podnadpis kolem 28 pt.
|
||||
- Písmo nechte jedno, nejvýš dvě. Třetí řez plakát rozbije.
|
||||
|
||||
> Tip: Textová vrstva se jmenuje podle nápisu. Nepřevádějte ji na pixely, dokud nemusíte. V PSD ať jde text přepsat.
|
||||
|
||||
## Čitelnost
|
||||
*Kontrast*
|
||||
|
||||
- Když text sedí na rušné fotce, dejte pod něj poloprůhledný pruh, ne jen stín.
|
||||
- Stín textu: vzdálenost malá, třeba 4 px, rozmazání 8 px, krytí kolem 40 %.
|
||||
- Bílý text na světlé obloze nečetete ani vy. Ztmavte místo pod ním, nebo změňte barvu písma.
|
||||
- Zarovnání na střed jen u krátkého nadpisu. Dlouhý text nechte vlevo.
|
||||
|
||||
> Tip: Styl vrstvy je fx dole v panelu Vrstvy. Stín pak jde vypnout, písmo zůstane.
|
||||
|
||||
## Zadání: nápis z fotky
|
||||
*Cvičení*
|
||||
|
||||
- Kapátkem I vezměte světlou barvu z fotky a nadpis Školní den napište barvou, která je k ní kontrastní.
|
||||
- Podnadpis se jménem autora dejte na 28 pt.
|
||||
- Pod text dejte pruh s krytím 70 %, ať nápis drží i na světlém místě.
|
||||
- Uložte napis.psd. Text nechte jako textovou vrstvu, nerasterizujte ho.
|
||||
|
||||
> Tip: X prohodí barvy, když kapátko vezme pravou. D vás vrátí na černou a bílou, když se ztratíte.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co udělá klávesa D?
|
||||
- Smaže vrstvu
|
||||
- [x] Vrátí výchozí černou a bílou
|
||||
- Spustí export
|
||||
- Založí masku
|
||||
> D je default. X potom černou a bílou prohodí.
|
||||
|
||||
## Čím se nabere barva z fotky?
|
||||
- Klonovacím razítkem
|
||||
- [x] Kapátkem, klávesa I
|
||||
- Ořezem
|
||||
- Ctrl+0
|
||||
> Kapátko uloží barvu pixelu do popředí. Nadpis pak ladí s fotkou.
|
||||
|
||||
## Jak velký má být podnadpis na plátně 1920 px?
|
||||
- 4 pt
|
||||
- [x] kolem 28 pt
|
||||
- 300 pt
|
||||
- 2480 pt
|
||||
> Nadpis je velký, kolem 72 pt. Podnadpis je menší, kolem 28 pt, ať je vidět hierarchie.
|
||||
|
||||
## Proč se text hned nerasterizuje?
|
||||
- PSD by nešel uložit
|
||||
- [x] V pracovním souboru má jít nápis přepsat
|
||||
- Raster je vektor
|
||||
- Premiere ho jinak nepřečte
|
||||
> Z pixelů text už neopravíte. Na pixely ho převádějte až v kopii, když musíte.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Assignment: edit a photograph
|
||||
popis: One photo, retouch, a selection, type and two exports.
|
||||
nazev_cviceni: Quiz: the photograph
|
||||
nadpis_kvizu: Check the finished piece
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-1-zadani-fotografie
|
||||
nazev: Zadání: úprava fotografie
|
||||
popis: Jedna fotka, retuš, výběr, nápis a dva výstupy.
|
||||
nazev_cviceni: Kvíz: úprava fotografie
|
||||
nadpis_kvizu: Zkontrolujte hotovou práci
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Co se odevzdává
|
||||
*Rozsah*
|
||||
|
||||
- Jedna fotka školní akce nebo místa, ořez na 1920 × 1080 px, RGB, 72 ppi.
|
||||
- Pracovní soubor fotografie.psd a plochá kopie fotografie.jpg v kvalitě 10.
|
||||
- Na plátně je nápis Školní den a pod ním vaše jméno.
|
||||
- JPG nesmí být jediný soubor. Bez PSD nejde práce opravit.
|
||||
|
||||
> Tip: Ořez udělá nástroj Ořez. Poměr stran zadejte 16 : 9, ať z fotky nezbude čtverec omylem.
|
||||
|
||||
## Vrstvy, které musí být
|
||||
*Skladba*
|
||||
|
||||
- Dole fotka. Nad ní retus s aspoň jednou odstraněnou věcí, vzorkuje všechny vrstvy.
|
||||
- Osoba nebo hlavní předmět je vybraný a leží na vlastní vrstvě, prolnutí okraje 2 px.
|
||||
- Pozadí jde ztmavit samostatně. Po vypnutí této úpravy je pozadí zpět světlé.
|
||||
- Skupina popisek drží pruh s krytím 70 % a oba texty. Texty nejsou rasterizované.
|
||||
|
||||
> Tip: Pět vteřin kontroly: vypínejte skupiny okem. Každá musí něco změnit a po zapnutí to vrátit.
|
||||
|
||||
## Nápis
|
||||
*Čitelnost*
|
||||
|
||||
- Barva nadpisu je z kapátka nebo k němu kontrastní. Na světlém místě nesmí zmizet.
|
||||
- Podnadpis má asi 28 pt. Nadpis je výrazně větší.
|
||||
- Pruh pod textem nelpí na horní hraně, sedí ve spodní třetině.
|
||||
- Žádný text není oříznutý hranou plátna. Nechte od okraje aspoň 48 px.
|
||||
|
||||
> Tip: 48 px je bezpečný okraj i na telefonu, když se JPG někde ořízne na krajích.
|
||||
|
||||
## Kontrola před odevzdáním
|
||||
*Seznam*
|
||||
|
||||
- Obraz je 1920 × 1080 px. Větší export zmenšete, menší nezvětšujte rozmazáním.
|
||||
- Retuš na 100 % nemá opakovaný vzor ani šmouhu přes obličej.
|
||||
- V JPG nejsou vrstvy, v PSD jsou. Oba soubory se jmenují fotografie, liší se příponou.
|
||||
- Původní fotku nemažte. Když ořez přetáhnete, musí být z čeho začít znovu.
|
||||
|
||||
> Tip: Soubor > Exportovat jako ukáže rozměr. Když tam není 1920 × 1080, ořez ještě nesedí.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jaký má být výsledný rozměr?
|
||||
- 2480 × 3508 px
|
||||
- [x] 1920 × 1080 px
|
||||
- A4 při 300 ppi
|
||||
- 80 × 80 px
|
||||
> Zadání je obrazovka, Full HD, 16 : 9. A4 při 300 ppi by bylo do tisku.
|
||||
|
||||
## Kde smí ležet retuš?
|
||||
- Jen v JPG
|
||||
- [x] Na vlastní vrstvě nad fotkou
|
||||
- V rasterizovaném textu
|
||||
- V dokumentu CMYK
|
||||
> Vrstva retus jde vypnout. JPG je až plochá kopie na odevzdání.
|
||||
|
||||
## Jaké krytí má pruh pod nápisem?
|
||||
- 10 %
|
||||
- [x] 70 %
|
||||
- 300 %
|
||||
- Pruh se nedělá
|
||||
> 70 % podrží text a ještě nechá tušit fotku. Plný pruh ji zakryje celou.
|
||||
|
||||
## Co se odevzdává?
|
||||
- Jen JPG
|
||||
- [x] PSD i JPG
|
||||
- Jen SVG
|
||||
- Projekt Premiere
|
||||
> PSD je práce s vrstvami. JPG je náhled, který otevře i člověk bez Photoshopu.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Masks
|
||||
popis: A mask hides, it does not delete. Black conceals, white reveals.
|
||||
nazev_cviceni: Quiz: masks
|
||||
nadpis_kvizu: Read the mask
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-masky
|
||||
nazev: Masky
|
||||
popis: Maska skrývá, nemaže. Černá kryje, bílá ukazuje.
|
||||
nazev_cviceni: Kvíz: masky
|
||||
nadpis_kvizu: Přečtěte masku
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## K čemu maska je
|
||||
*Nedestruktivně*
|
||||
|
||||
- Smazaný pixel je pryč. Maska ho jen schová a jde přemalovat zpátky.
|
||||
- Každá vrstva může mít jednu masku. Bílá plocha masky obraz ukazuje, černá ho kryje.
|
||||
- Šedá je poloprůhledná. 50 % šedá nechá vrstvu napůl vidět.
|
||||
- Masku přidáte ikonou obdélníku s kolečkem dole v panelu Vrstvy.
|
||||
|
||||
> Tip: Když mažete gumou, nemáte cestu zpět. Když malujete do masky černou, stačí přetřít bílou.
|
||||
|
||||
## Malování do masky
|
||||
*Štětec*
|
||||
|
||||
- Klik na miniaturu masky, ne na miniaturu obrazu. Jinak malujete do fotky.
|
||||
- Alt+klik na masku ji ukáže přes celé plátno. Černobílý obraz je jen maska, ne výsledek.
|
||||
- Měkký štětec, tvrdost 0 %, krytí 30 %, černá barva. Okraj předmětu pak není vystřižený nůžkami.
|
||||
- X prohodí černou a bílou, takže stejný štětec umí skrýt i vrátit.
|
||||
|
||||
> Tip: Kolem miniatury masky je rámeček, když je aktivní. Rámeček kolem fotky znamená, že malujete špatně.
|
||||
|
||||
## Výběr a maska
|
||||
*Spolu*
|
||||
|
||||
- Výběr postavy a pak ikona masky schová všechno mimo výběr.
|
||||
- Prolnutí 2 px udělejte ještě ve výběru, nebo okraj domalujte měkkým štětcem.
|
||||
- Maska není nová vrstva. V panelu sedí vpravo vedle miniatury.
|
||||
- Masku neslučujte s vrstvou, dokud učitel neřekne. Sloučení už nejde odmaskovat.
|
||||
|
||||
> Tip: Ctrl+I na masce, když je vybraná, černou a bílou otočí. Hodí se, když jste skryli opak.
|
||||
|
||||
## Zadání: výřez maskou
|
||||
*Cvičení*
|
||||
|
||||
- Postavu oddělte maskou, ne gumou. Původní fotka po Alt+klik a přemalování bílou musí být celá.
|
||||
- Okraj dopracujte štětcem tvrdost 0 % a krytí 30 %.
|
||||
- Pozadí nechte ve vrstvě pod ní, ať jde vyměnit.
|
||||
- Uložte maska.psd. V souboru nesmí být jen jedna sloučená vrstva.
|
||||
|
||||
> Tip: Vypněte a zapněte masku Shiftem a klikem na ni. Obraz se musí vrátit celý.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co dělá černá barva v masce?
|
||||
- Vrstvu ukáže
|
||||
- [x] Vrstvu skryje
|
||||
- Převede ji na text
|
||||
- Zvýší rozlišení na 300 ppi
|
||||
> Černá kryje, bílá ukazuje, šedá je mezi tím.
|
||||
|
||||
## Čím se maska zobrazí přes celé plátno?
|
||||
- Ctrl+1
|
||||
- [x] Alt+klik na miniaturu masky
|
||||
- Exportem JPG
|
||||
- Klávesou D na textu
|
||||
> Alt+klik ukáže černobílou masku. Další Alt+klik vrátí normální obraz.
|
||||
|
||||
## Proč se výřez nedělá gumou?
|
||||
- Guma je v Illustratoru
|
||||
- [x] Smazané pixely už nevrátíte, masku ano
|
||||
- Guma umí jen CMYK
|
||||
- Premiere gumu nepustí
|
||||
> Masku přemalujete. Guma na obyčejné vrstvě pixely zahodí.
|
||||
|
||||
## Jaké krytí štětce se hodí na jemný okraj masky?
|
||||
- 100 % tvrdý štětec
|
||||
- [x] 30 % a tvrdost 0 %
|
||||
- Krytí textu 28 pt
|
||||
- 10 Mb/s
|
||||
> Nízké krytí a měkký štětec skládají hranu postupně. Tvrdý tah je vidět jako střih.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Levels and curves
|
||||
popis: Brightness and contrast as an adjustment layer, not a rewrite of the pixels.
|
||||
nazev_cviceni: Quiz: curves
|
||||
nadpis_kvizu: Recognise a non-destructive edit
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-krivky
|
||||
nazev: Úrovně a křivky
|
||||
popis: Světlost a kontrast jako vrstva úprav, ne jako přepis pixelů.
|
||||
nazev_cviceni: Kvíz: křivky
|
||||
nadpis_kvizu: Poznejte nedestruktivní úpravu
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Vrstva úprav
|
||||
*Nad pixely*
|
||||
|
||||
- Vrstva úprav mění vzhled všeho pod sebou a pixely fotky nepřepisuje.
|
||||
- Přidá se kolečkem dole v panelu Vrstvy. Položka Křivky nebo Úrovně.
|
||||
- Když úpravu vypnete okem, fotka je jako na začátku.
|
||||
- Úprava přímo přes Obraz > Přizpůsobení fotku přepíše. Ve školní práci ji neberte.
|
||||
|
||||
> Tip: Vrstva úprav má vlastní masku. Černou v masce úpravu na části obrazu vypnete.
|
||||
|
||||
## Úrovně
|
||||
*Tři body*
|
||||
|
||||
- Černý bod říká, co má být nejtmavší. Bílý bod, co má být nejsvětlejší.
|
||||
- Šedý bod srovná nádech. Klik do místa, které má být neutrální šedé.
|
||||
- Bod světel nechte kolem 245, ne na 255, ať v obloze nezmizí kresba.
|
||||
- Bod stínů kolem 15, ne na 0, ať černá není slitá.
|
||||
|
||||
> Tip: Když histogram na obou koncích nic nemá, fotka je mdlá. Body přitáhněte k místu, kde data začínají.
|
||||
|
||||
## Křivka S
|
||||
*Kontrast*
|
||||
|
||||
- Křivka zdola zleva nahoru doprava je světlost od stínů ke světlům.
|
||||
- Jemná křivka do S zvedne kontrast: stíny o trochu níž, světla o trochu výš.
|
||||
- Ostré S přepálí tváře a zabije stíny. Stačí malý oblouk.
|
||||
- Jedna vrstva Křivky na celou fotku. Druhou přidejte jen na oblohu, a maskou ji tam omezte.
|
||||
|
||||
> Tip: Na křivce táhněte málo. Oko si na přepálený náhled rychle zvykne a původní fotka pak vypadá špatně, i když byla lepší.
|
||||
|
||||
## Zadání: dvě úpravy
|
||||
*Cvičení*
|
||||
|
||||
- Nad fotku dejte vrstvu úprav Křivky. Bod stínů nechte u 15, bod světel u 245, mezi tím jemné S.
|
||||
- Druhou křivku omezte maskou jen na pozadí, ať tvář nejde do přepalu.
|
||||
- Obě úpravy pojmenujte. Fotka vespod ať nemá žádné Přizpůsobení zapékané v pixelech.
|
||||
- Uložte krivky.psd. Vypnutí obou úprav vrátí původní světlost.
|
||||
|
||||
> Tip: Alt při tahu černého a bílého bodu v Úrovních ukáže, které místo už je slité. U křivek stačí oko a 100 %.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Kam patří školní zesvětlení fotky?
|
||||
- Obraz > Přizpůsobení, přímo do pixelů
|
||||
- [x] Vrstva úprav nad fotkou
|
||||
- Do textové vrstvy
|
||||
- Do exportu JPG jako jediná úprava
|
||||
> Vrstva úprav jde vypnout. Přizpůsobení přes nabídku Obraz pixely přepíše.
|
||||
|
||||
## Kam dát bod světel, aby obloha neztratila kresbu?
|
||||
- 0
|
||||
- [x] kolem 245
|
||||
- 255 a přes
|
||||
- 28 pt
|
||||
> 255 je čistá bílá bez kresby. 245 nechá ve světlech detail.
|
||||
|
||||
## Co dělá jemná křivka ve tvaru S?
|
||||
- Sníží rozlišení
|
||||
- [x] Zvedne kontrast
|
||||
- Převede RGB na vektor
|
||||
- Přidá spadávku
|
||||
> Stíny jdou trochu níž a světla trochu výš. Kontrast stoupne, barva se nemění v jiný režim.
|
||||
|
||||
## Čím se křivka omezí jen na pozadí?
|
||||
- Gumou na fotce
|
||||
- [x] Maskou vrstvy úprav
|
||||
- Exportem
|
||||
- Krytím textu
|
||||
> Černá v masce úpravy řekne: tady křivku nepoužívej. Tvář může zůstat bílá, tedy upravená jinou vrstvou, nebo naopak.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Smart objects and filters
|
||||
popis: Blur and sharpening you can still change.
|
||||
nazev_cviceni: Quiz: filters
|
||||
nadpis_kvizu: Fill in the filter values
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-chytre-objekty
|
||||
nazev: Chytré objekty a filtry
|
||||
popis: Rozostření a doostření, které jde změnit.
|
||||
nazev_cviceni: Kvíz: filtry
|
||||
nadpis_kvizu: Doplňte hodnoty filtru
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Chytrý objekt
|
||||
*Obal*
|
||||
|
||||
- Vrstva > Chytré objekty > Převést na chytrý objekt zabalí vrstvu do obalu.
|
||||
- Filtr na chytrém objektu zůstane jako položka pod vrstvou. Dvojklik ho otevře znovu.
|
||||
- Filtr na obyčejné vrstvě pixely přepíše. Ve školním plakátu ho neberte.
|
||||
- Logo z Illustratoru vkládejte rovnou jako chytrý objekt, ať jde zvětšit.
|
||||
|
||||
> Tip: V rohu miniatury chytrého objektu je malá ikona. Když tam není, filtr se zapíše natvrdo.
|
||||
|
||||
## Rozostření pozadí
|
||||
*Hloubka*
|
||||
|
||||
- Gaussovské rozostření oddělí pozadí od předmětu. Na pozadí stačí 8 px.
|
||||
- Předmět rozostřením nechte být. Buď je na vrstvě nad ním, nebo má masku.
|
||||
- Silnější rozostření, třeba 30 px, už pozadí smaže. Berte ho jen jako záměr.
|
||||
- Rozostření celého obrazu včetně tváře je chyba, ne hloubka ostrosti.
|
||||
|
||||
> Tip: Nejdřív výřez maskou z minulé lekce, potom rozostření jen vrstvy pozadí.
|
||||
|
||||
## Doostření
|
||||
*Unsharp*
|
||||
|
||||
- Filtr Doostření (Unsharp Mask) zvedne kontrast na hraně. Není to zvětšení pixelů.
|
||||
- Školní hodnoty na fotku: množství 80 %, poloměr 1 px, práh 2.
|
||||
- Vyšší množství dělá světlý a tmavý obrys kolem větví a vlasů.
|
||||
- Doostřujte až nakonec a jen jednou. Doostřené doostření je vidět.
|
||||
|
||||
> Tip: Náhled filtru přepínejte, ať vidíte rozdíl. Na 100 %, ne na zmenšeném plátně.
|
||||
|
||||
## Zadání: hloubka a hrana
|
||||
*Cvičení*
|
||||
|
||||
- Pozadí převeďte na chytrý objekt a dejte mu Gaussovské rozostření 8 px.
|
||||
- Předmět nechte ostrý. Maska nebo samostatná vrstva ho chrání.
|
||||
- Na předmět dejte Doostření 80 %, poloměr 1 px, práh 2, taky jako filtr chytrého objektu.
|
||||
- Uložte filtry.psd. Oba filtry musí jít otevřít dvojklikem a hodnoty změnit.
|
||||
|
||||
> Tip: Když dvojklik filtr neotevře, vrstva nebyla chytrý objekt. Vezměte krok z historie a převeďte ji znovu.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jaké rozostření má školní pozadí?
|
||||
- [x] 8 px Gaussovské
|
||||
- 80 px na celou fotku včetně tváře
|
||||
- 0 px
|
||||
- Rozostření se dělá v Premiere
|
||||
> 8 px pozadí oddělí a ještě ho nechá poznat. Celý obraz včetně předmětu se nerozostřuje.
|
||||
|
||||
## Jaké hodnoty má školní Doostření?
|
||||
- [x] množství 80 %, poloměr 1 px, práh 2
|
||||
- množství 300 %, poloměr 20 px
|
||||
- jen krytí 70 %
|
||||
- 300 ppi
|
||||
> Malý poloměr drží hranu. Velký poloměr kreslí kolem předmětů svatozář.
|
||||
|
||||
## Proč filtr patří na chytrý objekt?
|
||||
- Jinak nejde uložit PSD
|
||||
- [x] Hodnoty jdou potom změnit a pixely se nepřepíšou
|
||||
- Chytrý objekt je vždy CMYK
|
||||
- Kvůli 25 sn/s
|
||||
> Pod vrstvou zůstane řádek filtru. Dvojklik ho otevře se stejnými čísly.
|
||||
|
||||
## Co Doostření ve skutečnosti dělá?
|
||||
- Dopočítá nové pixely jako při zvětšení
|
||||
- [x] Zvedne kontrast na hraně
|
||||
- Převede fotku na křivky
|
||||
- Přidá masku
|
||||
> Unsharp Mask není zvětšení. Měkkou fotku z malého souboru nezachrání, jen zdůrazní hranu.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Shapes and layer styles
|
||||
popis: A vector bar, a shadow and a stroke inside Photoshop.
|
||||
nazev_cviceni: Quiz: shapes
|
||||
nadpis_kvizu: Fill in the bar and the shadow
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-tvary
|
||||
nazev: Tvary a styly vrstvy
|
||||
popis: Vektorový pruh, stín a tah přímo ve Photoshopu.
|
||||
nazev_cviceni: Kvíz: tvary
|
||||
nadpis_kvizu: Doplňte rozměr pruhu a stínu
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Tvar
|
||||
*Vektor ve Photoshopu*
|
||||
|
||||
- Nástroj obdélník a elipsa kreslí tvarovou vrstvu. Není to namalovaný pixel.
|
||||
- Tvar jde zvětšit a hrana zůstane hladká, podobně jako v Illustratoru.
|
||||
- Barvu změníte dvojklikem na miniaturu. Nemalujte přes tvar štětcem.
|
||||
- Na fotku 1920 × 1080 patří spodní pruh 1920 × 280 px, od kraje ke kraji.
|
||||
|
||||
> Tip: Když podržíte Shift, elipsa je kružnice a obdélník čtverec.
|
||||
|
||||
## Styl vrstvy
|
||||
*fx*
|
||||
|
||||
- fx dole v panelu přidá stín, tah nebo přechod. Písmo ani tvar se nerasterizuje.
|
||||
- Stín školního pruhu: vzdálenost 8 px, velikost 16 px, krytí 40 %.
|
||||
- Tah 2 px berte jen na tlačítko nebo rámeček. Na velký pruh je zbytečný.
|
||||
- Styl zkopírujete Alt+tažením řádku fx na jinou vrstvu.
|
||||
|
||||
> Tip: Krytí ve stínu není krytí celé vrstvy. Pruh může být plný a stín lehký.
|
||||
|
||||
## Pruh a text
|
||||
*Spolu*
|
||||
|
||||
- Pruh je jedna vrstva, text druhá. Neslučujte je.
|
||||
- Pruh má krytí 75 %, ať fotka pod ním nezmizí celá.
|
||||
- Text je bílý, když je pruh tmavý. Sedí aspoň 48 px od levého okraje pruhu.
|
||||
- Skupina spodni drží pruh i text. Vypnutí skupiny je sundá najednou.
|
||||
|
||||
> Tip: Zarovnání textu k pruhu: vyberte obě vrstvy a v nástroji přesun použijte ikony zarovnání.
|
||||
|
||||
## Zadání: spodní pruh
|
||||
*Cvičení*
|
||||
|
||||
- Na plátně 1920 × 1080 nakreslete tvar 1920 × 280 px, krytí vrstvy 75 %.
|
||||
- Stín: vzdálenost 8, velikost 16, krytí stínu 40 %.
|
||||
- Bílý nadpis a podnadpis 28 pt jsou ve skupině s pruhem, 48 px od levého kraje.
|
||||
- Uložte pruh.psd. Tvar nesmí být rasterizovaný.
|
||||
|
||||
> Tip: V panelu Vrstvy je u tvaru ikona, ne jen malba. Když chybí, kreslili jste štětcem.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak velký je spodní pruh na Full HD?
|
||||
- 280 × 280 px
|
||||
- [x] 1920 × 280 px
|
||||
- 2480 × 3508 px
|
||||
- A4
|
||||
> Šířka plátna je 1920. Výška pruhu 280 nechá fotce horní část.
|
||||
|
||||
## Jaké krytí má vrstva pruhu?
|
||||
- [x] 75 %
|
||||
- 10 %
|
||||
- 100 % a navíc CMYK
|
||||
- Krytí se nenastavuje
|
||||
> 75 % pruh podrží text a fotku pod ním ještě tušíte.
|
||||
|
||||
## Jaký stín má školní pruh?
|
||||
- [x] vzdálenost 8, velikost 16, krytí 40 %
|
||||
- vzdálenost 80, velikost 80, krytí 100 %
|
||||
- žádný, stín nejde u tvaru
|
||||
- jen filtr 8 px na fotku
|
||||
> Malý stín pruh odlepí od fotky. Velký stín přes celou fotku je špína, ne styl.
|
||||
|
||||
## Proč se tvar nespojuje s textem do jedné vrstvy?
|
||||
- Photoshop to neumí oddělit
|
||||
- [x] Text by nešel přepsat a pruh přebarvit zvlášť
|
||||
- Kvůli 25 sn/s
|
||||
- JPG umí vrstvy líp
|
||||
> Každá věc vlastní vrstvu. Sloučení nechte až na plochý export.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Poster composition
|
||||
popis: A3, a 3 mm bleed and one main headline.
|
||||
nazev_cviceni: Quiz: the poster
|
||||
nadpis_kvizu: Pick the size and the bleed
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-kompozice
|
||||
nazev: Kompozice plakátu
|
||||
popis: A3, spadávka 3 mm a jeden hlavní nápis.
|
||||
nazev_cviceni: Kvíz: plakát
|
||||
nadpis_kvizu: Vyberte formát a spadávku
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Formát a spadávka
|
||||
*A3*
|
||||
|
||||
- Školní plakát je A3 na výšku, 297 × 420 mm, 300 ppi, RGB.
|
||||
- Tiskárna ořízne papír na čistý A3. Barva, která má jít do kraje, musí přesahovat.
|
||||
- Spadávka je 3 mm na každé straně. Plátno tedy má 303 × 426 mm.
|
||||
- Vodítka dejte 3 mm od okraje. Dovnitř vodítek patří text, ven až k okraji plátna smí jen pozadí.
|
||||
|
||||
> Tip: 303 mm je 297 plus 3 a 3. Když je plátno jen 297, spadávka tam není.
|
||||
|
||||
## Jeden plakát, jedna věc
|
||||
*Hierarchie*
|
||||
|
||||
- Největší je název akce. Pod ním datum a místo, menším písmem.
|
||||
- Datum školního zadání je 12. 6. Místo je tělocvična.
|
||||
- Hlavní prvek, třeba postava, sedí na třetině, ne uprostřed jako pasové foto.
|
||||
- Dva stejně velké nadpisy se perou. Jeden musí vyhrát.
|
||||
|
||||
> Tip: Třetiny: dvě svislé a dvě vodorovné čáry dělí plochu na devět polí. Průsečík je silné místo.
|
||||
|
||||
## Okraj textu
|
||||
*Klid*
|
||||
|
||||
- Text je aspoň 10 mm od čistého ořezu, tedy dál než vodítko spadávky.
|
||||
- Řádek delší než dvě třetiny šířky se čte špatně. Nadpis zalomte.
|
||||
- Písmo nejvýš dvě. Jedno tučné na název, jedno obyčejné na údaj.
|
||||
- Logo školy je malé a v rohu. Není to druhý plakát.
|
||||
|
||||
> Tip: Když logo nemáte ve vektoru, berte největší PNG, které škola má, a zmenšete ho. Ne naopak.
|
||||
|
||||
## Zadání: kostra plakátu
|
||||
*Cvičení*
|
||||
|
||||
- Nový dokument 303 × 426 mm, 300 ppi, RGB. Vodítka 3 mm od každého kraje.
|
||||
- Fotku dejte přes celou spadávku. Pruh a text až za vodítka.
|
||||
- Název akce, pod ním 12. 6. a tělocvična. Název je výrazně větší.
|
||||
- Uložte plakat-kostra.psd. Čistý formát A3 ať jde poznat podle vodítek.
|
||||
|
||||
> Tip: Zobrazení > Pravítka a táhněte vodítko z pravítka. Přichytávání k němu zapněte v menu Zobrazení.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak velké je plátno plakátu se spadávkou 3 mm?
|
||||
- 297 × 420 mm
|
||||
- [x] 303 × 426 mm
|
||||
- 1920 × 1080 px
|
||||
- 210 × 297 mm
|
||||
> A3 je 297 × 420. Z každé strany 3 mm navíc dělá 303 × 426.
|
||||
|
||||
## Kam nesmí text?
|
||||
- [x] Do spadávky a blízko ořezu
|
||||
- Za vodítko, dovnitř čistého formátu
|
||||
- Pod název
|
||||
- Na vlastní vrstvu
|
||||
> Ořez spadávku uřízne. Text 10 mm od čistého kraje přežije i křivý řez.
|
||||
|
||||
## Kam se má strefit hlavní prvek?
|
||||
- Přesně na střed jako na občanku
|
||||
- [x] Na třetinu plochy
|
||||
- Do razítka
|
||||
- Mimo plátno
|
||||
> Střed je klidný a často nudný. Průsečík třetin drží oko.
|
||||
|
||||
## Jaké rozlišení má tiskový plakát?
|
||||
- 72 ppi
|
||||
- [x] 300 ppi
|
||||
- 25 sn/s
|
||||
- 8 px
|
||||
> Plakát je tisk. 300 ppi. 72 ppi by na A3 bylo vidět jako mřížka.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: A mockup
|
||||
popis: The poster design placed on a photograph of a wall.
|
||||
nazev_cviceni: Quiz: the mockup
|
||||
nadpis_kvizu: Pick the blend mode and the opacity
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-mockup
|
||||
nazev: Mockup
|
||||
popis: Návrh plakátu usazený na fotografii zdi.
|
||||
nazev_cviceni: Kvíz: mockup
|
||||
nadpis_kvizu: Vyberte režim a krytí
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## K čemu mockup je
|
||||
*Náhled*
|
||||
|
||||
- Mockup ukáže návrh v situaci: plakát na zdi, vizitka na stole, tričko na postavě.
|
||||
- Není to náhrada tiskového PDF. Je to obrázek pro prezentaci práce.
|
||||
- Fotka zdi má být velká aspoň jako výstup, ideálně 1920 px na delší straně.
|
||||
- Návrh plakátu vložte jako chytrý objekt, ať ho jde ještě opravit.
|
||||
|
||||
> Tip: Obraz > Umístit vložené, nebo přetáhněte PSD a potvrďte. Vznikne chytrý objekt.
|
||||
|
||||
## Perspektiva
|
||||
*Deformace*
|
||||
|
||||
- Úpravy > Transformovat > Pokřivit, nebo Deformace, srovná rohy plakátu s rohy na zdi.
|
||||
- Rohy táhněte na fotografii, ne od oka do prázdna.
|
||||
- Shift při tažení rohu není vždy správně. Zeď má úběžník, plakát na ní není obdélník v pohledu.
|
||||
- Po potvrzení transformace chytrý objekt deformaci podrží.
|
||||
|
||||
> Tip: Když je zeď focená z boku, horní hrana plakátu je kratší než dolní, nebo naopak. To má mockup ukázat.
|
||||
|
||||
## Potisk
|
||||
*Násobit*
|
||||
|
||||
- Režim prolnutí Násobit (Multiply) nechá prosvítit strukturu zdi.
|
||||
- Krytí návrhu dejte 90 %. 100 % vypadá jako nalepená samolepka bez papíru.
|
||||
- Bílá v režimu Násobit zmizí. Na bílý plakát se Násobit nehodí, nechte Normální a lehce snižte krytí.
|
||||
- Stín pod plakátem: měkký, malý, na vlastní vrstvě, ať odlepí papír od zdi.
|
||||
|
||||
> Tip: Násobit násobí barvy. Tmavé místa zůstanou tmavá, bílá se ztratí.
|
||||
|
||||
## Zadání: plakát na zdi
|
||||
*Cvičení*
|
||||
|
||||
- Vezměte kostru plakátu a usaďte ji na fotku zdi jako chytrý objekt.
|
||||
- Deformací srovnejte čtyři rohy. Krytí 90 %.
|
||||
- Když plakát není bílý, zkuste Násobit. Když zbělá, vraťte Normální.
|
||||
- Uložte mockup.psd na 1920 px delší strany, RGB. Tiskové PDF z toho nedělejte.
|
||||
|
||||
> Tip: Mockup je obrazovka, 72 ppi stačí. Tiskové rozměry zůstávají v plakat-kostra.psd.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## K čemu je mockup?
|
||||
- Je to tiskové PDF pro tiskárnu
|
||||
- [x] Ukáže návrh na fotografii místa
|
||||
- Nahradí vrstvy v PSD
|
||||
- Je to střih videa
|
||||
> Tiskárna dostane PDF v ořezu. Mockup je na obhajobu a na web.
|
||||
|
||||
## Jak se návrh srovná se zdí, která je focená z boku?
|
||||
- Ořezem na čtverec
|
||||
- [x] Deformací rohů
|
||||
- Filtrem Doostření
|
||||
- Převodem do CMYK
|
||||
> Pokřivení nebo deformace vezme každý roh zvlášť. Obyčejné zmenšení úhel zdi neopraví.
|
||||
|
||||
## Kdy dává smysl režim Násobit?
|
||||
- [x] Když má prosvítit struktura zdi a plakát není bílý
|
||||
- Vždy, i na bílý plakát
|
||||
- Jen u textu 28 pt
|
||||
- Jen v Premiere
|
||||
> Násobit nechá tmavou strukturu a bílou zruší. Bílý plakát by zmizel.
|
||||
|
||||
## Jaké krytí má návrh na zdi?
|
||||
- [x] 90 %
|
||||
- 10 %
|
||||
- 100 % bez výjimky
|
||||
- 300 %
|
||||
> 90 % lehce spojí papír se zdí. 100 % často vypadá jako nalepený obdélník.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Export for screen and print
|
||||
popis: JPG and PNG for the screen, a PDF with crop marks for the printer.
|
||||
nazev_cviceni: Quiz: export
|
||||
nadpis_kvizu: Match the format to the job
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-export
|
||||
nazev: Export pro web a tisk
|
||||
popis: JPG a PNG na obrazovku, PDF s ořezem do tiskárny.
|
||||
nazev_cviceni: Kvíz: export
|
||||
nadpis_kvizu: Přiřaďte formát k použití
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Tři výstupy
|
||||
*Formát*
|
||||
|
||||
- JPG je fotka bez průhlednosti. Kvalita 10, tedy kolem 80 %, na web.
|
||||
- PNG drží průhlednost. Berte ho na logo a ikonu, ne na velkou fotku.
|
||||
- PDF je pro tiskárnu. Vrstvy v něm být nemusí, musí sedět rozměr a ořez.
|
||||
- PSD není výstup. PSD je pracovní soubor a odevzdává se k němu.
|
||||
|
||||
> Tip: GIF na fotku neberte. Umí málo barev a školní plakát v něm pruhuje.
|
||||
|
||||
## Web
|
||||
*sRGB*
|
||||
|
||||
- Delší strana webového JPG je 1600 px. Větší soubor na stránku školy netřeba.
|
||||
- Barvy převeďte do sRGB, ať je telefon i projektor čtou stejně.
|
||||
- Do webového JPG nedávejte spadávku ani ořezové značky. Ty jsou pro tiskárnu.
|
||||
- Náhled pojmenujte plakat-web.jpg. Jméno Bez názvu-1.jpg se ve složce ztratí.
|
||||
|
||||
> Tip: Úpravy > Převést do profilu, cíl sRGB. Obrazovkový JPG pak není v tajném profilu tiskárny.
|
||||
|
||||
## Tisk
|
||||
*Značky*
|
||||
|
||||
- PDF plakátu je v rozměru se spadávkou, 303 × 426 mm, 300 ppi.
|
||||
- Ořezové značky ukážou, kudy vede čistý A3. Ve Photoshopu je přidáte při exportu PDF, nebo je nakreslíte do spadávky, ne do textu.
|
||||
- Do PDF nepatří vodítka a názvy vrstev. Patří do něj plochý obraz.
|
||||
- Písmo, které tiskárna nemá, do PDF vloží export. V Photoshopu je text stejně často už vykreslený v obraze, to tiskárně nevadí.
|
||||
|
||||
> Tip: Soubor > Uložit kopii a formát Photoshop PDF. Zaškrtněte, že se nemá ptát na vrstvy, ať je PDF ploché.
|
||||
|
||||
## Zadání: dva výstupy z jednoho PSD
|
||||
*Cvičení*
|
||||
|
||||
- Z plakátu udělejte plakat-web.jpg, delší strana 1600 px, sRGB, kvalita 10, bez značek.
|
||||
- Z téhož PSD udělejte plakat-tisk.pdf, 303 × 426 mm, 300 ppi, s ořezovými značkami.
|
||||
- PSD plakat.psd si nechte s vrstvami. Do PDF vrstvy nedávejte.
|
||||
- Obě kopie otevřete a zkontrolujte: JPG nemá značky, PDF nemá oříznutý text.
|
||||
|
||||
> Tip: Když je JPG větší než 1600 px, obraz jste zmenšili špatně. Obraz > Velikost obrazu, přepočet Automaticky.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Který formát drží průhledné logo?
|
||||
- JPG
|
||||
- [x] PNG
|
||||
- MP4
|
||||
- WAV
|
||||
> JPG průhlednost vyplní bílou nebo černou. PNG ji umí.
|
||||
|
||||
## Jak široký je webový náhled plakátu?
|
||||
- [x] 1600 px na delší straně
|
||||
- 303 mm
|
||||
- 80 px
|
||||
- Full HD a zároveň 300 ppi
|
||||
> 1600 px stačí na obrazovku. Tiskové milimetry do JPG nepatří.
|
||||
|
||||
## Co musí mít tiskové PDF plakátu?
|
||||
- [x] Rozměr se spadávkou a ořezové značky
|
||||
- Vrstvy Photoshopu a vodítka
|
||||
- 25 sn/s
|
||||
- Průhledné pozadí jako PNG
|
||||
> Tiskárna řeže podle značek. Vrstvy a vodítka jsou věc PSD, ne PDF.
|
||||
|
||||
## Který soubor je pracovní a nejde nahradit exportem?
|
||||
- JPG
|
||||
- [x] PSD
|
||||
- PDF
|
||||
- PNG
|
||||
> Z PSD uděláte JPG i PDF znovu. Z JPG vrstvy neobnovíte.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Assignment: a poster
|
||||
popis: A3 with bleed, a mask, curves and two exports.
|
||||
nazev_cviceni: Quiz: the finished poster
|
||||
nadpis_kvizu: Check the print file and the web file
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-2-zadani-plakat
|
||||
nazev: Zadání: plakát
|
||||
popis: A3 se spadávkou, maskou, křivkami a dvěma exporty.
|
||||
nazev_cviceni: Kvíz: hotový plakát
|
||||
nadpis_kvizu: Zkontrolujte tisk i web
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Zadání akce
|
||||
*Obsah*
|
||||
|
||||
- Plakát zve na školní den 12. 6. v tělocvičně. Název si zvolte jeden a držte ho.
|
||||
- Formát A3 na výšku, plátno 303 × 426 mm, 300 ppi, RGB, spadávka 3 mm.
|
||||
- Na plakátu je fotka, jeden hlavní nápis, datum, místo a malé logo nebo značka školy.
|
||||
- Text je aspoň 10 mm od čistého ořezu. Ve spadávce smí být jen pozadí.
|
||||
|
||||
> Tip: Jeden plakát, jedna akce. Nepřidávejte druhé datum a druhý sál.
|
||||
|
||||
## Jak je složený
|
||||
*Vrstvy*
|
||||
|
||||
- Skupina foto: fotka, maska předmětu, křivky jako vrstva úprav, pozadí rozostřené 8 px.
|
||||
- Skupina grafika: tvarový pruh 75 % a případný další tvar. Stín pruhu 8 / 16 / 40 %.
|
||||
- Skupina text: název a údaje, pořád jako text, ne jako pixely.
|
||||
- Vypnutí kterékoli skupiny musí být vidět. Když ne, je skupina prázdná nebo je všechno sloučené.
|
||||
|
||||
> Tip: Křivka má bod světel kolem 245 a stínů kolem 15. Doostření předmětu 80 %, 1 px, práh 2.
|
||||
|
||||
## Dva výstupy
|
||||
*Soubory*
|
||||
|
||||
- plakat.psd s vrstvami.
|
||||
- plakat-web.jpg, delší strana 1600 px, sRGB, kvalita 10, bez ořezových značek.
|
||||
- plakat-tisk.pdf, 303 × 426 mm, ořezové značky, bez vrstev.
|
||||
- Mockup na zdi je navíc, ne místo PDF. Když ho přidáte, je to mockup.psd.
|
||||
|
||||
> Tip: Soubory leží v jedné složce plakat. Název Bez názvu v odevzdání neberte.
|
||||
|
||||
## Kontrola
|
||||
*Než to odevzdáte*
|
||||
|
||||
- Na 100 % nemá retuš opakovaný vzor a maska nemá barevný lem.
|
||||
- Datum 12. 6. je celé a čitelné. Logo není rozmazaný JPG zvětšený z 80 px.
|
||||
- Webový JPG otevřený na celou obrazovku nemá značky ani šedé okraje plátna.
|
||||
- PDF má stejný název akce jako PSD. Dvě verze textu jsou chyba.
|
||||
|
||||
> Tip: Vytiskněte si PDF na A4 jako náhled. Když je text u kraje už na A4, na A3 bude u řezu taky.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jaké je plátno tiskového plakátu?
|
||||
- 1920 × 1080 px, 72 ppi
|
||||
- [x] 303 × 426 mm, 300 ppi
|
||||
- A4 bez spadávky
|
||||
- 1600 px
|
||||
> A3 je 297 × 420, spadávka 3 mm z každé strany přidá 6 mm. 300 ppi je tisk.
|
||||
|
||||
## Jak je rozostřené pozadí?
|
||||
- [x] 8 px, předmět zůstane ostrý
|
||||
- 8 px přes celý plakát včetně textu
|
||||
- 80 % Doostření na pozadí
|
||||
- Nijak
|
||||
> Rozostření oddělí pozadí. Text a hlavní předmět jsou ostré.
|
||||
|
||||
## Co je ve webovém JPG navíc chyba?
|
||||
- sRGB a 1600 px
|
||||
- [x] Ořezové značky
|
||||
- Kvalita kolem 10
|
||||
- Název akce
|
||||
> Značky jsou pro tiskárnu. Na webu vypadají jako čáry v rozích.
|
||||
|
||||
## Který soubor musí obsahovat vrstvy?
|
||||
- plakat-web.jpg
|
||||
- [x] plakat.psd
|
||||
- plakat-tisk.pdf
|
||||
- Žádný
|
||||
> PSD je práce. JPG a PDF jsou ploché kopie.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Project and media
|
||||
popis: A Full HD sequence, 25 fps and bins for the media.
|
||||
nazev_cviceni: Quiz: the project
|
||||
nadpis_kvizu: Set up the right sequence
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-projekt
|
||||
nazev: Projekt a média
|
||||
popis: Sekvence Full HD, 25 sn/s a složky materiálu.
|
||||
nazev_cviceni: Kvíz: projekt
|
||||
nadpis_kvizu: Založte správnou sekvenci
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Projekt
|
||||
*Soubor*
|
||||
|
||||
- Premiere ukládá práci do projektu s příponou prproj. Video v něm není, jsou v něm odkazy.
|
||||
- Materiál a projekt mějte v jedné složce. Když video přesunete, Premiere ho nenajde.
|
||||
- Ztracený soubor se připojí znovu: pravý klik, Propojit médium, a ukážete novou cestu.
|
||||
- Automatické ukládání nechte zapnuté. Projekt se jinak po pádu nevrátí celý.
|
||||
|
||||
> Tip: prproj není mp4. Otevře ho jen Premiere. Na odevzdání videa je až export.
|
||||
|
||||
## Sekvence
|
||||
*25 sn/s*
|
||||
|
||||
- Sekvence je časová osa s daným rozměrem a snímkovou frekvencí.
|
||||
- Školní zadání: 1920 × 1080, čtvercové pixely, 25 snímků za sekundu.
|
||||
- 25 sn/s je běžné evropské video. Materiál z telefonu má často 30. Sekvenci přesto založte na 25, Premiere snímky přepočítá.
|
||||
- Pojmenujte ji skolni-den. Název Sekvence 01 se ve větším projektu ztratí.
|
||||
|
||||
> Tip: Nová sekvence je v panelu Projekt ikonou nového objektu. Předvolba DSLR nebo Digital SLR 1080p25 se trefí.
|
||||
|
||||
## Složky
|
||||
*Pořádek*
|
||||
|
||||
- V panelu Projekt založte složky Záběry, Zvuk a Grafika.
|
||||
- Import je Ctrl+I, nebo soubor přetáhnete do správné složky.
|
||||
- Do Grafiky patří logo a titulky. Do Zvuku hudba a komentář. Do Záběrů jen video.
|
||||
- Na časovou osu netáhněte deset záběrů najednou, dokud ve složce nemají pořádek.
|
||||
|
||||
> Tip: Přejmenujte záběry podle místa, ne podle DSC_1842. Za rok nepoznáte, co to bylo.
|
||||
|
||||
## Zadání: prázdný projekt
|
||||
*Cvičení*
|
||||
|
||||
- Založte skolni-den.prproj ve složce, kde už leží záběry.
|
||||
- Sekvence skolni-den: 1920 × 1080, 25 sn/s.
|
||||
- Tři složky: Zabery, Zvuk, Grafika. Importujte aspoň jeden záběr a jednu hudbu do správných složek.
|
||||
- Projekt uložte. Mp4 ještě nedělejte.
|
||||
|
||||
> Tip: Když Premiere hlásí, že sekvence nesedí se záběrem, nechte sekvenci na 25. Je to zadání, ne chyba souboru.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jakou příponu má projekt Premiere?
|
||||
- mp4
|
||||
- [x] prproj
|
||||
- psd
|
||||
- svg
|
||||
> prproj je projekt. mp4 vznikne až exportem.
|
||||
|
||||
## Jaká je školní sekvence?
|
||||
- 1280 × 720, 60 sn/s
|
||||
- [x] 1920 × 1080, 25 sn/s
|
||||
- 303 × 426 mm
|
||||
- A4, 300 ppi
|
||||
> Full HD a 25 snímků za sekundu. Milimetry patří plakátu, ne videu.
|
||||
|
||||
## Kam v projektu patří hudba?
|
||||
- Do složky Záběry
|
||||
- [x] Do složky Zvuk
|
||||
- Přímo do názvu sekvence
|
||||
- Do PSD
|
||||
> Záběry, Zvuk a Grafika se nemíchají. Jinak desátý soubor už nenajdete.
|
||||
|
||||
## Co uděláte, když Premiere po přesunu složky video nevidí?
|
||||
- Natočíte ho znovu
|
||||
- [x] Propojíte médium a ukážete novou cestu
|
||||
- Převedete projekt do JPG
|
||||
- Změníte sekvenci na 72 ppi
|
||||
> Projekt si pamatuje cestu. Propojit médium ji opraví, záběr se netočil znovu.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: The timeline and the cut
|
||||
popis: Cuts with no gaps, 45 seconds long.
|
||||
nazev_cviceni: Quiz: the cut
|
||||
nadpis_kvizu: Pick the tool and the length
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-strih
|
||||
nazev: Časová osa a střih
|
||||
popis: Střih záběrů bez mezer, délka 45 sekund.
|
||||
nazev_cviceni: Kvíz: střih
|
||||
nadpis_kvizu: Vyberte nástroj a délku
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Stopy
|
||||
*Obraz a zvuk*
|
||||
|
||||
- V1 je první obrazová stopa, A1 první zvuková. Vyšší V leží vizuálně nad nižší.
|
||||
- Záběr z kamery přinese obraz i zvuk. Na ose jsou spojené, dokud je nerozdělíte.
|
||||
- Titulek patří na V2, ať nepřepíše záběr na V1. Sundáte ho a obraz pod ním zůstane.
|
||||
- Mezera na ose je černé pole ve filmu. Mezi záběry být nemá.
|
||||
|
||||
> Tip: Když přetáhnete jen obraz, držte Alt. Zvuk zůstane na místě, nebo se naopak nevezme.
|
||||
|
||||
## Nástroje
|
||||
*Žiletka*
|
||||
|
||||
- V je výběr. C je žiletka, rozřízne záběr v místě přehrávací hlavy.
|
||||
- I označí začátek, O konec. Čárka vloží výběr a zbytek odsunete. Tečka výběr přepíše.
|
||||
- Delete smaže a nechá díru. Shift+Delete, nebo vyjmutí s uzavřením mezery, díru zatáhne.
|
||||
- Mezerník přehrává. Šipky vlevo a vpravo jedou po střihu.
|
||||
|
||||
> Tip: Po žiletce přepněte zpět na V. Jinak další klik zase řeže.
|
||||
|
||||
## Co nechat
|
||||
*45 sekund*
|
||||
|
||||
- Ze surového záznamu nechte to, co nese větu nebo děj. Rozjezd a konec kamery pryč.
|
||||
- Školní sestřih tohoto cvičení má 45 sekund. Kratší nestihne nic říct, delší se rozpadá.
|
||||
- Střih je na pohybu nebo na začátku věty, ne uprostřed slova.
|
||||
- Stejný záběr dvakrát po sobě nechte jen schválně. Jinak to vypadá jako chyba.
|
||||
|
||||
> Tip: Délku sekvence čtete vpravo dole nebo na konci posledního záběru. 00:00:45:00 je 45 sekund.
|
||||
|
||||
## Zadání: sestřih
|
||||
*Cvičení*
|
||||
|
||||
- Na ose skolni-den sestříhejte 45 sekund. Začátek je 00:00:00:00, konec 00:00:45:00.
|
||||
- Mezi záběry není mezera. Černý snímek uprostřed je chyba.
|
||||
- Aspoň čtyři různé záběry. Žádný kratší než jedna sekunda.
|
||||
- Uložte projekt. Export až v pozdější lekci.
|
||||
|
||||
> Tip: Když je konec 00:00:45:10, máte o 10 snímků navíc. U 25 sn/s je to necelá půlsekunda, zkraťte to.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Čím se záběr rozřízne?
|
||||
- Nástrojem V
|
||||
- [x] Žiletkou, klávesa C
|
||||
- Exportem H.264
|
||||
- Krytím 70 %
|
||||
> C je žiletka. V je výběr, tím se záběr posouvá, neřeže.
|
||||
|
||||
## Jak dlouhý je sestřih v této lekci?
|
||||
- [x] 45 sekund
|
||||
- 8 sekund
|
||||
- 4 minuty
|
||||
- 303 mm
|
||||
> 00:00:45:00. Titulky a export přijdou později, teď je čistý střih.
|
||||
|
||||
## Co je chyba uprostřed sestřihu?
|
||||
- Střih na začátku věty
|
||||
- [x] Černá mezera mezi záběry
|
||||
- Záběr delší než sekunda
|
||||
- Stopa V1
|
||||
> Díra na ose je ve filmu černá. Po smazání ji zatáhněte.
|
||||
|
||||
## Kam patří titulek, aby šel sundat bez ztráty záběru?
|
||||
- Místo obrazu na V1
|
||||
- [x] Na stopu V2 nad záběrem
|
||||
- Do složky Zvuk
|
||||
- Do PSD plakátu
|
||||
> V2 leží nad V1. Vypnete ho a záběr pod ním pokračuje.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Pace and transitions
|
||||
popis: A hard cut as the default, one short dissolve.
|
||||
nazev_cviceni: Quiz: transitions
|
||||
nadpis_kvizu: Choose the length of the dissolve
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-prechody
|
||||
nazev: Tempo a přechody
|
||||
popis: Tvrdý střih jako základ, jedna krátká prolínačka.
|
||||
nazev_cviceni: Kvíz: přechody
|
||||
nadpis_kvizu: Zvolte délku prolínačky
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Střih stačí
|
||||
*Přechod*
|
||||
|
||||
- Obyčejný střih je nejčistší. Přechod mezi každými dvěma záběry film zpomalí a vypadá jako šablona.
|
||||
- Prolínačku berte na změnu času nebo na vstup titulku, ne na každý řez.
|
||||
- Stírání, hvězdičky a stránkování ve školním dokumentu nemají co dělat.
|
||||
- Jeden typ přechodu v celém videu. Druhý je už výstřednost.
|
||||
|
||||
> Tip: Přechod přetáhnete z panelu Účinky mezi dva záběry. Dvojklik otevře délku.
|
||||
|
||||
## Délka
|
||||
*12 snímků*
|
||||
|
||||
- Při 25 sn/s je sekunda 25 snímků. Půl sekundy je zhruba 12 snímků.
|
||||
- Školní prolínačka má 12 snímků. Delší než sekunda už je nálada, ne střih.
|
||||
- Přechod potřebuje materiál za řezem. Když záběr končí přesně na řezu, Premiere ho nemá čím prolnout a konec zmrazí.
|
||||
- Proto neřežte záběr úplně na doraz, když víte, že na něj přijde prolínačka.
|
||||
|
||||
> Tip: 12 snímků je 00:00:00:12. V časovém kódu jsou snímky až za poslední dvojtečkou.
|
||||
|
||||
## Rychlost
|
||||
*Polovina*
|
||||
|
||||
- Pravý klik na záběr, Rychlost a trvání. 50 % ho přehraje poloviční rychlostí a dvakrát prodlouží.
|
||||
- 100 % je normální tempo. 200 % je dvojnásobná rychlost a poloviční délka.
|
||||
- Zpomalení použijte na jeden záběr, který má být čtený: vstup do dveří, pohled, detail.
|
||||
- Zvuk zpomalený na 50 % je bručivý. U zpomaleného záběru ho oddělte a nechte původní, nebo ho ztichte.
|
||||
|
||||
> Tip: Když má zůstat délka a změnit se jen tempo, hlídejte zaškrtnutí, které drží nebo nedrží délku záběru.
|
||||
|
||||
## Zadání: jeden přechod, jedno tempo
|
||||
*Cvičení*
|
||||
|
||||
- V 45sekundovém sestřihu nechte tvrdé střihy.
|
||||
- Jednu prolínačku dejte jen před titulek nebo mezi dvě místa. Délka 12 snímků.
|
||||
- Jeden záběr zpomalte na 50 % a jeho zvuk nechte v původní rychlosti, nebo ho vypněte.
|
||||
- Délka celku ať zůstane čitelná. Když se sekvence protáhne, zkraťte jiný záběr.
|
||||
|
||||
> Tip: Přehrávání od prolínačky: mezerník. Když obraz na vteřinu zmrzne, záběru chybí přesah.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak dlouhá je školní prolínačka?
|
||||
- [x] 12 snímků
|
||||
- 12 sekund
|
||||
- 4 minuty
|
||||
- 3 mm
|
||||
> 12 snímků při 25 sn/s je necelá půlsekunda. 12 sekund by bylo uspávací.
|
||||
|
||||
## Kolik prolínaček má být v tomto cvičení?
|
||||
- Mezi všemi záběry
|
||||
- [x] Jedna
|
||||
- Žádná nikdy, ani před titulkem
|
||||
- Deset různých typů
|
||||
> Základ je tvrdý střih. Jedna prolínačka má důvod, deset je šablona.
|
||||
|
||||
## Co udělá rychlost 50 %?
|
||||
- Záběr zrychlí na dvojnásobek
|
||||
- [x] Přehrá ho poloviční rychlostí a prodlouží
|
||||
- Ořízne ho na 50 px
|
||||
- Převede ho do CMYK
|
||||
> 50 % je polovina tempa. 200 % je dvojnásobná rychlost.
|
||||
|
||||
## Proč prolínačka na konci záběru někdy zmrazí obraz?
|
||||
- Sekvence je v PNG
|
||||
- [x] Za řezem už není materiál, kterým by šla prolnout
|
||||
- Chybí spadávka
|
||||
- Hudba je moc potichu
|
||||
> Přechod potřebuje snímky za střihem. Doraz na posledním snímku je nemá.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Titles
|
||||
popis: An opening and a closing, four seconds each.
|
||||
nazev_cviceni: Quiz: titles
|
||||
nadpis_kvizu: Fill in the time and the size
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-titulky
|
||||
nazev: Titulky
|
||||
popis: Úvod a závěr, každé po čtyřech sekundách.
|
||||
nazev_cviceni: Kvíz: titulky
|
||||
nadpis_kvizu: Doplňte čas a velikost
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Kde se píšou
|
||||
*Grafika*
|
||||
|
||||
- Titulek je vrstva na ose, ne text vypálený do záběru ve Photoshopu.
|
||||
- Panel Základní grafika, nebo nástroj text nad obrazem v programu, založí textovou vrstvu.
|
||||
- Úvodní titulek leží na začátku na V2. Závěrečný na konci.
|
||||
- Písmo nechte jedno. Bílé na tmavém podkladu, nebo tmavé na světlém pruhu.
|
||||
|
||||
> Tip: Když text píšete do záběru razítkem, už ho nepřepíšete. Vrstva textu jde opravit kdykoli.
|
||||
|
||||
## Velikost a čas
|
||||
*4 sekundy*
|
||||
|
||||
- Nadpis Školní den má kolem 72 pt. Jméno autora kolem 36 pt.
|
||||
- Každý titulek trvá 4 sekundy. Kratší nestačí přečíst, delší drží obraz zbytečně.
|
||||
- 4 sekundy při 25 sn/s jsou 100 snímků.
|
||||
- Mezi úvodním titulkem a prvním záběrem může být prolínačka 12 snímků z minulé lekce.
|
||||
|
||||
> Tip: Délku textové vrstvy táhnete za konec na ose jako záběr. Číslo 00:00:04:00 je přesně čtyři sekundy.
|
||||
|
||||
## Bezpečný okraj
|
||||
*Nepřeříznout*
|
||||
|
||||
- Text nepatří až k hraně obrazu. Od kraje nechte aspoň 80 px.
|
||||
- Televize a některé přehrávače kraj oříznou. Co je 40 px od hrany, může zmizet.
|
||||
- Dlouhý název rozdělte na dva řádky. Jeden řádek přes celou šířku je malý, nebo přeteče.
|
||||
- Zarovnání na střed jen u titulku. U seznamu jmen nechte zarovnání vlevo.
|
||||
|
||||
> Tip: V nastavení náhledu se dá zapnout bezpečná oblast. Vnitřní rámeček je pro text.
|
||||
|
||||
## Zadání: úvod a závěr
|
||||
*Cvičení*
|
||||
|
||||
- Na začátek dejte 4 sekundy titulku Školní den, kolem 72 pt, aspoň 80 px od kraje.
|
||||
- Na konec 4 sekundy se jménem autora, kolem 36 pt.
|
||||
- Oba texty jsou na V2 a jdou přepsat. Nejsou vypálené v záběru.
|
||||
- Projekt uložte. Délka sekvence teď smí být delší než 45 sekund o těchto 8 sekund.
|
||||
|
||||
> Tip: Když titulek leží na V1 místo záběru, přesuňte ho na V2. Záběr pod ním ať pokračuje, nebo ať je pod úvodem prázdná plocha schválně.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak dlouho trvá úvodní titulek?
|
||||
- [x] 4 sekundy
|
||||
- 12 snímků
|
||||
- 45 sekund
|
||||
- 1 snímek
|
||||
> Čtyři sekundy se dají přečíst. 12 snímků je délka prolínačky, ne titulku.
|
||||
|
||||
## Jak velké je zhruba jméno autora?
|
||||
- 8 pt
|
||||
- [x] kolem 36 pt
|
||||
- 300 pt
|
||||
- 1600 px
|
||||
> Nadpis je kolem 72 pt, jméno menší, kolem 36. Pořád čitelné na telefonu.
|
||||
|
||||
## Jak daleko od kraje má text být?
|
||||
- Až v posledních 10 px
|
||||
- [x] Aspoň 80 px
|
||||
- Ve spadávce 3 mm
|
||||
- To je jedno, video se neořezává
|
||||
> Kraj obrazu přehrávač někdy seřízne. 80 px text udrží uvnitř.
|
||||
|
||||
## Na které stopě má titulek ležet?
|
||||
- A1
|
||||
- [x] V2
|
||||
- Jen v JPG plakátu
|
||||
- Místo zvuku
|
||||
> V2 je nad obrazem. Titulek jde sundat a záběr zůstane.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Sound
|
||||
popis: Speech, music under it and a one-second fade.
|
||||
nazev_cviceni: Quiz: sound
|
||||
nadpis_kvizu: Set the levels
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-zvuk
|
||||
nazev: Zvuk
|
||||
popis: Řeč, hudba pod ní a jedna sekunda náběhu.
|
||||
nazev_cviceni: Kvíz: zvuk
|
||||
nadpis_kvizu: Nastavte hladiny
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Dvě hladiny
|
||||
*Řeč a hudba*
|
||||
|
||||
- Řeč je hlavní. Na ukazateli ať se drží kolem −6 dB a do červené nuly nelezete.
|
||||
- Hudba sama o sobě kolem −15 dB. Pod řečí ji stáhněte ještě na −24 dB.
|
||||
- Dva stejně hlasité zdroje se přebijí. Divák pak neslyší ani jeden pořádně.
|
||||
- Ztlumení je klíčový snímek hlasitosti na klipu, ne jednou provždy na celou píseň, pokud pod ní jen občas mluvíte.
|
||||
|
||||
> Tip: Pravý klik na zvukový klip a zobrazení klíčových snímků hlasitosti. Přidáte je perem na čáře.
|
||||
|
||||
## Náběh
|
||||
*1 sekunda*
|
||||
|
||||
- Hudba nemá nastoupit v plné hlasitosti na prvním snímku. Náběh 1 sekundu.
|
||||
- Konec hudby stejně tak: jednu sekundu do ticha, ať video neuskakuje.
|
||||
- Náběh je taky klíčový snímek, z ticha na cílovou hladinu.
|
||||
- Střih hudby uprostřed taktu je slyšet. Řežte v pauze nebo na začátku fráze.
|
||||
|
||||
> Tip: 1 sekunda je 25 snímků. Na ose je to krátký úsek, ne celý titulek.
|
||||
|
||||
## Střih zvuku napřed
|
||||
*J-cut*
|
||||
|
||||
- J-cut znamená, že zvuk dalšího záběru začne dřív než jeho obraz.
|
||||
- Nejdřív je slyšet věta, až pak se obraz přepne na mluvčího. Střih je měkčí než tvrdý řez obou stop.
|
||||
- Obraz a zvuk jednoho klipu rozdělíte pravým klikem, Zrušit propojení, a zvuk přetáhnete doleva.
|
||||
- Ve školním videu stačí jeden takový střih. Nemusí být všude.
|
||||
|
||||
> Tip: Když zvuk předběhne obraz o víc než půl sekundy, už to působí jako chyba synchronu. Držte se kolem 10 až 15 snímků.
|
||||
|
||||
## Zadání: hudba pod řečí
|
||||
*Cvičení*
|
||||
|
||||
- Hudbu dejte pod sestřih. Mimo řeč kolem −15 dB, pod řečí −24 dB.
|
||||
- Náběh i doběh hudby 1 sekunda.
|
||||
- Řeč srovnejte kolem −6 dB. Červená nula na ukazateli je chyba.
|
||||
- Jeden přechod mezi záběry udělejte jako J-cut: zvuk o kousek dřív než obraz.
|
||||
|
||||
> Tip: Sluchátka odhalí hukot, reproduktor v učebně ho schová. Poslechněte si to jednou na sluchátkách.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Kde má být hudba, když zrovna někdo mluví?
|
||||
- [x] Kolem −24 dB
|
||||
- Na nule
|
||||
- Vypnutá natrvalo i v místech bez řeči
|
||||
- Hlasitější než řeč
|
||||
> Řeč je kolem −6 dB. Hudba pod ní musí ustoupit, školní hladina je −24 dB.
|
||||
|
||||
## Jak dlouhý je náběh hudby?
|
||||
- [x] 1 sekunda
|
||||
- 12 sekund
|
||||
- 4 minuty
|
||||
- Náběh se nedělá
|
||||
> Jedna sekunda z ticha. Nástup v plné hlasitosti na prvním snímku je skok.
|
||||
|
||||
## Co je J-cut?
|
||||
- Obraz dalšího záběru začne dřív než jeho zvuk
|
||||
- [x] Zvuk dalšího záběru začne dřív než jeho obraz
|
||||
- Střih uprostřed slova
|
||||
- Přechod hvězdičkou
|
||||
> Nejdřív je slyšet, až pak je vidět. Opačné pořadí je L-cut.
|
||||
|
||||
## Kam nesmí ukazatel řeči?
|
||||
- K −6 dB
|
||||
- [x] Do červené nuly
|
||||
- Na stopu A1
|
||||
- Pod hudbu
|
||||
> Nula je přebuzení. Řeč se drží pod ní, kolem −6 dB.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Colour in video
|
||||
popis: Exposure first, then contrast, saturation last.
|
||||
nazev_cviceni: Quiz: video colour
|
||||
nadpis_kvizu: Put the steps in order
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-barva
|
||||
nazev: Barva ve videu
|
||||
popis: Nejdřív expozice, potom kontrast, sytost až nakonec.
|
||||
nazev_cviceni: Kvíz: barva videa
|
||||
nadpis_kvizu: Seřaďte postup
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Lumetri
|
||||
*Jeden panel*
|
||||
|
||||
- Barva záběru se dělá efektem Lumetri Color, ne exportem přes Photoshop.
|
||||
- Efekt dejte na záběr, nebo na úpravu vrstvy nad stopou, ať se dá vypnout.
|
||||
- Nejdřív srovnejte expozici, ať není záběr tmavý nebo přepálený.
|
||||
- Pak kontrast, nakonec sytost. Sytá tmavá fotka se špatně zachraňuje.
|
||||
|
||||
> Tip: Panel Barva Lumetri otevřete z nabídky Okno. Když efekt jen přetáhnete a panel zavřete, hodnoty stejně zůstanou na klipu.
|
||||
|
||||
## Dva záběry vedle sebe
|
||||
*Srovnat*
|
||||
|
||||
- Střih mezi teplým a studeným záběrem je vidět víc než samotná barva.
|
||||
- Druhý záběr přiblížte prvnímu: podobné stíny, podobná pleť.
|
||||
- Pleť nenechte oranžovou. Když je sytost vysoko, uberte ji dřív, než přidáte teplou barvu.
|
||||
- Jeden záběr smí být černobílý schválně. Sytost 0. Ostatní nechte barevné.
|
||||
|
||||
> Tip: Oko porovná záběry, když je přehrajete přes střih. Zastavený snímek klame.
|
||||
|
||||
## LUT až potom
|
||||
*Míra*
|
||||
|
||||
- LUT je hotová tabulka vzhledu. Dá se na záběr jako vzhled, ne jako první krok.
|
||||
- Intenzitu LUT nechte kolem 50 %, když záběr přebarví moc.
|
||||
- Dva různé LUT v jednom minutovém videu působí jako dvě školy. Stačí jeden, nebo žádný.
|
||||
- Bez LUT, jen se srovnanou expozicí, je video často čistší.
|
||||
|
||||
> Tip: LUT na přepálenou oblohu kresbu nevrátí. Nejdřív expozice, tabulka až na srovnaný obraz.
|
||||
|
||||
## Zadání: srovnat a jeden bez barvy
|
||||
*Cvičení*
|
||||
|
||||
- Dva sousední záběry srovnejte Lumetri: nejdřív expozice, pak kontrast, sytost jen mírně, třeba +10.
|
||||
- Jeden jiný záběr dejte na sytost 0, ať je černobílý schválně a krátce.
|
||||
- LUT buď žádný, nebo jeden na intenzitě nejvýš 50 %.
|
||||
- Efekt ať jde vypnout. Vypnuté Lumetri vrátí původní barvu záběru.
|
||||
|
||||
> Tip: Když vypnutí efektu nic nezmění, upravovali jste jiný klip. Efekt je na tom, který je na ose vybraný.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## V jakém pořadí se barva srovnává?
|
||||
- Nejdřív sytost, pak třeba expozice
|
||||
- [x] Nejdřív expozice, pak kontrast, sytost nakonec
|
||||
- Nejdřív LUT, surový záběr se nechá
|
||||
- Barva se ve videu nedělá
|
||||
> Špatně světlý záběr sytost jen zhorší. Nejdřív světlo, potom síla barvy.
|
||||
|
||||
## Jak uděláte jeden záběr černobílý?
|
||||
- Smažete stopu V1
|
||||
- [x] Sytost na 0
|
||||
- Exportem do JPG
|
||||
- Rychlostí 50 %
|
||||
> Sytost 0 nechá jas a vezme barvu. Ostatní záběry zůstanou barevné.
|
||||
|
||||
## Jak vysoko necháte intenzitu LUT, když barví moc?
|
||||
- 100 % vždy
|
||||
- [x] Kolem 50 %
|
||||
- 0 %, ale LUT stejně všechno přebarví
|
||||
- 300 %
|
||||
> LUT je volba vzhledu, ne povinnost. Poloviční intenzita ho podrží na uzdě.
|
||||
|
||||
## Čím se barva na záběru vypne?
|
||||
- Smazáním projektu
|
||||
- [x] Vypnutím efektu Lumetri
|
||||
- Převodem sekvence na 72 ppi
|
||||
- To nejde, export je trvalý už na ose
|
||||
> Efekt na klipu jde vypnout. Dokud není video exportované, původní záběr zůstává.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Exporting the video
|
||||
popis: H.264, Full HD, 25 fps and 10 Mb/s.
|
||||
nazev_cviceni: Quiz: the video export
|
||||
nadpis_kvizu: Pick the format and the bitrate
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-export
|
||||
nazev: Export videa
|
||||
popis: H.264, Full HD, 25 sn/s a 10 Mb/s.
|
||||
nazev_cviceni: Kvíz: export videa
|
||||
nadpis_kvizu: Vyberte formát a datový tok
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Formát
|
||||
*H.264*
|
||||
|
||||
- Odevzdává se MP4 s kodekem H.264. Otevře ho telefon, projektor i Windows.
|
||||
- Formát projektu prproj nikdo bez Premiere nepustí. Není to výstup.
|
||||
- Sekvence 1920 × 1080 a 25 sn/s se do exportu přenese. Neměňte ji při exportu na 1280 × 720, pokud to zadání nechce.
|
||||
- Zvuk nechte v exportu zapnutý. Němý výstup je často jen odškrtnutý zvuk, ne záměr.
|
||||
|
||||
> Tip: Soubor > Export > Média. Zkratka Ctrl+M. Náhled vpravo ukáže první snímek, ne celý střih.
|
||||
|
||||
## Datový tok
|
||||
*10 Mb/s*
|
||||
|
||||
- Cílový datový tok 10 Mb/s stačí na školní Full HD. Vyšší soubor zbytečně naroste.
|
||||
- 1 Mb/s už na 1080p kostkuje, hlavně v pohybu. 10 je klidná střední hodnota.
|
||||
- Nastavení zdroje, nebo shoda se sekvencí, podrží 25 sn/s a rozměr.
|
||||
- Dva průchody export zpřesní, ale trvá déle. Na školní video stačí jeden.
|
||||
|
||||
> Tip: Mb/s je megabit za sekundu, ne megabajt. Minutové video při 10 Mb/s má zhruba 75 MB.
|
||||
|
||||
## Rozsah
|
||||
*Celá sekvence*
|
||||
|
||||
- Exportujte celou sekvenci, ne jen výběr mezi body In a Out, pokud jste je nechali uprostřed.
|
||||
- Zaškrtnutí, které exportuje jen vstup až výstup, umí oříznout film na pět sekund.
|
||||
- Název souboru skolni-den.mp4. Cesta ať vede do složky projektu, ne na plochu.
|
||||
- Po exportu soubor pusťte mimo Premiere. V náhledu programu chybu často nevidíte.
|
||||
|
||||
> Tip: Když je film moc krátký, otevřete body In a Out na ose. Ctrl+Shift+X je zruší.
|
||||
|
||||
## Zadání: první mp4
|
||||
*Cvičení*
|
||||
|
||||
- Exportujte skolni-den.mp4, H.264, 1920 × 1080, 25 sn/s, cílový tok 10 Mb/s.
|
||||
- Zvuk je v souboru. Úvodní titulek je hned na začátku, ne po deseti sekundách černé.
|
||||
- Projekt prproj nechte vedle mp4. Mp4 samo o sobě nejde znovu střihnout po vrstvách.
|
||||
- Soubor přehrajte celý. Jednou. Zastavte se na titulku, na prolínačce a na konci hudby.
|
||||
|
||||
> Tip: Když přehrávač hlásí, že soubor nejde otevřít, export nedoběhl. V Premiere je fronta, podívejte se, jestli neskončil chybou.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Který soubor se odevzdává jako video?
|
||||
- prproj
|
||||
- [x] mp4 v H.264
|
||||
- psd
|
||||
- svg
|
||||
> MP4 otevře i člověk bez Premiere. Projekt je zdroj.
|
||||
|
||||
## Jaký datový tok má školní Full HD?
|
||||
- [x] 10 Mb/s
|
||||
- 1 Mb/s
|
||||
- 300 ppi
|
||||
- 72 Mb/s vždy
|
||||
> 10 Mb/s je na 1080p25 dost. 1 Mb/s se v pohybu rozpadá.
|
||||
|
||||
## Co zkontrolujete, když je export dlouhý jen pár sekund?
|
||||
- Spadávku
|
||||
- [x] Jestli se neexportoval jen úsek mezi In a Out
|
||||
- Režim CMYK
|
||||
- Krytí pruhu
|
||||
> Body In a Out omezí export na výběr. Zrušte je a exportujte celou sekvenci.
|
||||
|
||||
## Proč nestačí odevzdat jen prproj?
|
||||
- Premiere ho neumí uložit
|
||||
- [x] Bez Premiere ho nikdo nepřehraje a média mohou chybět
|
||||
- Nemá 25 sn/s
|
||||
- Je to totéž co mp4
|
||||
> Projekt je odkaz na střih. Film je až mp4.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Assignment: a short video
|
||||
popis: 40 to 60 seconds, titles, sound and one J-cut.
|
||||
nazev_cviceni: Quiz: the short video
|
||||
nadpis_kvizu: Check the length and the export
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-3-zadani-video
|
||||
nazev: Zadání: krátké video
|
||||
popis: 40 až 60 sekund, titulky, zvuk a jeden J-cut.
|
||||
nazev_cviceni: Kvíz: krátké video
|
||||
nadpis_kvizu: Zkontrolujte délku a export
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Délka a obsah
|
||||
*40 až 60 s*
|
||||
|
||||
- Hotové video trvá 40 až 60 sekund včetně titulků.
|
||||
- Téma je školní den: místo, lidé, jedna věta o tom, co se děje.
|
||||
- Úvodní titulek Školní den trvá 4 sekundy. Závěrečný se jménem taky 4 sekundy.
|
||||
- Aspoň čtyři záběry. Žádný pod jednu sekundu, kromě případného černobílého detailu.
|
||||
|
||||
> Tip: Délku čtete na konci posledního titulku. Titulky se do limitu počítají.
|
||||
|
||||
## Střih a obraz
|
||||
*Pravidla*
|
||||
|
||||
- Mezi záběry nejsou černé mezery. Střihy jsou tvrdé.
|
||||
- Jedna prolínačka, 12 snímků, nejlépe mezi titulkem a záběrem.
|
||||
- Jeden záběr smí být na 50 % rychlosti. Jeden smí mít sytost 0.
|
||||
- Barva je srovnaná Lumetri: expozice, kontrast, sytost. Nejvýš jeden LUT na 50 %.
|
||||
|
||||
> Tip: V2 je na titulky. Obrazové záběry ať zůstanou na V1, ať se ve stopách neztratíte.
|
||||
|
||||
## Zvuk
|
||||
*Hladiny*
|
||||
|
||||
- Řeč kolem −6 dB, bez červené nuly.
|
||||
- Hudba mimo řeč −15 dB, pod řečí −24 dB. Náběh a doběh 1 sekunda.
|
||||
- Jeden J-cut: zvuk dalšího záběru začne dřív než obraz.
|
||||
- Hudba nekončí uprostřed slova ani uprostřed taktu, pokud to jde střihnout jinak.
|
||||
|
||||
> Tip: Poslechněte si export, ne jen osu. Export umí zvuk vynechat, když je odškrtnutý.
|
||||
|
||||
## Odevzdání
|
||||
*Dva soubory*
|
||||
|
||||
- skolni-den.prproj ve složce s médií, složky Zabery, Zvuk, Grafika.
|
||||
- skolni-den.mp4, H.264, 1920 × 1080, 25 sn/s, 10 Mb/s.
|
||||
- Mp4 pusťte od začátku do konce mimo Premiere.
|
||||
- Když média přesouváte, nejdřív složku celou. Rozbitý odkaz je neodevzdaná práce.
|
||||
|
||||
> Tip: Na začátku mp4 má být titulek, ne černá. Černá znamená, že sekvence začíná později než export.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak dlouhé je hotové video i s titulky?
|
||||
- Přesně 45 sekund bez titulků
|
||||
- [x] 40 až 60 sekund
|
||||
- 8 sekund
|
||||
- 4 minuty
|
||||
> Titulky se počítají. Pod 40 sekund téma nestačí, nad minutu se školní sestřih rozpadá.
|
||||
|
||||
## Jak dlouhé jsou oba titulky?
|
||||
- 12 snímků
|
||||
- [x] 4 sekundy každý
|
||||
- 1 sekunda
|
||||
- Dokud hraje hudba
|
||||
> Čtyři sekundy na úvod, čtyři na jméno. 12 snímků je prolínačka.
|
||||
|
||||
## Kam patří hudba v okamžiku, kdy mluví člověk?
|
||||
- [x] −24 dB
|
||||
- 0 dB
|
||||
- Stejně nahlas jako řeč
|
||||
- Hudba se pod řeč nedává nikdy, ani ztišená
|
||||
> Řeč zůstává kolem −6 dB. Hudba pod ní ustoupí na −24 dB.
|
||||
|
||||
## Jaký je export?
|
||||
- prproj jako jediný soubor
|
||||
- [x] mp4, H.264, 1920 × 1080, 25 sn/s, 10 Mb/s
|
||||
- JPG 1600 px
|
||||
- PDF se spadávkou
|
||||
> Film je mp4. Projekt se odevzdává k němu, ne místo něj.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Illustrator: the artboard
|
||||
popis: Curves, the V, A and P tools, an artboard for the screen.
|
||||
nazev_cviceni: Quiz: Illustrator
|
||||
nadpis_kvizu: Name the tool
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-illustrator
|
||||
nazev: Illustrator: plocha a nástroje
|
||||
popis: Křivky, nástroje V, A a P, plátno pro obrazovku.
|
||||
nazev_cviceni: Kvíz: Illustrator
|
||||
nadpis_kvizu: Poznejte nástroj
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Proč Illustrator
|
||||
*Křivka*
|
||||
|
||||
- Illustrator kreslí křivky. Logo z něj vytisknete na vizitku i na banner a hrana zůstane hladká.
|
||||
- Photoshopové logo z malého PNG sem nepatří. Vektor se tu staví znovu, nebo se otevře SVG a AI.
|
||||
- Soubor je AI. Na výměnu s jiným programem se hodí i SVG a PDF.
|
||||
- Na fotku Illustrator není. Fotka sem patří jen jako podklad, který pak skryjete.
|
||||
|
||||
> Tip: Když v náhledu na 800 % uvidíte pixely, není to křivka. Je to vložená bitmapa.
|
||||
|
||||
## Tři nástroje
|
||||
*V, A, P*
|
||||
|
||||
- V je výběr. Posouvá a mění celý objekt.
|
||||
- A je přímý výběr. Táhne jeden kotevní bod, zbytek tvaru nechá.
|
||||
- P je pero. Klik klade body, tah klade křivku. Pero je hlavní kreslicí nástroj.
|
||||
- Na první cvičení pero nepotřebujete celé. Obdélník a elipsa stačí.
|
||||
|
||||
> Tip: Na Macu jsou zkratky stejné. Přepínají se jednou klávesou, bez Cmd.
|
||||
|
||||
## Plátno
|
||||
*1920 × 1080*
|
||||
|
||||
- Nový dokument pro obrazovku: 1920 × 1080 px, RGB, jeden artboard.
|
||||
- Pro tisk se později založí milimetrový artboard. Teď je to obrazovka, ať sedí s Premiere a Photoshopem.
|
||||
- Artboard není vrstva. Je to papír. Objekty mimo něj se neexportují, ale v souboru jsou.
|
||||
- Bílé pozadí artboardu není objekt. Když chcete barvu v pozadí, nakreslete obdélník.
|
||||
|
||||
> Tip: Více artboardů přijde u loga ve variantách. Zatím jeden.
|
||||
|
||||
## Zadání: dva tvary
|
||||
*Cvičení*
|
||||
|
||||
- Dokument znacka-podklad.ai, 1920 × 1080 px, RGB.
|
||||
- Nakreslete jeden obdélník a jednu elipsu. Každý ať má výplň a žádný tah, nebo tah 2 pt schválně.
|
||||
- Elipsu vyberte nástrojem A a vytáhněte jeden kotevní bod, ať není pravidelná.
|
||||
- Uložte AI. Do JPG to zatím nepřevádějte.
|
||||
|
||||
> Tip: Výplň a tah jsou dole v panelu nástrojů. Prázdná výplň, červený přeškrtnutý čtverec, objekt neukáže, dokud nemá tah.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co dělá nástroj A?
|
||||
- Posouvá celý objekt
|
||||
- [x] Táhne jeden kotevní bod
|
||||
- Píše text ve Photoshopu
|
||||
- Stříhá video
|
||||
> A je přímý výběr bodu. V posouvá celý tvar.
|
||||
|
||||
## Který nástroj kreslí křivku po bodech?
|
||||
- V
|
||||
- [x] P, pero
|
||||
- C v Premiere
|
||||
- Kapátko I
|
||||
> Pero je P. Žiletka C patří do Premiere, sem ne.
|
||||
|
||||
## Jak velký je školní dokument pro obrazovku?
|
||||
- [x] 1920 × 1080 px, RGB
|
||||
- A4, CMYK, 300 ppi jako jediná možnost
|
||||
- 303 × 426 mm hned
|
||||
- 80 × 80 px
|
||||
> Obrazovka je Full HD a RGB. Tiskový artboard přijde, až bude značka na papír.
|
||||
|
||||
## Kdy v náhledu poznáte vloženou bitmapu?
|
||||
- Na 800 % zůstane hrana hladká
|
||||
- [x] Na 800 % se objeví pixely
|
||||
- Soubor má příponu AI, takže pixely nemá nikdy
|
||||
- Podle stopy V2
|
||||
> Křivka se nezvětší do čtverečků. Bitmapa ano.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Curves and a logo
|
||||
popis: A mark made of three shapes, a full version and one colour.
|
||||
nazev_cviceni: Quiz: the logo
|
||||
nadpis_kvizu: Check the versions and the export
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-logo
|
||||
nazev: Křivky a logo
|
||||
popis: Značka ze tří tvarů, plná verze a jedna barva.
|
||||
nazev_cviceni: Kvíz: logo
|
||||
nadpis_kvizu: Zkontrolujte verze a export
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Málo bodů
|
||||
*Čistá křivka*
|
||||
|
||||
- Logo je jednoduché. Tři tvary stačí: třeba kniha, paprsek a kruh.
|
||||
- Každý tvar ať má co nejmíň kotevních bodů. Deset bodů na kružnici je zbytečných, elipsa je jeden objekt.
|
||||
- Tah převeďte na obrys, až když má být tloušťka součástí tvaru. Do té doby ať je tah tahem a jde změnit.
|
||||
- Text názvu školy nechte jako text, dokud nemáte vybrané písmo. Pak ho můžete převést na křivky.
|
||||
|
||||
> Tip: Objekt > Cesta > Obrysy tahu, nebo Písmo > Vytvořit obrysy. Až v kopii. Původní text ať jde přepsat.
|
||||
|
||||
## Dvě verze
|
||||
*Plná a jedna barva*
|
||||
|
||||
- Plná verze má barvy školy, nejvýš dvě plus bílou nebo černou.
|
||||
- Jednobarevná verze je celá černá. Hodí se do razítka, do raznice a na světlý papír.
|
||||
- Obě verze jsou dva artboardy v jednom AI, ne dva náhodné JPG.
|
||||
- Na bílém i na černém podkladu musí být značka čitelná. Bílá značka na bílé není verze, je to chyba.
|
||||
|
||||
> Tip: Třetí artboard si nechte na černé pozadí a bílou značku, když ji škola bude dávat na tričko.
|
||||
|
||||
## Export
|
||||
*SVG a PDF*
|
||||
|
||||
- SVG je pro web. Křivky v něm zůstanou, stránka ho zvětší.
|
||||
- PDF je pro tisk a pro vložení do InDesignu.
|
||||
- JPG z loga dělejte jen jako náhled, velký aspoň 1600 px. Jako jediný zdroj je zakázaný.
|
||||
- Názvy: logo.svg, logo.pdf, logo-cerna.svg.
|
||||
|
||||
> Tip: Při exportu SVG nechte text v obrysech, pokud má značku otevřít někdo bez vašeho písma.
|
||||
|
||||
## Zadání: značka školy
|
||||
*Cvičení*
|
||||
|
||||
- Nakreslete značku ze tří tvarů a názvu školy.
|
||||
- Artboard plné verze a artboard černé verze.
|
||||
- Exportujte SVG a PDF u obou. JPG jen jako náhled 1600 px, navíc.
|
||||
- Soubor logo.ai si nechte. V něm musí jít značku přebarvit.
|
||||
|
||||
> Tip: Tři tvary, ne třicet. Když značku nepřečtete na 16 px, je moc podrobná.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Z kolika tvarů je školní značka?
|
||||
- [x] Ze tří
|
||||
- Z jedné fotky
|
||||
- Z dvaceti přechodů
|
||||
- Z videa
|
||||
> Tři tvary se pamatují a vejdou se na vizitku. Fotka není logo.
|
||||
|
||||
## Která verze se hodí do razítka?
|
||||
- Plnobarevná s přechodem
|
||||
- [x] Jednobarevná černá
|
||||
- JPG 80 px
|
||||
- Černobílé video
|
||||
> Razítko neumí přechod. Černá verze se vytiskne jednou barvou.
|
||||
|
||||
## Který export podrží křivky na webu?
|
||||
- JPG
|
||||
- [x] SVG
|
||||
- MP4
|
||||
- prproj
|
||||
> SVG je vektor. JPG je bitmapa a při zvětšení se rozmaže.
|
||||
|
||||
## Proč nestačí odevzdat jen JPG loga?
|
||||
- JPG nejde otevřít
|
||||
- [x] Nejsou v něm křivky a malý soubor nejde zvětšit
|
||||
- JPG je totéž co AI
|
||||
- Illustrator JPG neuloží
|
||||
> Zdroj je AI. SVG a PDF jsou výstupy. JPG je jen náhled.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: After Effects: a composition
|
||||
popis: Eight seconds, Full HD, 25 fps and the logo layers.
|
||||
nazev_cviceni: Quiz: the composition
|
||||
nadpis_kvizu: Set up the composition
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-kompozice
|
||||
nazev: After Effects: kompozice
|
||||
popis: Osm sekund, Full HD, 25 sn/s a vrstvy loga.
|
||||
nazev_cviceni: Kvíz: kompozice
|
||||
nadpis_kvizu: Založte kompozici
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Kompozice
|
||||
*Jako sekvence*
|
||||
|
||||
- Kompozice v After Effects je plátno v čase. Má rozměr, snímkovou frekvenci a délku.
|
||||
- Školní úvod: 1920 × 1080, 25 sn/s, délka 8 sekund.
|
||||
- 8 sekund je 200 snímků. Titulek z Premiere trval 4, tady je čas i na pohyb.
|
||||
- Projekt má příponu aep. Není to mp4.
|
||||
|
||||
> Tip: Nová kompozice je Ctrl+N. Délku pište 0:00:08:00, ne 8 snímků.
|
||||
|
||||
## Vrstvy
|
||||
*Stejný princip*
|
||||
|
||||
- Horní vrstva překrývá spodní, jako ve Photoshopu.
|
||||
- Logo z AI vložte jako kompozici nebo jako vrstvy, ať jde každý tvar animovat zvlášť.
|
||||
- PSD s vrstvami importujte jako kompozici, ne jako sloučený snímek.
|
||||
- Vrstvy pojmenujte. Tvar 1 a Tvar 2 se při animaci pletou.
|
||||
|
||||
> Tip: Když je logo jedna sloučená vrstva, jednotlivý paprsek nerozhýbáte. Importujte znovu s vrstvami.
|
||||
|
||||
## Kotva
|
||||
*Kolem čeho se to točí*
|
||||
|
||||
- Kotva je bod, kolem kterého vrstva roste a otáčí se.
|
||||
- U loga má sedět uprostřed značky, ne v rohu plátna.
|
||||
- Nástroj kotva, nebo dvojklik na ikonu kotvy v panelu, ji srovná na střed vrstvy.
|
||||
- Špatná kotva je nejčastější důvod, proč logo přijede z boku, i když jste chtěli zvětšení.
|
||||
|
||||
> Tip: Vrstvu si najeďte na začátek času, srovnejte kotvu, a teprve potom dávejte klíčové snímky.
|
||||
|
||||
## Zadání: prázdný úvod
|
||||
*Cvičení*
|
||||
|
||||
- Projekt uvod.aep, kompozice uvod, 1920 × 1080, 25 sn/s, 8 sekund.
|
||||
- Importujte logo tak, aby tvary byly samostatné vrstvy, a pojmenujte je.
|
||||
- Kotvu každého tvaru dejte na jeho střed.
|
||||
- Zatím nic neanimujte. Uložte aep. Mp4 z After Effects ještě nedělejte.
|
||||
|
||||
> Tip: Délku kompozice přečtete nahoře v časové ose. Když končí na 10 sekundách, zkraťte ji na 8.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak dlouhá je školní kompozice úvodu?
|
||||
- [x] 8 sekund
|
||||
- 45 sekund
|
||||
- 4 snímky
|
||||
- 303 mm
|
||||
> Osm sekund stačí na nástup loga a textu. Delší úvod sežere krátké video.
|
||||
|
||||
## Jaká je snímková frekvence?
|
||||
- [x] 25 sn/s
|
||||
- 300 ppi
|
||||
- 72 sn/s vždy
|
||||
- 1 sn/s
|
||||
> Stejně jako Premiere, 25. Jinak se úvod ve filmu cuká nebo přepočítává.
|
||||
|
||||
## Kam má sedět kotva loga?
|
||||
- Do levého horního rohu plátna
|
||||
- [x] Na střed značky
|
||||
- Mimo kompozici
|
||||
- Na stopu A1
|
||||
> Od kotvy se počítá zvětšení a otočení. V rohu plátna značka odjíždí.
|
||||
|
||||
## Jak se má importovat logo z Illustratoru?
|
||||
- Jako jeden JPG
|
||||
- [x] Po vrstvách, ať jde každý tvar zvlášť
|
||||
- Jako zvuk
|
||||
- Sloučené a hned exportované
|
||||
> Sloučená vrstva se hýbe jen celá. Tvary potřebují vlastní vrstvy.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Keyframes
|
||||
popis: The logo arrives in one second, and the motion eases.
|
||||
nazev_cviceni: Quiz: keyframes
|
||||
nadpis_kvizu: Fill in the times
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-klice
|
||||
nazev: Klíčové snímky
|
||||
popis: Nástup loga za jednu sekundu a zjemnění pohybu.
|
||||
nazev_cviceni: Kvíz: klíčové snímky
|
||||
nadpis_kvizu: Doplňte časy
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Dva snímky
|
||||
*Od a do*
|
||||
|
||||
- Klíčový snímek je hodnota v čase: pozice, měřítko nebo krytí.
|
||||
- Na čase 0 má logo měřítko 0 %. Na čase 1 sekunda má 100 %.
|
||||
- Mezi těmito dvěma snímky After Effects pohyb dopočítá.
|
||||
- Jeden snímek nic neanimuje. Bez druhého hodnoty není kam dojít.
|
||||
|
||||
> Tip: Stopky vedle vlastnosti v časové ose založí snímek. Druhý vznikne, když v jiném čase změníte hodnotu.
|
||||
|
||||
## Zjemnění
|
||||
*F9*
|
||||
|
||||
- Rovnoměrný pohyb vypadá strojově. Easy Ease, klávesa F9, začátek a konec zpomalí.
|
||||
- F9 mačkejte, když jsou snímky vybrané. Jinak se nezmění nic.
|
||||
- Na nástup loga Easy Ease patří. Na střih záběru v Premiere ne, to je jiný program.
|
||||
- Krytí textu nechte běžet taky mezi dvěma snímky, ne skokem z 0 na 100.
|
||||
|
||||
> Tip: Změněný snímek má po F9 jinou ikonu, přesýpací, ne kosočtverec. Podle toho poznáte, že zjemnění sedí.
|
||||
|
||||
## Text
|
||||
*1 + 4 + 1*
|
||||
|
||||
- Text se objeví za 1 sekundu, zůstane 4 sekundy a zmizí za 1 sekundu.
|
||||
- To je 6 sekund textu. Logo nastupuje v první sekundě, text může začít po ní.
|
||||
- Celá kompozice má 8 sekund, takže na konci zůstanou 2 sekundy klidu nebo doběhu.
|
||||
- Text pište v After Effects. Nevypalujte ho do PSD, pokud ho chcete ještě posunout.
|
||||
|
||||
> Tip: Čtyři sekundy klidu jsou stejné jako titulek v Premiere. Divák čte stejně pomalu.
|
||||
|
||||
## Zadání: nástup
|
||||
*Cvičení*
|
||||
|
||||
- Logo z měřítka 0 % na 100 % za první sekundu. Oba snímky s F9.
|
||||
- Název Školní den: nástup 1 sekunda, klid 4 sekundy, odchod 1 sekunda.
|
||||
- Kotvy jsou uprostřed. Logo neodjíždí z rohu.
|
||||
- Uložte uvod.aep. Export mp4 až po kontrole přehrávání, délka pořád 8 sekund.
|
||||
|
||||
> Tip: Mezerník přehrává. Když logo skočí, chybí druhý snímek nebo je na stejném čase jako první.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jaké měřítko má logo v čase 0 a v čase 1 sekunda?
|
||||
- 100 % a 100 %
|
||||
- [x] 0 % a 100 %
|
||||
- 50 % a 50 %
|
||||
- 300 ppi
|
||||
> Z nuly na plnou velikost za sekundu. Bez dvou snímků se nic nepohne.
|
||||
|
||||
## Čím se nástup zjemní?
|
||||
- [x] F9, Easy Ease
|
||||
- Ctrl+J
|
||||
- Sytostí 0
|
||||
- Spadávkou
|
||||
> F9 na vybraných snímcích zpomalí rozjezd a dojezd. Pohyb přestane být pravítko.
|
||||
|
||||
## Jak je rozložený text?
|
||||
- [x] 1 s nástup, 4 s klid, 1 s odchod
|
||||
- 12 snímků celkem
|
||||
- 8 s nástup a hned pryč
|
||||
- Jen vypálený v JPG
|
||||
> Jedna sekunda se objeví, čtyři se čte, jedna zmizí. Dohromady šest sekund.
|
||||
|
||||
## Proč logo odjíždí z rohu, i když měníte jen měřítko?
|
||||
- Sekvence je 30 sn/s
|
||||
- [x] Kotva není uprostřed značky
|
||||
- Chybí CMYK
|
||||
- F9 je zapnuté
|
||||
> Měřítko roste od kotvy. Kotva v rohu plátna žene značku přes obraz.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: InDesign: a page
|
||||
popis: A two-page A4 leaflet, a master and a placed image.
|
||||
nazev_cviceni: Quiz: InDesign
|
||||
nadpis_kvizu: Recognise the master and the link
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-indesign
|
||||
nazev: InDesign: stránka
|
||||
popis: Dvoustránkový leták A4, předloha a vložený obraz.
|
||||
nazev_cviceni: Kvíz: InDesign
|
||||
nadpis_kvizu: Poznejte předlohu a odkaz
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Stránka, ne plátno
|
||||
*A4*
|
||||
|
||||
- InDesign skládá stránku: text, obraz a logo v rámcích.
|
||||
- Leták je A4, 210 × 297 mm. Spadávka 3 mm se nastaví u dokumentu, stránka zůstane A4.
|
||||
- Na rozdíl od Photoshopu se tu plátno nezvětšuje na 216 × 303. Přesah je spadávka mimo stránku.
|
||||
- Dvě strany: přední s názvem akce, zadní s krátkým programem dne.
|
||||
|
||||
> Tip: Nový dokument: záměr Tisk, A4, dvě stránky, spadávka 3 mm všude.
|
||||
|
||||
## Rámce
|
||||
*Text a obraz*
|
||||
|
||||
- Text žije v textovém rámci. Obraz v rámci obrazu. Nejsou to vrstvy Photoshopu.
|
||||
- Obraz se vkládá Soubor > Umístit. Nevkládejte ho přes schránku jako snímek obrazovky.
|
||||
- Umístěný PSD nebo JPG je odkaz. Když opravíte PSD a uložíte, InDesign ho umí aktualizovat.
|
||||
- Vložený obraz, který v souboru uvízne bez odkazu, se po opravě fotky sám nezmění.
|
||||
|
||||
> Tip: Panel Odkazy ukáže, jestli je soubor aktuální, nebo chybí. Chybějící odkaz je červeně.
|
||||
|
||||
## Předloha
|
||||
*Číslo strany*
|
||||
|
||||
- Předloha, master, je stránka pod ostatními. Co je na ní, opakuje se.
|
||||
- Na předlohu dejte malé logo a číslo strany. Na běžnou stránku už jen obsah.
|
||||
- Prvek z předlohy na jedné straně odemknete Ctrl+Shift+klik, když ho máte výjimečně posunout.
|
||||
- Číslo strany je znak čísla stránky, ne ručně napsaná jednička. Druhá strana se pak očísluje sama.
|
||||
|
||||
> Tip: Předloha je nahoře v panelu Stránky. Dvojklik ji otevře. Dvojklik na stránku 1 vás vrátí do dokumentu.
|
||||
|
||||
## Zadání: dvě strany
|
||||
*Cvičení*
|
||||
|
||||
- letak.indd, A4, dvě strany, spadávka 3 mm, okraje aspoň 12 mm.
|
||||
- Předloha: logo a automatické číslo strany.
|
||||
- Strana 1: název Školní den, datum 12. 6., umístěná fotka jako odkaz.
|
||||
- Strana 2: tři řádky programu. Uložte INDD a export nechte na pozdější lekci, nebo udělejte náhled PDF.
|
||||
|
||||
> Tip: Fotku nejdřív upravte ve Photoshopu a uložte PSD. Do InDesignu ji umístěte, nekopírujte ji znovu.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Jak je v InDesignu nastavená spadávka?
|
||||
- Stránka se zvětší na 303 × 426 mm
|
||||
- [x] Stránka zůstane A4 a spadávka 3 mm je navíc
|
||||
- Spadávka se v sazbě nedělá
|
||||
- 72 ppi
|
||||
> A4 je čistý format. 3 mm přesah je vlastnost dokumentu, ne jiný rozměr stránky.
|
||||
|
||||
## Jak se má dostat fotka do letáku?
|
||||
- Snímkem obrazovky
|
||||
- [x] Soubor > Umístit, jako odkaz
|
||||
- Vypálením do předlohy jednou provždy
|
||||
- Jako mp4
|
||||
> Odkaz jde po opravě PSD aktualizovat. Snímek obrazovky je druhá, horší fotka.
|
||||
|
||||
## Co patří na předlohu?
|
||||
- Celý program dne, na každé straně jiný
|
||||
- [x] Logo a automatické číslo strany
|
||||
- Časová osa Premiere
|
||||
- Maska z Photoshopu
|
||||
> Předloha je to, co se opakuje. Program dne je obsah konkrétní strany.
|
||||
|
||||
## Proč se číslo strany nepíše ručně jako 1?
|
||||
- InDesign čísla neumí
|
||||
- [x] Znak čísla stránky se na druhé straně změní sám
|
||||
- Ruční jednička je vektor
|
||||
- Kvůli 25 sn/s
|
||||
> Znak čísla stránky čte, na které straně je. Ruční 1 zůstane 1 i na straně 2.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Linking the programs
|
||||
popis: The Illustrator logo in After Effects, and the opener in Premiere without a middle export.
|
||||
nazev_cviceni: Quiz: linking
|
||||
nadpis_kvizu: Pick what updates
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-propojeni
|
||||
nazev: Propojení programů
|
||||
popis: Logo z Illustratoru v After Effects a úvod v Premiere bez mezivýstupu.
|
||||
nazev_cviceni: Kvíz: propojení
|
||||
nadpis_kvizu: Vyberte, co se aktualizuje
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Jeden zdroj
|
||||
*Odkaz*
|
||||
|
||||
- Logo má jeden zdroj, logo.ai. Photoshop, After Effects i InDesign ať na něj odkazují.
|
||||
- Když značku přebarvíte v AI a uložíte, odkazy ji mohou načíst znovu. Kopírování JPG to neumí.
|
||||
- JPG 80 px vložené do čtyř programů jsou čtyři různé značky. Jedna se opraví, tři zůstanou staré.
|
||||
- Pojmenujte zdroj jednou. logo-final-final2.ai je cesta, jak odevzdat špatnou verzi.
|
||||
|
||||
> Tip: V After Effects se odkaz obnoví v panelu projektu. V InDesignu v panelu Odkazy.
|
||||
|
||||
## Dynamic Link
|
||||
*AE do Premiere*
|
||||
|
||||
- Dynamic Link vloží kompozici After Effects na časovou osu Premiere bez mezivýstupu mp4.
|
||||
- Když v úvodu posunete text, Premiere po uložení aep ukáže novou verzi.
|
||||
- Oba programy mají být stejná generace. Starší Premiere nový aep často neotevře.
|
||||
- Soubory aep a prproj mějte ve stejné složce. Odkaz jinak spadne při přesunu jen jednoho z nich.
|
||||
|
||||
> Tip: V Premiere: Soubor > Adobe Dynamic Link > Importovat kompozici After Effects. Na osu přijde jako záběr.
|
||||
|
||||
## Co nepropojovat
|
||||
*Kopie*
|
||||
|
||||
- Zvuk do Illustratoru nepatří. Video do InDesignu taky ne, kromě náhledu, který tu neděláme.
|
||||
- Plakát v PSD zůstává tisk. Do videa z něj berte jen logo nebo krátký náhled, ne celou spadávku se značkami.
|
||||
- Ořezové značky plakátu ve videu jsou chyba. Ty má jen tiskové PDF.
|
||||
- Když Dynamic Link nejde, exportujte úvod jako mp4 v ProRes nebo aspoň v kvalitním H.264 a ten vložte. Je to kopie, už se sama neopraví.
|
||||
|
||||
> Tip: ProRes je mezisoubor, velký a kvalitní. H.264 je menší a už jednou stlačený. Do dalšího exportu je horší.
|
||||
|
||||
## Zadání: úvod na ose
|
||||
*Cvičení*
|
||||
|
||||
- V Premiere na začátek sekvence vložte kompozici uvod z After Effects přes Dynamic Link.
|
||||
- Délka ať sedí: 8 sekund úvodu, pak pokračuje sestřih.
|
||||
- Změňte v AI jednu barvu loga, uložte, a obnovte odkaz až do videa. Když se barva nezmění, máte někde JPG.
|
||||
- Uložte prproj i aep. Mp4 celého filmu exportujte znovu až na konci, ne po každém kroku.
|
||||
|
||||
> Tip: Když se úvod na ose tváří jako offline, chybí aep nebo je jiná verze programu. Neexportujte přes to černou.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Kde má žít značka, aby šla opravit všude?
|
||||
- [x] V jednom logo.ai
|
||||
- Ve čtyřech různých JPG
|
||||
- Jen vypálená ve videu
|
||||
- V titulku Premiere jako jediném místě
|
||||
> Jeden zdroj. Ostatní programy na něj odkazují.
|
||||
|
||||
## Co dělá Dynamic Link?
|
||||
- Převede plakát do CMYK
|
||||
- [x] Vloží kompozici After Effects do Premiere bez mezivýstupu
|
||||
- Smaže vrstvy v PSD
|
||||
- Nahradí InDesign
|
||||
> Úprava v aep se po uložení ukáže na ose. Mp4 mezi tím není potřeba.
|
||||
|
||||
## Co do videa z plakátu nepatří?
|
||||
- Logo
|
||||
- [x] Ořezové značky
|
||||
- Název akce
|
||||
- Barva značky
|
||||
> Značky jsou pro tiskárnu. Ve snímku videa vypadají jako omylem vyfocený tiskový arch.
|
||||
|
||||
## Kdy je mp4 z After Effects horší než Dynamic Link?
|
||||
- [x] Když chcete, aby se oprava textu sama propsala do Premiere
|
||||
- Když video má 25 sn/s
|
||||
- Když je úvod dlouhý 8 sekund
|
||||
- Mp4 je vždycky zdroj
|
||||
> Mp4 je kopie. Další oprava textu už do něj sama nevleze, musíte exportovat znovu.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Export and formats
|
||||
popis: What goes to the printer, to the web and out as video.
|
||||
nazev_cviceni: Quiz: formats
|
||||
nadpis_kvizu: Match the file to the job
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-export
|
||||
nazev: Export a formáty
|
||||
popis: Co se odevzdává tiskárně, na web a jako video.
|
||||
nazev_cviceni: Kvíz: formáty
|
||||
nadpis_kvizu: Přiřaďte soubor k použití
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Tabulka výstupů
|
||||
*Kam co*
|
||||
|
||||
- Tiskárna dostane PDF. Plakát se spadávkou, leták A4 se spadávkou 3 mm.
|
||||
- Web dostane JPG nebo PNG. Logo navíc SVG.
|
||||
- Video dostane MP4, H.264, 1920 × 1080, 25 sn/s, 10 Mb/s.
|
||||
- Pracovní soubory PSD, AI, AEP, PRPROJ a INDD se odevzdávají do složky zdroj, ne místo výstupů.
|
||||
|
||||
> Tip: Jeden formát nespasí všechno. SVG na projektor s videem nehraje a MP4 tiskárna nevytiskne.
|
||||
|
||||
## Jména
|
||||
*Verze*
|
||||
|
||||
- Název ať říká, co soubor je: plakat-tisk.pdf, plakat-web.jpg, skolni-den.mp4, logo.svg.
|
||||
- Datum verze pište jako 2026-06-12, rok-měsíc-den. Seřadí se samo.
|
||||
- Nepoužívejte final, final2 a oprava. Nová verze má nové datum, stará zůstane ve složce stare.
|
||||
- Mezery a háčky v názvech na Windows i Macu projdou, ale odkaz mezi programy občas spadne. Bez háčků je jistější.
|
||||
|
||||
> Tip: skolni-den_2026-06-12.mp4 je jasnější než video1.mp4.
|
||||
|
||||
## Složka odevzdání
|
||||
*Dvě hromádky*
|
||||
|
||||
- Složka zdroj: ai, psd, aep, prproj, indd a použitá média.
|
||||
- Složka export: pdf, jpg, png, svg, mp4.
|
||||
- Média videa leží tam, kam vede odkaz projektu. Kopie na ploše se nepočítá.
|
||||
- Když učitel otevře jen složku export, musí vidět plakát, leták, logo i video bez Adobe.
|
||||
|
||||
> Tip: INDD bez odkazovaných fotek otevře prázdné rámečky. Fotky patří k němu, nebo se před odevzdáním zabalí.
|
||||
|
||||
## Zadání: srovnat složku
|
||||
*Cvičení*
|
||||
|
||||
- Založte složku skolni-den se složkami zdroj a export.
|
||||
- Do export dejte aspoň logo.svg, plakat-tisk.pdf, plakat-web.jpg a skolni-den.mp4.
|
||||
- Do zdroj dejte odpovídající ai, psd, aep a prproj.
|
||||
- Cizí soubor Bez názvu-1 smažte nebo přejmenujte. Ve složce ať není nic, co neumíte vysvětlit.
|
||||
|
||||
> Tip: InDesign umí Soubor > Sbalit. Vznikne složka s INDD i s obrázky. Tu dejte do zdroj.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co dostane tiskárna?
|
||||
- prproj
|
||||
- [x] PDF
|
||||
- AEP
|
||||
- Jen SVG na plakát A3
|
||||
> Tisk je PDF se spadávkou. Projekt Premiere tiskárna neotevře.
|
||||
|
||||
## Který soubor loga patří na web a zůstane ostrý?
|
||||
- logo.jpg o šířce 80 px
|
||||
- [x] logo.svg
|
||||
- skolni-den.mp4
|
||||
- plakat-tisk.pdf jako ikona
|
||||
> SVG je křivka. Malé JPG se na webu rozmaže, jakmile ho stránka zvětší.
|
||||
|
||||
## Jak se má jmenovat nová verze videa z 12. 6. 2026?
|
||||
- final2.mp4
|
||||
- [x] skolni-den_2026-06-12.mp4
|
||||
- oprava oprava.mp4
|
||||
- DSC_1842.mp4
|
||||
> Datum rok-měsíc-den se seřadí a je vidět, která verze je nová.
|
||||
|
||||
## Co musí být ve složce export, aby to otevřel člověk bez Adobe?
|
||||
- Jen AEP a PRPROJ
|
||||
- [x] PDF, JPG nebo PNG, SVG a MP4
|
||||
- Jen PSD
|
||||
- Jen INDD
|
||||
> Export je plochý výstup. Pracovní soubory Adobe bez programu nejdou přehrát ani otevřít naplno.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
nazev: Exam assignment
|
||||
popis: A Školní den campaign: a mark, a poster, a leaflet and a video.
|
||||
nazev_cviceni: Quiz: the campaign
|
||||
nadpis_kvizu: Walk through the whole hand-in
|
||||
---
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: pg-4-maturita
|
||||
nazev: Maturitní zadání
|
||||
popis: Kampaň Školní den: značka, plakát, leták a video.
|
||||
nazev_cviceni: Kvíz: kampaň
|
||||
nadpis_kvizu: Projdi celé odevzdání
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Značka
|
||||
*Illustrator*
|
||||
|
||||
- Značka ze tří tvarů a názvu. Plná verze a černá verze, obě v logo.ai.
|
||||
- Export logo.svg a logo.pdf. Černá verze jako logo-cerna.svg.
|
||||
- Na 16 px musí být značka pořád čitelná. Když není, uberete detail.
|
||||
- JPG není zdroj. Smí být jen náhled 1600 px.
|
||||
|
||||
> Tip: Jedna značka na plakátu, v letáku i ve videu. Tři různé značky jsou tři práce, ne kampaň.
|
||||
|
||||
## Tisk
|
||||
*Plakát a leták*
|
||||
|
||||
- Plakát A3 na výšku, plátno 303 × 426 mm, 300 ppi, spadávka 3 mm, text mimo ořez.
|
||||
- Na plakátu je 12. 6. a tělocvična, fotka, maska, křivky a skupiny foto, grafika, text.
|
||||
- Leták InDesign, A4, dvě strany, spadávka 3 mm, předloha s číslem strany, fotka jako odkaz.
|
||||
- Výstupy: plakat-tisk.pdf se značkami, plakat-web.jpg 1600 px, letak.pdf.
|
||||
|
||||
> Tip: Stejný název akce, stejné datum. Plakát a leták se nesmí rozejít.
|
||||
|
||||
## Video
|
||||
*Premiere a After Effects*
|
||||
|
||||
- Úvod 8 sekund z After Effects: logo z 0 % na 100 % za 1 sekundu, text 1 + 4 + 1, snímky s F9.
|
||||
- Úvod je v Premiere přes Dynamic Link, nebo jako jednou exportovaná kopie, když Link nejde.
|
||||
- Celé video 40 až 60 sekund, titulky, jeden J-cut, hudba −15 a pod řečí −24 dB, řeč kolem −6 dB.
|
||||
- Export skolni-den.mp4, H.264, 1920 × 1080, 25 sn/s, 10 Mb/s.
|
||||
|
||||
> Tip: Na začátku mp4 hraje úvod, ne černá a ne ořezové značky z plakátu.
|
||||
|
||||
## Složka
|
||||
*Obhajoba*
|
||||
|
||||
- skolni-den/zdroj drží ai, psd, aep, prproj, indd a média.
|
||||
- skolni-den/export drží svg, pdf, jpg a mp4. Otevře je i člověk bez Adobe.
|
||||
- Na obhajobu ukážete nejdřív video, pak plakát, pak jeden pracovní soubor s vrstvami.
|
||||
- Řeknete, co je bitmapa a co vektor a proč je spadávka 3 mm. To je obsah čtyř ročníků.
|
||||
|
||||
> Tip: Když se zeptají, proč není všechno v jednom JPG, odpověď je: tisk, web a video chtějí každý svůj soubor.
|
||||
|
||||
# Kvíz
|
||||
|
||||
## Co musí mít značka?
|
||||
- [x] Tři tvary, plnou a černou verzi, SVG a PDF
|
||||
- Jen JPG 80 px
|
||||
- Jen titulek v Premiere
|
||||
- Čtyři různé barvy na každém materiálu
|
||||
> Zdroj je AI. SVG a PDF jsou výstupy. Černá verze je pro jednu barvu.
|
||||
|
||||
## Jaké je plátno plakátu?
|
||||
- A4 bez spadávky
|
||||
- [x] 303 × 426 mm při 300 ppi
|
||||
- 1920 × 1080 jako jediný tiskový rozměr
|
||||
- 8 sekund
|
||||
> A3 plus 3 mm z každé strany. 300 ppi. Video je zvlášť, ve Full HD.
|
||||
|
||||
## Jak je dlouhý úvod z After Effects?
|
||||
- [x] 8 sekund, logo nastoupí za 1 sekundu
|
||||
- 45 sekund
|
||||
- 12 snímků celé
|
||||
- 4 minuty
|
||||
> Kompozice má 8 sekund. Měřítko loga jde z 0 % na 100 % během první z nich.
|
||||
|
||||
## Co leží ve složce export?
|
||||
- Jen prproj a aep
|
||||
- [x] SVG, PDF, JPG a MP4
|
||||
- Jen PSD s vrstvami
|
||||
- Rozpracované bez názvu
|
||||
> Export otevře i člověk bez Adobe. Pracovní soubory jsou ve složce zdroj.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Hello, world
|
||||
popis: The first program: writing to the console.
|
||||
---
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
id: cs-1-ahoj-svete
|
||||
nazev: Ahoj světe
|
||||
popis: První program: výpis na konzoli.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Výpis
|
||||
*WriteLine*
|
||||
|
||||
- Console.WriteLine vypíše text a odřádkuje.
|
||||
- Console.Write vypíše text a zůstane na stejném řádku.
|
||||
- Text se píše do uvozovek. Středník ukončuje příkaz.
|
||||
|
||||
> Tip: Bez středníku se program nepřeloží.
|
||||
|
||||
## Krátký a dlouhý zápis
|
||||
*Main*
|
||||
|
||||
- Starší učebnice mají třídu Program a metodu Main.
|
||||
- Nový projekt stejný program zapíše několika řádky bez třídy.
|
||||
- Obojí spustí stejný výpis. V lekcích používáme krátký zápis.
|
||||
|
||||
> Tip: Krátký zápis je pořád C#. Není to jiný jazyk.
|
||||
|
||||
## Vyzkoušejte
|
||||
*Editor*
|
||||
|
||||
- Vpravo je kód. Upravte ho a stiskněte Spustit.
|
||||
- Výstup se objeví hned vedle.
|
||||
- Obnovit ukázku vrátí původní program.
|
||||
|
||||
> Tip: Změňte text v uvozovkách a spusťte znovu.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
Console.WriteLine("Ahoj světe");
|
||||
Console.Write("Toto je ");
|
||||
Console.WriteLine("C#");
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Comments
|
||||
popis: Notes the program does not run.
|
||||
---
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
---
|
||||
id: cs-1-komentare
|
||||
nazev: Komentáře
|
||||
popis: Poznámky, které se nespouštějí.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Jednořádkový
|
||||
*//*
|
||||
|
||||
- Vše za // na stejném řádku počítač přeskočí.
|
||||
- Komentář vysvětluje, proč tam řádek je, ne co je vidět.
|
||||
- Kód bez komentáře pořád běží stejně.
|
||||
|
||||
> Tip: Komentář není výpis. Na konzoli se neobjeví.
|
||||
|
||||
## Více řádků
|
||||
*/* */*
|
||||
|
||||
- Blok začíná /* a končí */.
|
||||
- Hodí se, když chcete dočasně vypnout několik řádků.
|
||||
- Zapomenuté */ rozbije zbytek souboru.
|
||||
|
||||
> Tip: Nevnořujte blokové komentáře do sebe.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
// Tohle se nespustí.
|
||||
Console.WriteLine("Tento řádek ano");
|
||||
/*
|
||||
Console.WriteLine("A tento ne");
|
||||
*/
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Variables
|
||||
popis: A named value you can change.
|
||||
---
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
id: cs-1-promenne
|
||||
nazev: Proměnné
|
||||
popis: Pojmenovaná hodnota, kterou lze změnit.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Deklarace
|
||||
*typ jméno*
|
||||
|
||||
- Nejdřív typ, pak jméno, pak hodnota: int vek = 17;
|
||||
- Jméno začíná písmenem. Mezery v něm být nesmí.
|
||||
- Do stejné proměnné lze později uložit novou hodnotu stejného typu.
|
||||
|
||||
> Tip: int drží celé číslo. string drží text.
|
||||
|
||||
## Čtení
|
||||
*jméno*
|
||||
|
||||
- Jméno bez uvozovek je proměnná. Uvozovky by z něj udělaly text.
|
||||
- WriteLine umí vypsat proměnnou i text spojený plusem.
|
||||
- Hodnota se dosadí až při běhu, ne při psaní.
|
||||
|
||||
> Tip: Změňte vek na 18 a spusťte znovu.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
string jmeno = "Anna";
|
||||
int vek = 17;
|
||||
jmeno = "Eva";
|
||||
Console.WriteLine(jmeno);
|
||||
Console.WriteLine(vek);
|
||||
Console.WriteLine(jmeno + " má " + vek + " let");
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Data types
|
||||
popis: int, double, bool, char and string.
|
||||
---
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
---
|
||||
id: cs-1-typy
|
||||
nazev: Datové typy
|
||||
popis: int, double, bool, char a string.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Čísla
|
||||
*int a double*
|
||||
|
||||
- int je celé číslo: 42.
|
||||
- double je číslo s desetinnou tečkou: 3.14.
|
||||
- V kódu je desetinná tečka, ne čárka.
|
||||
|
||||
> Tip: 3,14 by C# přečetl jako dva údaje oddělené čárkou.
|
||||
|
||||
## Text a ano/ne
|
||||
*string, char, bool*
|
||||
|
||||
- string je text v uvozovkách.
|
||||
- char je jeden znak v apostrofech: 'A'.
|
||||
- bool je jen true nebo false.
|
||||
|
||||
> Tip: Apostrof a uvozovky nejsou totéž. 'A' je znak, "A" je text.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
int cele = 42;
|
||||
double desetinne = 3.14;
|
||||
bool prsi = false;
|
||||
char pismeno = 'A';
|
||||
string text = "ahoj";
|
||||
Console.WriteLine(cele);
|
||||
Console.WriteLine(desetinne);
|
||||
Console.WriteLine(prsi);
|
||||
Console.WriteLine(pismeno);
|
||||
Console.WriteLine(text);
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Type conversion
|
||||
popis: From double to int and from text to a number.
|
||||
---
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
id: cs-1-prevody
|
||||
nazev: Převody typů
|
||||
popis: Z double na int a z textu na číslo.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Ořez desetin
|
||||
*(int)*
|
||||
|
||||
- (int)3.9 je 3. Desetinná část se odřízne, nezaokrouhlí.
|
||||
- Opačně int do double ztrátu nemá: 3 se stane 3.0.
|
||||
- Převod napište před hodnotu do závorky.
|
||||
|
||||
> Tip: Když potřebujete zaokrouhlit, (int) na to není.
|
||||
|
||||
## Text na číslo
|
||||
*Parse*
|
||||
|
||||
- int.Parse("20") udělá z textu číslo 20.
|
||||
- Když text číslo není, program spadne. To později chytíme výjimkou.
|
||||
- Číslo na text udělá ToString nebo zápis do řetězce.
|
||||
|
||||
> Tip: Vstup z konzole je vždy text, i když uživatel napíše číslici.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
double cena = 19.9;
|
||||
int cele = (int)cena;
|
||||
Console.WriteLine(cele);
|
||||
string vstup = "20";
|
||||
int cislo = int.Parse(vstup);
|
||||
Console.WriteLine(cislo + 1);
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
nazev: Operators
|
||||
popis: Arithmetic, remainder, comparison and logic.
|
||||
---
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
id: cs-1-operatory
|
||||
nazev: Operátory
|
||||
popis: Počítání, zbytek, porovnání a a zároveň.
|
||||
---
|
||||
|
||||
# Výklad
|
||||
|
||||
## Počet
|
||||
*+ - * / %*
|
||||
|
||||
- Sčítání, odčítání a násobení fungují, jak čekáte.
|
||||
- Dělení dvou int je celočíselné: 17 / 5 je 3.
|
||||
- % je zbytek po dělení: 17 % 5 je 2.
|
||||
|
||||
> Tip: Když chcete desetinný podíl, jedno číslo udělejte double: 17 / 5.0.
|
||||
|
||||
## Porovnání
|
||||
*true a false*
|
||||
|
||||
- == je rovnost. = je uložení. Nejsou totéž.
|
||||
- && znamená a zároveň. || znamená nebo.
|
||||
- ! otočí bool: !true je false.
|
||||
|
||||
> Tip: Jedno = v podmínce je častá chyba. Podmínka chce ==.
|
||||
|
||||
# Kód
|
||||
|
||||
```
|
||||
int a = 17;
|
||||
int b = 5;
|
||||
Console.WriteLine(a + b);
|
||||
Console.WriteLine(a / b);
|
||||
Console.WriteLine(a % b);
|
||||
Console.WriteLine(a > b);
|
||||
Console.WriteLine(a > 10 && b < 10);
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue