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 - **Deutsch** is open (round bubble with the German flag) and opens the
German learning path German learning path
- **Správa počítačových sítí / Computer Network Administration** is open too - **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; (shown with a Wi-Fi icon) and opens a year picker (years 1–4); **year 1**
**units 1–27 are playable**, units 28–30 are locked placeholders 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 - **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 to a 10-unit hardware path; **units 1–3 are playable**, units 4–10 are
locked placeholders locked placeholders
@ -62,7 +63,8 @@ GTK 4 interface.
- **Hints & model answers** – in exercises where you write or complete a German - **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 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 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 1. **Výpočet IP adres / IP Address Calculation** – 4-slide VLSM walkthrough
and four interactive subnetting tasks (prefix, network, broadcast, host and four interactive subnetting tasks (prefix, network, broadcast, host
range) with check and “show solution” 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 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 an exercise. Units 2 and 3 are available even if the earlier units are not
finished yet. finished yet.
5. On the networks path, units **1–27** are open. Unit 1 (**Výpočet IP adres**) 5. On the networks path, pick **year 1** (years 2–4 are locked). Units **1–27**
walks through four VLSM slides and then four interactive subnetting tasks are open. Unit 1 (**Výpočet IP adres**) walks through four VLSM slides and
with check / “show solution”. Units 2–27 each have theory slides followed by then four interactive subnetting tasks with check / “show solution”.
a multiple-choice quiz (basic concepts through wireless networks). Units 2–27 each have theory slides followed by a multiple-choice quiz
Units 28–30 stay locked placeholders. (basic concepts through wireless networks). Units 28–30 stay locked
placeholders.
6. On the hardware path, units **1–3** are open (architecture / von Neumann, 6. On the hardware path, units **1–3** are open (architecture / von Neumann,
computer history generations, bit & byte), each with slides and a quiz. computer history generations, bit & byte), each with slides and a quiz.
Units 4–10 stay locked. 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 - **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 - **Deutsch** je otevřený (bublina s německou vlajkou) a vede na německou
učební cestu učební cestu
- **Správa počítačových sítí** je také otevřená (ikona Wi‑Fi) a vede na cestu - **Správa počítačových sítí** je také otevřená (ikona Wi‑Fi) a otevře výběr
s 30 jednotkami; **jednotky 1–27 jsou hratelné**, 28–30 jsou zamčené ročníku (1–4); **1. ročník** má cestu s 30 jednotkami, z nichž **1–27 jsou
placeholdery 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 - **Technické vybavení** je otevřené (ikona čipu) a vede na cestu
s 10 jednotkami; **jednotky 1–3 jsou hratelné**, 4–10 jsou zamčené s 10 jednotkami; **jednotky 1–3 jsou hratelné**, 4–10 jsou zamčené
placeholdery 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) „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 - **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 č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 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í“ (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 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 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 **"Bei uns zu Hause"** (3) a vyberte bublinu cvičení. Jednotky 2 a 3 jdou
otevřít i bez dokončení předchozích. 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 5. Na síťové cestě nejdřív vyberte **1. ročník** (2.–4. jsou zamčené). Otevřené
adres**) má 4 snímky VLSM a pak 4 interaktivní úlohy s kontrolou / jsou jednotky **1–27**. Jednotka 1 (**Výpočet IP adres**) má 4 snímky VLSM
„ukázat řešení“. Jednotky 2–27 mají snímky teorie a kvíz s výběrem a pak 4 interaktivní úlohy s kontrolou / „ukázat řešení“. Jednotky 2–27 mají
(od základních pojmů po bezdrátové sítě). Jednotky 28–30 zůstávají zamčené. 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 / 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. von Neumann, historie generací, bit a byte), každá se snímky a kvízem.
Jednotky 4–10 zůstávají zamčené. 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_u2.c cvičení jednotky 2 („Aus aller Welt“)
exercise_u3.c cvičení jednotky 3 („Bei uns zu Hause“) exercise_u3.c cvičení jednotky 3 („Bei uns zu Hause“)
settings.c panel nastavení (režim, téma, jazyk) settings.c panel nastavení (režim, téma, jazyk)
net.c cesta počítačových sítí (30 uzlů), jednotky 1–27 net.c výběr ročníku + cesta sítí (30 uzlů), 1. ročník:
(1: VLSM cvičení; 2–27: kvízy s výběrem) jednotky 1–27 (1: VLSM cvičení; 2–27: kvízy)
hw.c cesta technického vybavení (10 uzlů), jednotky 1–3 hw.c cesta technického vybavení (10 uzlů), jednotky 1–3
(architektura, historie, bit/byte + kvízy) (architektura, historie, bit/byte + kvízy)
main.c vstupní bod aplikace a zapojení stránek 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"}, {"Programové vybavení", "Programové vybavení", "Software"},
{"net_sub", "Vyberte lekci na cestě a začněte procvičovat.", {"net_sub", "Vyberte lekci na cestě a začněte procvičovat.",
"Pick a unit on the path and start practicing."}, "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", "Výpočet IP adres", "IP Address Calculation"},
{"net_unit1_sub", "4 snímky s postupem a pak cvičení.", {"net_unit1_sub", "4 snímky s postupem a pak cvičení.",
"4 slides with the method, then an exercise."}, "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, build_subjects_page(), "subjects");
gtk_stack_add_named(main_stack, roadmap_page, "roadmap"); 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_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_netmap_page(), "netmap");
gtk_stack_add_named(main_stack, build_hwmap_page(), "hwmap"); gtk_stack_add_named(main_stack, build_hwmap_page(), "hwmap");
gtk_stack_add_named(main_stack, build_czechmap_page(), "czechmap"); 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_rail_theme_reset(void);
void net_add_node(GtkFixed *fixed, int index); void net_add_node(GtkFixed *fixed, int index);
GtkWidget *build_netmap_page(void); GtkWidget *build_netmap_page(void);
GtkWidget *build_netyears_page(void);
GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key, GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key,
const char *sub_key, const NetSlide *slides, const char *sub_key, const NetSlide *slides,
guint n_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); 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 *build_netmap_page(void) {
GtkWidget *page; GtkWidget *page;
GtkWidget *scroll; GtkWidget *scroll;
@ -551,7 +654,7 @@ GtkWidget *build_netmap_page(void) {
gtk_widget_set_margin_bottom(page, 24); gtk_widget_set_margin_bottom(page, 24);
gtk_box_append(GTK_BOX(page), 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(); scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), 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); draw_wifi_icon, NULL, NULL);
gtk_button_set_child(GTK_BUTTON(card), wifi); gtk_button_set_child(GTK_BUTTON(card), wifi);
g_object_set_data_full(G_OBJECT(card), "target", 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); g_signal_connect(card, "clicked", G_CALLBACK(on_nav_clicked), NULL);
} else if (i == HW_SUBJ) { } else if (i == HW_SUBJ) {
GtkWidget *chip = gtk_drawing_area_new(); GtkWidget *chip = gtk_drawing_area_new();