Add year picker for computer networks path (years 1–4).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-14 13:27:29 +02:00
commit 1dc8ddea07
6 changed files with 140 additions and 20 deletions

View file

@ -30,8 +30,9 @@ GTK 4 interface.
- **Deutsch** is open (round bubble with the German flag) and opens the
German learning path
- **Správa počítačových sítí / Computer Network Administration** is open too
(shown with a Wi-Fi icon) and leads to a 30-unit computer-networks path;
**units 1–27 are playable**, units 28–30 are locked placeholders
(shown with a Wi-Fi icon) and opens a year picker (years 1–4); **year 1**
has a 30-unit path where **units 1–27 are playable**, units 28–30 are
locked; years 2–4 are locked placeholders until content is added
- **Technické vybavení / Computer Hardware** is open (chip icon) and leads
to a 10-unit hardware path; **units 1–3 are playable**, units 4–10 are
locked placeholders
@ -62,7 +63,8 @@ GTK 4 interface.
- **Hints & model answers** – in exercises where you write or complete a German
sentence the Czech meaning is shown right away as a hint, and clicking the
check button also reveals the correct German sentence so you can compare
- **Computer networks path** – twenty-seven unlocked units (theory slides + practice):
- **Computer networks path** – pick a school year first; **year 1** has
twenty-seven unlocked units (theory slides + practice); years 2–4 are locked:
1. **Výpočet IP adres / IP Address Calculation** – 4-slide VLSM walkthrough
and four interactive subnetting tasks (prefix, network, broadcast, host
range) with check and “show solution”
@ -314,11 +316,12 @@ When launched, the application shows the welcome screen. From there:
unit 2 or **"Bei uns zu Hause"** for unit 3, then pick any bubble to start
an exercise. Units 2 and 3 are available even if the earlier units are not
finished yet.
5. On the networks path, units **1–27** are open. Unit 1 (**Výpočet IP adres**)
walks through four VLSM slides and then four interactive subnetting tasks
with check / “show solution”. Units 2–27 each have theory slides followed by
a multiple-choice quiz (basic concepts through wireless networks).
Units 28–30 stay locked placeholders.
5. On the networks path, pick **year 1** (years 2–4 are locked). Units **1–27**
are open. Unit 1 (**Výpočet IP adres**) walks through four VLSM slides and
then four interactive subnetting tasks with check / “show solution”.
Units 2–27 each have theory slides followed by a multiple-choice quiz
(basic concepts through wireless networks). Units 28–30 stay locked
placeholders.
6. On the hardware path, units **1–3** are open (architecture / von Neumann,
computer history generations, bit & byte), each with slides and a quiz.
Units 4–10 stay locked.
@ -468,9 +471,9 @@ moderním GTK 4 rozhraním stylovaným přes CSS.
- **Předměty** – přizpůsobivá „hadí“ mapa s 13 předměty
- **Deutsch** je otevřený (bublina s německou vlajkou) a vede na německou
učební cestu
- **Správa počítačových sítí** je také otevřená (ikona Wi‑Fi) a vede na cestu
s 30 jednotkami; **jednotky 1–27 jsou hratelné**, 28–30 jsou zamčené
placeholdery
- **Správa počítačových sítí** je také otevřená (ikona Wi‑Fi) a otevře výběr
ročníku (1–4); **1. ročník** má cestu s 30 jednotkami, z nichž **1–27 jsou
hratelné**, 28–30 zamčené; ročníky 2–4 jsou zatím zamčené placeholdery
- **Technické vybavení** je otevřené (ikona čipu) a vede na cestu
s 10 jednotkami; **jednotky 1–3 jsou hratelné**, 4–10 jsou zamčené
placeholdery
@ -495,7 +498,8 @@ moderním GTK 4 rozhraním stylovaným přes CSS.
„Was siehst du?“, řazení vět, chybějící písmena)
- **Nápovědy a vzorové odpovědi** – u psaných / doplňovaných vět je hned
český význam; po kontrole se ukáže i správná německá věta
- **Cesta počítačových sítí** – sedmadvacet odemčených jednotek (snímky + cvičení):
- **Cesta počítačových sítí** – nejdřív výběr ročníku; **1. ročník** má
sedmadvacet odemčených jednotek (snímky + cvičení); ročníky 2–4 jsou zamčené:
1. **Výpočet IP adres** – 4 snímky VLSM a čtyři interaktivní úlohy
(prefix, síť, broadcast, rozsah uzlů) s kontrolou a „ukázat řešení“
2. Základní pojmy a rozdělení sítí – snímky + kvíz
@ -744,10 +748,11 @@ Po spuštění se zobrazí úvodní obrazovka. Odtud:
4. Otevřete **"Neue Freunde"** (jednotka 1), **"Aus aller Welt"** (2) nebo
**"Bei uns zu Hause"** (3) a vyberte bublinu cvičení. Jednotky 2 a 3 jdou
otevřít i bez dokončení předchozích.
5. Na síťové cestě jsou otevřené jednotky **1–27**. Jednotka 1 (**Výpočet IP
adres**) má 4 snímky VLSM a pak 4 interaktivní úlohy s kontrolou /
„ukázat řešení“. Jednotky 2–27 mají snímky teorie a kvíz s výběrem
(od základních pojmů po bezdrátové sítě). Jednotky 28–30 zůstávají zamčené.
5. Na síťové cestě nejdřív vyberte **1. ročník** (2.–4. jsou zamčené). Otevřené
jsou jednotky **1–27**. Jednotka 1 (**Výpočet IP adres**) má 4 snímky VLSM
a pak 4 interaktivní úlohy s kontrolou / „ukázat řešení“. Jednotky 2–27 mají
snímky teorie a kvíz s výběrem (od základních pojmů po bezdrátové sítě).
Jednotky 28–30 zůstávají zamčené.
6. Na cestě technického vybavení jsou otevřené jednotky **1–3** (architektura /
von Neumann, historie generací, bit a byte), každá se snímky a kvízem.
Jednotky 4–10 zůstávají zamčené.
@ -791,8 +796,8 @@ exercise_u1.c cvičení jednotky 1 („Neue Freunde“)
exercise_u2.c cvičení jednotky 2 („Aus aller Welt“)
exercise_u3.c cvičení jednotky 3 („Bei uns zu Hause“)
settings.c panel nastavení (režim, téma, jazyk)
net.c cesta počítačových sítí (30 uzlů), jednotky 1–27
(1: VLSM cvičení; 2–27: kvízy s výběrem)
net.c výběr ročníku + cesta sítí (30 uzlů), 1. ročník:
jednotky 1–27 (1: VLSM cvičení; 2–27: kvízy)
hw.c cesta technického vybavení (10 uzlů), jednotky 1–3
(architektura, historie, bit/byte + kvízy)
main.c vstupní bod aplikace a zapojení stránek

10
i18n.c
View file

@ -198,6 +198,16 @@ const TrEntry tr_ui[] = {
{"Programové vybavení", "Programové vybavení", "Software"},
{"net_sub", "Vyberte lekci na cestě a začněte procvičovat.",
"Pick a unit on the path and start practicing."},
{"net_years_title", "Správa počítačových sítí",
"Computer Network Administration"},
{"net_years_sub", "Vyberte ročník a začněte procvičovat.",
"Pick a school year and start practicing."},
{"net_year1", "1. ročník", "Year 1"},
{"net_year2", "2. ročník", "Year 2"},
{"net_year3", "3. ročník", "Year 3"},
{"net_year4", "4. ročník", "Year 4"},
{"net_year_locked_sub", "Zatím bez obsahu",
"No content yet"},
{"net_unit1", "Výpočet IP adres", "IP Address Calculation"},
{"net_unit1_sub", "4 snímky s postupem a pak cvičení.",
"4 slides with the method, then an exercise."},

1
main.c
View file

@ -229,6 +229,7 @@ void activate(GtkApplication *app, gpointer user_data) {
gtk_stack_add_named(main_stack, build_subjects_page(), "subjects");
gtk_stack_add_named(main_stack, roadmap_page, "roadmap");
gtk_stack_add_named(main_stack, build_stats_page(), "stats");
gtk_stack_add_named(main_stack, build_netyears_page(), "netyears");
gtk_stack_add_named(main_stack, build_netmap_page(), "netmap");
gtk_stack_add_named(main_stack, build_hwmap_page(), "hwmap");
gtk_stack_add_named(main_stack, build_czechmap_page(), "czechmap");

View file

@ -1087,6 +1087,7 @@ void net_draw_rail(GtkDrawingArea *area, cairo_t *cr,
void net_rail_theme_reset(void);
void net_add_node(GtkFixed *fixed, int index);
GtkWidget *build_netmap_page(void);
GtkWidget *build_netyears_page(void);
GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key,
const char *sub_key, const NetSlide *slides,
guint n_slides);

105
net.c
View file

@ -531,6 +531,109 @@ void net_add_node(GtkFixed *fixed, int index) {
gtk_fixed_put(fixed, name, 0, 0);
}
static GtkWidget *net_year_button(int year, gboolean locked) {
static const char *year_keys[] = {
"net_year1", "net_year2", "net_year3", "net_year4",
};
GtkWidget *btn;
GtkWidget *row;
GtkWidget *num;
GtkWidget *texts;
GtkWidget *title;
char *num_text;
btn = gtk_button_new();
gtk_widget_add_css_class(btn, "unit-node");
gtk_widget_set_can_focus(btn, FALSE);
gtk_widget_set_hexpand(btn, TRUE);
gtk_widget_set_size_request(btn, -1, 72);
gtk_widget_set_sensitive(btn, !locked);
if (locked)
gtk_widget_add_css_class(btn, "locked");
else
gtk_widget_add_css_class(btn, "current");
row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14);
gtk_widget_set_halign(row, GTK_ALIGN_START);
gtk_widget_set_valign(row, GTK_ALIGN_CENTER);
gtk_widget_set_margin_start(row, 18);
gtk_widget_set_margin_end(row, 18);
gtk_button_set_child(GTK_BUTTON(btn), row);
num_text = g_strdup_printf("%d", year);
num = gtk_label_new(num_text);
g_free(num_text);
gtk_widget_add_css_class(num, "unit-number");
gtk_widget_set_valign(num, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(row), num);
texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
gtk_widget_set_halign(texts, GTK_ALIGN_START);
gtk_widget_set_hexpand(texts, TRUE);
gtk_box_append(GTK_BOX(row), texts);
title = gtk_label_new(NULL);
i18n_bind(title, year_keys[year - 1], 0);
gtk_widget_set_halign(title, GTK_ALIGN_START);
gtk_widget_add_css_class(title, "unit-name");
gtk_box_append(GTK_BOX(texts), title);
if (locked) {
GtkWidget *sub = gtk_label_new(NULL);
GtkWidget *icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569,
0.4392, 18);
i18n_bind(sub, "net_year_locked_sub", 0);
gtk_widget_set_halign(sub, GTK_ALIGN_START);
gtk_widget_add_css_class(sub, "unit-name-locked");
gtk_box_append(GTK_BOX(texts), sub);
gtk_widget_set_valign(icon, GTK_ALIGN_CENTER);
gtk_box_append(GTK_BOX(row), icon);
} else {
g_object_set_data_full(G_OBJECT(btn), "target",
g_strdup("netmap"), g_free);
g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL);
}
return btn;
}
GtkWidget *build_netyears_page(void) {
GtkWidget *page;
GtkWidget *scroll;
GtkWidget *list;
int y;
page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_hexpand(page, TRUE);
gtk_widget_set_vexpand(page, TRUE);
gtk_widget_set_margin_start(page, 32);
gtk_widget_set_margin_end(page, 32);
gtk_widget_set_margin_top(page, 24);
gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page),
top_bar("subjects", "net_years_title", "net_years_sub"));
scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_widget_set_vexpand(scroll, TRUE);
gtk_widget_set_margin_top(scroll, 18);
gtk_box_append(GTK_BOX(page), scroll);
list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_widget_set_halign(list, GTK_ALIGN_CENTER);
gtk_widget_set_valign(list, GTK_ALIGN_CENTER);
gtk_widget_set_size_request(list, 360, -1);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list);
for (y = 1; y <= 4; y++)
gtk_box_append(GTK_BOX(list), net_year_button(y, y > 1));
return page;
}
GtkWidget *build_netmap_page(void) {
GtkWidget *page;
GtkWidget *scroll;
@ -551,7 +654,7 @@ GtkWidget *build_netmap_page(void) {
gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page),
top_bar("subjects", "Správa počítačových sítí", "net_sub"));
top_bar("netyears", "Správa počítačových sítí", "net_sub"));
scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),

View file

@ -366,7 +366,7 @@ GtkWidget *build_subjects_page(void) {
draw_wifi_icon, NULL, NULL);
gtk_button_set_child(GTK_BUTTON(card), wifi);
g_object_set_data_full(G_OBJECT(card), "target",
g_strdup("netmap"), g_free);
g_strdup("netyears"), g_free);
g_signal_connect(card, "clicked", G_CALLBACK(on_nav_clicked), NULL);
} else if (i == HW_SUBJ) {
GtkWidget *chip = gtk_drawing_area_new();