diff --git a/README.md b/README.md index 58dd513..86d20be 100644 --- a/README.md +++ b/README.md @@ -1,955 +1,247 @@ # maturita.c -An educational GTK 4 app written in C. / Vzdělávací GTK 4 aplikace napsaná v C. +Vzdělávací GTK 4 aplikace k přípravě na maturitu. / An educational GTK 4 app for the Czech maturita exam. -**[English](#english)** · **[Česky](#česky)** - ---- - -## English - -### Description - -maturita.c is an educational program for high-school and gymnasium students -preparing for their maturita exam. The UI is available in Czech and English and -is built from a set of small C modules (see -[Project structure](#project-structure)) that render a modern, CSS-styled -GTK 4 interface. - -### Screenshots - -| Welcome screen | Subjects ("Předměty") | German learning roadmap | -| --------------------------------------- | ---------------------------------------- | --------------------------------------- | -| ![Welcome screen](assets/welcomescreen.png) | ![Subjects screen](assets/subjectsscreen.png) | ![German roadmap](assets/germanlection.png) | - -### Features - -- **Welcome screen** – branded greeting with a description of the program and a - continue button to get started -- **Subjects ("Předměty")** – adaptive serpentine subject map with 13 subjects - - **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 opens a year picker (years 1–4); **year 1** - has a **27-unit** path (all playable); 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 - - the remaining subjects are dimmed/locked placeholders until their content - is added - - layout folds into multiple rows when the window is narrow -- **Learning roadmap** – adaptive serpentine learning path with 10 units - - each unit numbered and labeled with its topic (e.g. "Neue Freunde") - - units 1–3 are open; completed units shown in green with a checkmark - - remaining units dimmed with a lock icon - - finish node at the end of the path - - layout folds into multiple rows when the window is narrow -- **Back navigation** – themed circular back button (top-left) returns to the - previous screen -- **Unit 1 exercises** – "Neue Freunde" opens an interactive bubble map with 13 - exercises (dialogs, sentence building, multiple choice, free answers, - numbers, verb conjugation, greeting sorting and more), each with German - prompts and an instant-check button -- **Unit 2 exercises** – "Aus aller Welt" is playable from the start (no need - to finish unit 1 first) and offers a bubble map with 19 exercises: verb - conjugation, prepositions `aus`/`in`, question words, nationalities and - countries, spelling/look-and-find tasks, a matching exercise, a number/word - game, free-answer "Steckbrief" tasks and a Hangman game with 5 professions -- **Unit 3 exercises** – "Bei uns zu Hause" covers family vocabulary, - possessives, accusative and related grammar across 15 exercises (drop-down - sentence fill-ins, word building, "Was siehst du?", sentence ordering and - missing-letter sentences) -- **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** – 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” - 2. Základní pojmy a rozdělení sítí – slides + multiple-choice quiz - 3. Sítě Klient–Server a Cloud – slides + quiz - 4. Přenos dat a jeho zabezpečení – slides + quiz - 5. Signály a modulace – slides + quiz - 6. Cesta, kanál a okruh – slides + quiz - 7. Multiplex a směry přenosu – slides + quiz - 8. Přepojování – slides + quiz - 9. Vrstevnaté modely a protokoly – slides + quiz - 10. Model ISO/OSI a TCP/IP – slides + quiz - 11. Podrobný rozbor 7 vrstev ISO/OSI – slides + quiz - 12. Základy architektury TCP/IP – slides + quiz - 13. Topologie sítě – slides + quiz - 14. Optika – slides + quiz - 15. Ochrana a montáž optiky – slides + quiz - 16. Metody přístupu – slides + quiz - 17. Aktivní prvky – slides + quiz - 18. Switch (podrobně) – slides + quiz - 19. Směrování (Routing) – slides + quiz - 20. Směrovač a brána – slides + quiz - 21. Adresy a rámce v ethernetu – slides + quiz - 22. Paket IP – slides + quiz - 23. ICMP – slides + quiz - 24. ARP – slides + quiz - 25. TCP a UDP – slides + quiz - 26. Aplikační protokoly – slides + quiz - 27. Bezdrátové sítě – slides + quiz - Progress for networks is saved to `progress/net.conf` (one flag per unit); - completed network units show a checkmark on the path and count in Statistics -- **Computer hardware path** – three unlocked units (theory slides + quiz): - 1. **Architektura počítače / Computer architecture** – von Neumann, the - von Neumann model (ALU, control unit, memory, I/O), then a quiz - 2. **Historie počítačů / History of computers** – generations 0–4 (vacuum - tubes, transistors, ICs, microprocessors and milestones), then a quiz - 3. **Zobrazování dat / Data representation** – bit and byte, then a quiz - Progress for hardware is saved to `progress/hw.conf`; completed units show - a checkmark on the path and count in Statistics -- **Progress tracking** – completed exercises are marked green; progress is - saved per unit to `progress/unit1.conf`, `progress/unit2.conf` and - `progress/unit3.conf` and restored on startup -- **Statistics** – chart icon in the header opens a per-subject progress - overview: summary totals (exercises done, percent, finished units) at the - top, then every subject with its own progress bar (subjects without tracked - content yet are shown as locked; **networks** and **hardware** use lesson - completion from `progress/net.conf` / `progress/hw.conf`), and a per-unit - breakdown with progress bars for Deutsch; numbers update as soon as you - finish an exercise -- **Settings** – gear icon in the top-right header opens a panel where you can - choose: - - **mode**: dark or light, as a segmented control - - **theme**: 10 palettes picked from a grid of color swatches - - **language**: Czech or English, applied instantly without a restart - - all three preferences are stored in `progress/settings.conf` -- **Keyboard quit shortcuts** – `Super/Cmd+Q` or `Alt+F4` closes the app -- Modular C codebase split across several files, cross-platform (Linux, macOS and Windows) - -### Downloads (prebuilt) - -There are no releases and no version numbers. CI rebuilds all three platforms -whenever `main` changes and commits the packages to the -[`builds`](../../tree/builds) branch, so what you download is always the -current state of the repository. No compiler or GTK development packages are -required. - -Start with the installer for your platform. It contains no application of its -own — it fetches the current build when you run it, so the file never goes out -of date and you only ever need this one download: - -| Platform | File | How to run | -| -------- | ---- | ---------- | -| macOS (Apple Silicon) | [`maturita-installer-macos.zip`](../../raw/builds/maturita-installer-macos.zip) | Unzip, then double-click the `.command` file | -| Windows (x64) | [`maturita-installer-windows.cmd`](../../raw/builds/maturita-installer-windows.cmd) | Double-click the file | -| Linux (x86_64) | [`maturita-installer-linux.sh`](../../raw/builds/maturita-installer-linux.sh) | `sh maturita-installer-linux.sh` | - -Once installed, the app keeps itself up to date: it compares the commit it was -built from against `VERSION` on the `builds` branch shortly after startup and -offers the update in a banner. There is a manual check under -**Settings → Updates**. - -The builds are not code-signed, so the first launch needs one extra step: -on macOS right-click the installer and pick **Open**, and on Windows choose -**More info → Run anyway** if SmartScreen appears. - -The packages themselves are on the same branch if you would rather skip the -installer: `maturita-linux-x86_64.AppImage`, `maturita-macos-arm64.zip` and -`maturita-windows-x64.zip`. Progress and settings are saved next to the -AppImage / `.app` / unzipped folder in a `progress/` directory. - -Local packaging (same scripts the CI uses): - -```bash -make bundle # Linux AppImage, macOS .app zip, or Windows DLL folder -``` - -### Installation - -#### Prerequisites - -##### 1. GTK 4 development libraries - -macOS: - -```bash -brew install gtk4 -``` - -Linux (Debian / Ubuntu): - -```bash -sudo apt install libgtk-4-dev -``` - -Linux (Fedora): - -```bash -sudo dnf install gtk4-devel -``` - -Linux (Arch): - -```bash -sudo pacman -S gtk4 -``` - -Windows – there is no official GTK 4 installer. The recommended path is -**MSYS2 + MinGW UCRT64** (no Visual Studio). See -[Windows install guide (GTK4)](#windows-install-guide-gtk4) below. - -##### 2. Build tools (compiler, Make, pkg-config) - -macOS – install these explicitly; they are **not** preinstalled: - -```bash -brew install gcc make pkg-config -# or Apple's Clang toolchain: -# xcode-select --install -``` - -Linux – on most distributions `gcc` is already available -(`build-essential` / `base-devel`): - -```bash -# Debian / Ubuntu -sudo apt install build-essential pkg-config -``` - -```bash -# Fedora -sudo dnf groupinstall "Development Tools" -sudo dnf install pkgconf-pkg-config -``` - -```bash -# Arch -sudo pacman -S base-devel pkgconf -``` - -Windows – `gcc`, GTK 4 and `pkg-config` are installed in step 1 of the -Windows guide below. Visual Studio is not required. - -#### Building the application - -1. Clone or download this repository -2. Navigate to the project directory -3. Build with the Makefile: - -```bash -make -``` - -Or manually: - -```bash -# Linux / macOS -gcc -o maturita *.c $(pkg-config --cflags --libs gtk4) -lm - -# Windows (MSYS2 UCRT64) -gcc -o maturita.exe *.c $(pkg-config --cflags --libs gtk4) -lm -mwindows -``` - -##### Building with CMake (optional, Linux / macOS) - -```bash -cmake -S . -B build -cmake --build build -``` - -CMake finds GTK 4 through pkg-config. On Windows prefer the MSYS2 flow below. - -#### Running the application - -```bash -make run -``` - -or - -```bash -# Linux / macOS -./maturita - -# Windows (from the same MSYS2 UCRT64 shell used to build) -./maturita.exe -``` - -#### Windows install guide (GTK4) - -Follow these steps to compile and run on Windows. -**Visual Studio is not required** – MSYS2 and MinGW UCRT64 are enough. - -1. **Install MSYS2 and GTK4** - - Open Command Prompt (CMD) or PowerShell as Administrator and run: - - ```cmd - winget install --id MSYS2.MSYS2 -e --source winget - C:\msys64\ucrt64.exe pacman -S --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-pkg-config - ``` - - Wait until both commands finish. If `winget` says MSYS2 is already - installed, continue with the second command. - (The second command opens an MSYS2 window, downloads packages, then exits – - that is expected.) - -2. **Get the project** - - Clone or download this repository and note the path, e.g. - `C:\Users\Josef\maturita.c`. - -3. **Open the MSYS2 UCRT64 terminal** - - In the Start menu search for **MSYS2 UCRT64** and open it. - Do not use regular CMD or PowerShell – `gcc` and `pkg-config` work in this - shell. - -4. **Enter the project folder and compile** - - In MSYS2, paths look like `/c/...` instead of `C:\...`. Adjust the path and - run: - - ```bash - cd /c/Users/Josef/maturita.c - gcc -o maturita.exe *.c $(pkg-config --cflags --libs gtk4) -lm -mwindows - ``` - - Path conversion examples: - - - `C:\Users\Josef\maturita.c` → `/c/Users/Josef/maturita.c` - - `C:\Users\Josef\Desktop\maturita.c` → `/c/Users/Josef/Desktop/maturita.c` - - If compilation succeeds, `maturita.exe` appears in the project folder. - -5. **Run the app** - - From the same UCRT64 terminal: - - ```bash - ./maturita.exe - ``` - -6. **(Optional) Double-click from File Explorer** - - Running `maturita.exe` outside the MSYS2 terminal usually fails with missing - DLLs. From the UCRT64 terminal (after installing `make`) you can bundle - everything into `dist/`: - - ```bash - pacman -S --noconfirm make - make bundle - ``` - - Then double-click `dist/maturita.exe`. - -### Usage - -When launched, the application shows the welcome screen. From there: - -1. Click **"Pokračuj" / "Continue"** to open the **Předměty / Subjects** map. -2. Click the **Deutsch** bubble (German flag) for the German path, the **Wi-Fi** - bubble ("Správa počítačových sítí") for networks, or the **chip** bubble - ("Technické vybavení") for hardware. Other subjects are still locked. -3. Browse the units along the path; the roadmap reflows into rows and scrolls - if the window is too narrow. -4. Click the **"Neue Freunde"** node to open unit 1, **"Aus aller Welt"** for - 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, 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). -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. -7. Use the **back button** in the top-left corner to return to the previous - screen. -8. Open **Statistiky / Statistics** (chart icon, top-right) to see progress - grouped per subject (overall totals plus, for Deutsch, a per-unit - breakdown). Network and hardware lesson completion is included in the - subject totals. -9. Open **Nastavení / Settings** (gear icon, top-right) to switch dark/light - mode, pick a color theme, or change the interface language. - -German units 1–3, network units 1–10 and hardware units 1–3 are currently -implemented. Locked nodes do nothing – they are placeholders until lessons are -added. Completed Deutsch exercises stay green and are saved per unit to -`progress/unit1.conf` / `progress/unit2.conf` / `progress/unit3.conf`. -Completed network units are saved to `progress/net.conf`; hardware units to -`progress/hw.conf`. - -#### Keyboard shortcuts - -| Shortcut | Action | -| ------------------- | ---------------- | -| `Super/Cmd` + `Q` | Quit application | -| `Alt` + `F4` | Quit application | - -### Project structure - -``` -maturita.h shared types, macros, globals and prototypes -globals.c shared global state (window, stack, units, theme, …) -theme.c theme palettes, stylesheet injection and settings file -i18n.c Czech/English translation tables and language switching -icons.c Cairo-drawn vector icons (check, lock, wifi, chip, …) -util.c small helpers (answer normalisation, feedback, umlaut note) -progress.c per-unit exercise progress (load/save/completion) -stats.c statistics page and progress aggregation -navigation.c back button, top bar, welcome page, key shortcuts -roadmap.c German learning-path roadmap -subjects.c subjects map and subject catalogue -unitmap.c per-unit exercise bubble map -exercise_common.c shared exercise shell + combo/assembly/choice widgets -exercise_u1.c unit 1 ("Neue Freunde") exercises -exercise_u2.c unit 2 ("Aus aller Welt") exercises -exercise_u3.c unit 3 ("Bei uns zu Hause") exercises -settings.c settings popover (mode, theme, language) -net.c computer-networks path (30 nodes), units 1–10 slides - and exercises (unit 1: VLSM practice; 2–10: MC quizzes) -hw.c computer-hardware path (10 nodes), units 1–3 slides - and quizzes (architecture, history, bit/byte) -main.c application entry point and page wiring -style.css GTK stylesheet (palette colors are injected at runtime) -Makefile build & run targets (Linux, macOS, MSYS2); `make bundle` packs a release -scripts/bundle-linux.sh Linux AppImage (linuxdeploy + GTK plugin) -scripts/bundle-macos.sh macOS Maturita.app with relocated GTK dylibs -.github/workflows/ GitHub Actions release on tag `v*` -CMakeLists.txt optional CMake build (Linux / macOS) -build-windows.bat legacy MSVC build (requires Visual Studio + gvsbuild GTK) -run-windows.bat legacy launcher for the MSVC build with GTK DLLs on PATH -README.md this file -LICENSE GPL-3.0 license -assets/ README screenshots (welcome, subjects, German roadmap) -progress/ created at runtime - unit1.conf unit 1 exercise completion state - unit2.conf unit 2 exercise completion state - unit3.conf unit 3 exercise completion state - net.conf computer-networks lesson completion - hw.conf computer-hardware lesson completion - settings.conf theme, dark/light mode and language preference -``` - -### Theming - -The app ships with ten palettes – Catppuccin, Nord, Dracula, Rose Pine, Ocean, -Gruvbox, Solarized, Everforest, Monokai and One Dark – each available in dark -and light mode. Colors are defined as theme palettes in `theme.c`, injected -as `@define-color` bindings, and combined with the rules in the external -`style.css` stylesheet (plus matching Cairo colors for the roadmap rails and -icons). - -Change the look from the in-app settings panel, or edit the palette tables in -`theme.c` / the rules in `style.css` and rebuild. - -### Languages - -The interface can be switched between Czech and English from the settings -panel; the choice takes effect immediately and is remembered between runs. -Translations live in two tables in `i18n.c`: `tr_ui` holds interface -strings under short keys, while `tr_content` translates the Czech meanings -shown next to the German exercise items and uses the Czech text itself as the -key. Widgets are registered with `i18n_bind()` so `apply_language()` can -retranslate them in place. - -German prompts, unit names and exercise titles are learning material and stay -German in both languages. - -### To-Do plans - -- [ ] Wire unit nodes to actual German vocabulary/grammar exercises - - [x] Unit 1 ("Neue Freunde") – 13 interactive exercises with progress saving - - [x] Unit 2 ("Aus aller Welt") – 19 interactive exercises (incl. Hangman) - - [x] Unit 3 ("Bei uns zu Hause") – 15 interactive exercises -- [x] Computer networks units 1–10 (IP/VLSM + nine theory units with quizzes) -- [x] Progress tracking / statistics for the networks path -- [x] Technické vybavení units 1–3 (architecture, history, bit/byte + quizzes) -- [ ] Lesson progression and unlock system for the remaining units -- [ ] Add audio pronunciation features -- [x] Add user settings panel (theme, dark/light mode, language) -- [ ] Implement spaced repetition system for vocabulary -- [ ] Add listening and reading comprehension exercises -- [ ] Add writing practice with feedback -- [x] Expand progress tracking with statistics -- [x] Move CSS styling to an external file -- [x] Split the UI code into multiple files -- [x] Add internationalization support (Czech and English) -- [ ] Add more interface languages -- [ ] Add unit testing framework - -### License - -This project is licensed under the GPL-3.0 License – see the LICENSE file for -details. - -### Acknowledgments - -- Created as a learning exercise in C and GTK programming -- Inspired by language learning applications -- Built with GTK 4 for modern GUI development +**[Česky](#česky)** · **[English](#english)** --- ## Česky -### Popis +Rozhraní je v češtině a angličtině. Hotové jsou čtyři předměty; ostatní jsou +zatím zamčené placeholdery. Aplikace se po instalaci aktualizuje sama. -maturita.c je vzdělávací program pro středoškoláky a gymnazisty připravující -se na maturitu. Rozhraní je v češtině a angličtině a aplikace je rozdělena do -několika malých C modulů (viz [Struktura projektu](#struktura-projektu)) s -moderním GTK 4 rozhraním stylovaným přes CSS. - -### Screenshoty - -| Úvodní obrazovka | Předměty | Německá učební cesta | -| --------------------------------------- | ---------------------------------------- | --------------------------------------- | -| ![Welcome screen](assets/welcomescreen.png) | ![Subjects screen](assets/subjectsscreen.png) | ![German roadmap](assets/germanlection.png) | - -### Funkce - -- **Úvodní obrazovka** – branding, popis programu a tlačítko pokračovat -- **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 otevře výběr - ročníku (1–4); **1. ročník** má cestu s **27 jednotkami** (všechny - hratelné); 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 - - ostatní předměty jsou ztmavené / zamčené placeholdery - - při úzkém okně se mapa zalomí do více řad -- **Učební cesta** – přizpůsobivá cesta s 10 jednotkami - - každá jednotka má číslo a název (např. „Neue Freunde“) - - jednotky 1–3 jsou otevřené; dokončené jsou zelené s fajfkou - - zbývající jsou ztmavené se zámkem - - na konci je cílová / finish uzel - - při úzkém okně se cesta zalomí do více řad -- **Zpět** – kulaté tlačítko vlevo nahoře vrátí na předchozí obrazovku -- **Cvičení jednotky 1** – „Neue Freunde“: mapa s 13 cvičeními (dialogy, - skládání vět, výběr z možností, volné odpovědi, čísla, časování sloves, - řazení pozdravů…), německé zadání a okamžitá kontrola -- **Cvičení jednotky 2** – „Aus aller Welt“ je hratelná hned (není nutné - dokončit jednotku 1): 19 cvičení – časování, předložky `aus`/`in`, tázací - slova, národnosti a země, pravopis / hledej a najdi, párování, hra s čísly, - volné „Steckbrief“ odpovědi a Hangman s 5 povoláními -- **Cvičení jednotky 3** – „Bei uns zu Hause“: rodina, přivlastňovací zájmena, - akuzativ a další gramatika v 15 cvičeních (doplňování vět, skládání slov, - „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í** – 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 - 3. Sítě Klient–Server a Cloud – snímky + kvíz - 4. Přenos dat a jeho zabezpečení – snímky + kvíz - 5. Signály a modulace – snímky + kvíz - 6. Cesta, kanál a okruh – snímky + kvíz - 7. Multiplex a směry přenosu – snímky + kvíz - 8. Přepojování – snímky + kvíz - 9. Vrstevnaté modely a protokoly – snímky + kvíz - 10. Model ISO/OSI a TCP/IP – snímky + kvíz - 11. Podrobný rozbor 7 vrstev ISO/OSI – snímky + kvíz - 12. Základy architektury TCP/IP – snímky + kvíz - 13. Topologie sítě – snímky + kvíz - 14. Optika – snímky + kvíz - 15. Ochrana a montáž optiky – snímky + kvíz - 16. Metody přístupu – snímky + kvíz - 17. Aktivní prvky – snímky + kvíz - 18. Switch (podrobně) – snímky + kvíz - 19. Směrování (Routing) – snímky + kvíz - 20. Směrovač a brána – snímky + kvíz - 21. Adresy a rámce v ethernetu – snímky + kvíz - 22. Paket IP – snímky + kvíz - 23. ICMP – snímky + kvíz - 24. ARP – snímky + kvíz - 25. TCP a UDP – snímky + kvíz - 26. Aplikační protokoly – snímky + kvíz - 27. Bezdrátové sítě – snímky + kvíz - Postup u sítí se ukládá do `progress/net.conf` (příznak na jednotku); - dokončené jednotky mají fajfku na cestě a počítají se ve Statistikách -- **Cesta technického vybavení** – tři odemčené jednotky (snímky + kvíz): - 1. **Architektura počítače** – von Neumann, Von Neumannovo schéma (ALU, - řadič, paměť, V/V) a kvíz - 2. **Historie počítačů** – generace 0–4 (elektronky, tranzistory, IO, - mikroprocesory a milníky) a kvíz - 3. **Zobrazování dat v počítači** – bit a byte a kvíz - Postup se ukládá do `progress/hw.conf`; dokončené jednotky mají fajfku - na cestě a počítají se ve Statistikách -- **Ukládání postupu** – hotová cvičení zezelenají; stav se ukládá do - `progress/unit1.conf`, `progress/unit2.conf` a `progress/unit3.conf` a při - startu se načte zpět -- **Statistiky** – ikona grafu v hlavičce ukáže postup po předmětech (součty, - procenta, dokončené jednotky), progress bary u každého předmětu (předměty - bez trackovaného obsahu jsou zamčené; **sítě** a **technické vybavení** - berou dokončení lekcí z `progress/net.conf` / `progress/hw.conf`) a rozpad - po jednotkách u Deutsch -- **Nastavení** – ozubené kolečko vpravo nahoře: - - **režim**: tmavý / světlý - - **téma**: 10 barevných palet - - **jazyk**: čeština nebo angličtina, bez restartu - - vše se ukládá do `progress/settings.conf` -- **Klávesové zkratky pro ukončení** – `Super/Cmd+Q` nebo `Alt+F4` -- Modulární C kód v několika souborech, multiplatformní (Linux, macOS i Windows) - -### Stažení (předkompilované) - -Žádné releasy ani čísla verzí nejsou. CI přestaví všechny tři platformy -pokaždé, když se změní `main`, a balíčky commitne do větve -[`builds`](../../tree/builds) — stahujete tedy vždycky aktuální stav repa. -Kompilátor ani vývojové balíčky GTK nejsou potřeba. - -Začněte instalátorem pro svou platformu. Samotnou aplikaci neobsahuje, stáhne -si aktuální build až při spuštění, takže soubor nikdy nezestárne a stačí vám -tohle jedno stažení: - -| Platforma | Soubor | Spuštění | -| --------- | ------ | -------- | -| macOS (Apple Silicon) | [`maturita-installer-macos.zip`](../../raw/builds/maturita-installer-macos.zip) | Rozbalit a dvojklik na soubor `.command` | -| Windows (x64) | [`maturita-installer-windows.cmd`](../../raw/builds/maturita-installer-windows.cmd) | Dvojklik na soubor | -| Linux (x86_64) | [`maturita-installer-linux.sh`](../../raw/builds/maturita-installer-linux.sh) | `sh maturita-installer-linux.sh` | - -Nainstalovaná aplikace se pak udržuje aktuální sama: chvíli po startu porovná -commit, ze kterého je postavená, se souborem `VERSION` ve větvi `builds` -a případnou aktualizaci nabídne v pruhu nahoře. Ruční kontrola je -v **Nastavení → Aktualizace**. - -Buildy nejsou podepsané, takže první spuštění chce jeden krok navíc: na macOS -klikněte na instalátor pravým tlačítkem a zvolte **Otevřít**, na Windows při -hlášce SmartScreenu **Další informace → Přesto spustit**. - -Kdo chce instalátor přeskočit, najde na stejné větvi i samotné balíčky: -`maturita-linux-x86_64.AppImage`, `maturita-macos-arm64.zip` a -`maturita-windows-x64.zip`. Postup a nastavení se ukládají vedle AppImage / -`.app` / rozbalené složky do adresáře `progress/`. - -Vydání nové verze je prostý push na `main` — build i publikování do větve -`builds` obstará CI. - -Lokální balíček (stejné skripty jako CI): - -```bash -make bundle # Linux AppImage, macOS .app zip, nebo Windows složka s DLL -``` +| Úvod | Předměty | Německá cesta | +| ---- | -------- | ------------- | +| ![Úvod](assets/welcomescreen.png) | ![Předměty](assets/subjectsscreen.png) | ![Německá cesta](assets/germanlection.png) | ### Instalace -#### Požadavky +Žádné releasy ani čísla verzí nejsou. CI po každém pushi na `main` uloží +balíčky do větve [`builds`](https://github.com/pepaskopec-blip/maturita.c/tree/builds). +Instalátor samotnou aplikaci neobsahuje — při spuštění si stáhne aktuální +build, takže soubor nikdy nezestárne. -##### 1. Vývojářské knihovny GTK 4 +**Nejjednodušší je instalátor pro vaši platformu:** -macOS: +| Platforma | Soubor | Jak spustit | +| --------- | ------ | ----------- | +| macOS (Apple Silicon) | [maturita-installer-macos.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-macos.zip) | Rozbalit, pravý klik → **Otevřít** | +| Windows (x64) | [maturita-installer-windows.cmd](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-windows.cmd) | Dvojklik; u SmartScreenu **Další informace → Přesto spustit** | +| Linux (x86_64) | [maturita-installer-linux.sh](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-linux.sh) | `sh maturita-installer-linux.sh` | -```bash -brew install gtk4 -``` +Kam se to nainstaluje: `/Applications` nebo `~/Applications` (macOS), +`%LOCALAPPDATA%\Programs\Maturita` (Windows), `~/Applications` (Linux). -Linux (Debian / Ubuntu): +Buildy nejsou podepsané, proto je při **prvním** spuštění potřeba výše uvedený +krok navíc. Aplikace se pak udržuje sama: po startu porovná svůj commit se +souborem `VERSION` ve větvi `builds` a aktualizaci nabídne v pruhu nahoře. +Ruční kontrola je v **Nastavení → Aktualizace**. -```bash -sudo apt install libgtk-4-dev -``` +#### Bez instalátoru -Linux (Fedora): +Na stejné větvi jsou i hotové balíčky: -```bash -sudo dnf install gtk4-devel -``` +- [maturita-macos-arm64.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-macos-arm64.zip) +- [maturita-windows-x64.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-windows-x64.zip) +- [maturita-linux-x86_64.AppImage](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-linux-x86_64.AppImage) -Linux (Arch): +Postup a nastavení se ukládají vedle `.app` / složky / AppImage do `progress/`. -```bash -sudo pacman -S gtk4 -``` +Intel Mac, jiná architektura nebo úpravy kódu → [sestavení ze zdroje](#sestavení-ze-zdroje). -Windows – oficiální instalátor GTK 4 neexistuje. Doporučený postup je -**MSYS2 + MinGW UCRT64** (bez Visual Studia). Viz -[Instalační návod pro Windows (GTK4)](#instalační-návod-pro-windows-gtk4) -níže. +### Co v aplikaci je -##### 2. Build nástroje (kompilátor, Make, pkg-config) - -macOS – nainstalujte je ručně, **nejsou** předinstalované: - -```bash -brew install gcc make pkg-config -# nebo Apple Clang: -# xcode-select --install -``` - -Linux – na většině distro je `gcc` už k dispozici -(`build-essential` / `base-devel`): - -```bash -# Debian / Ubuntu -sudo apt install build-essential pkg-config -``` - -```bash -# Fedora -sudo dnf groupinstall "Development Tools" -sudo dnf install pkgconf-pkg-config -``` - -```bash -# Arch -sudo pacman -S base-devel pkgconf -``` - -Windows – `gcc`, GTK 4 i `pkg-config` se nainstalují v kroku 1 návodu níže. -Visual Studio není potřeba. - -#### Sestavení aplikace - -1. Naklonujte nebo stáhněte tento repozitář -2. Přejděte do složky projektu -3. Sestavte pomocí Makefile: - -```bash -make -``` - -Nebo ručně: - -```bash -# Linux / macOS -gcc -o maturita *.c $(pkg-config --cflags --libs gtk4) -lm - -# Windows (MSYS2 UCRT64) -gcc -o maturita.exe *.c $(pkg-config --cflags --libs gtk4) -lm -mwindows -``` - -##### Sestavení přes CMake (volitelné, Linux / macOS) - -```bash -cmake -S . -B build -cmake --build build -``` - -CMake najde GTK 4 přes pkg-config. Na Windows použijte MSYS2 návod níže. - -#### Spuštění aplikace - -```bash -make run -``` - -nebo - -```bash -# Linux / macOS -./maturita - -# Windows (ze stejného MSYS2 UCRT64 terminálu, ve kterém jste kompilovali) -./maturita.exe -``` - -#### Instalační návod pro Windows (GTK4) - -Následujte tyto kroky pro rychlé zkompilování a spuštění na Windows. -**Visual Studio není potřeba** – stačí MSYS2 a MinGW UCRT64. - -1. **Nainstalujte MSYS2 a GTK4** - - Otevřete Příkazový řádek (CMD) nebo PowerShell jako Správce a spusťte: - - ```cmd - winget install --id MSYS2.MSYS2 -e --source winget - C:\msys64\ucrt64.exe pacman -S --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-pkg-config - ``` - - Počkejte, až se obě instalace dokončí. Pokud `winget` hlásí, že MSYS2 už - je nainstalované, klidně pokračujte druhým příkazem. - (Druhý příkaz otevře okno MSYS2, stáhne balíčky a zase se ukončí – to je - v pořádku.) - -2. **Stáhněte projekt** - - Naklonujte nebo stáhněte tento repozitář a zapamatujte si cestu, např. - `C:\Users\Josef\maturita.c`. - -3. **Otevřete terminál MSYS2 UCRT64** - - Ve Start menu vyhledejte **MSYS2 UCRT64** a spusťte ho. - Nepoužívejte běžný CMD ani PowerShell – `gcc` a `pkg-config` fungují - právě v tomto okně. - -4. **Přejděte do složky projektu a zkompilujte** - - V MSYS2 se cesty píší jako `/c/...` místo `C:\...`. Upravte cestu podle - sebe a spusťte: - - ```bash - cd /c/Users/Josef/maturita.c - gcc -o maturita.exe *.c $(pkg-config --cflags --libs gtk4) -lm -mwindows - ``` - - Příklady převodu cesty: - - - `C:\Users\Josef\maturita.c` → `/c/Users/Josef/maturita.c` - - `C:\Users\Josef\Desktop\maturita.c` → `/c/Users/Josef/Desktop/maturita.c` - - Pokud kompilace projde bez chyb, ve složce projektu vznikne `maturita.exe`. - -5. **Spusťte aplikaci** - - Ze stejného terminálu UCRT64: - - ```bash - ./maturita.exe - ``` - -6. **(Volitelně) Spuštění dvojklikem z Průzkumníka** - - Samotný `maturita.exe` bez MSYS2 terminálu obvykle spadne na chybějící - DLL. Z UCRT64 terminálu (po instalaci `make`) můžete vytvořit složku - `dist/` se vším potřebným: - - ```bash - pacman -S --noconfirm make - make bundle - ``` - - Pak spusťte `dist/maturita.exe` dvojklikem. +- **Deutsch** — 3 otevřené jednotky (Neue Freunde, Aus aller Welt, Bei uns zu + Hause): cvičení, nápovědy, vokabeltraining +- **Správa počítačových sítí** — 1. ročník, 27 lekcí (VLSM + teorie a kvízy); + ročníky 2–4 jsou zamčené +- **Technické vybavení** — 3 lekce (architektura, historie, bit/byte) +- **Český jazyk a literatura** — mluvnice (20 cvičení) a maturitní četba + (1984, Spalovač mrtvol); literatura je zatím zamčená +- statistiky, 10 témat, tmavý/světlý režim, čeština/angličtina +- ukončení: `Cmd/Super+Q` nebo `Alt+F4` ### Použití -Po spuštění se zobrazí úvodní obrazovka. Odtud: +1. **Pokračuj** otevře mapu předmětů. +2. Otevřený předmět (vlajka, Wi‑Fi, čip, česká vlajka) vede na učební cestu. +3. Uzly cvičení / lekcí otevřou obsah; zamčené nic nedělají. +4. **Statistiky** (graf) a **Nastavení** (ozubené kolo) jsou vpravo nahoře. -1. Klikněte na **"Pokračuj" / "Continue"** a otevře se mapa **Předměty / - Subjects**. -2. Klikněte na bublinu **Deutsch** (německá vlajka) pro německou cestu, na - bublinu **Wi‑Fi** („Správa počítačových sítí“) pro sítě, nebo na bublinu - **čipu** („Technické vybavení“) pro hardware. Ostatní předměty jsou zatím - zamčené. -3. Procházejte jednotky po cestě; při úzkém okně se cesta zalomí a scrolluje. -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ě 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ě). -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é. -7. Tlačítkem **zpět** vlevo nahoře se vrátíte na předchozí obrazovku. -8. **Statistiky** (ikona grafu vpravo nahoře) ukazují postup po předmětech - (u Deutsch i po jednotkách). Dokončené síťové a hardwarové lekce se - započítávají do součů předmětu. -9. **Nastavení** (ozubené kolečko) – tmavý/světlý režim, barevné téma nebo - jazyk rozhraní. +### Sestavení ze zdroje -Hotové jsou německé jednotky 1–3, síťové jednotky 1–10 a hardwarové jednotky -1–3. Zamčené uzly nic nedělají – jsou to placeholdery. Dokončená německá -cvičení zůstanou zelená a ukládají se do `progress/unit1.conf` / -`progress/unit2.conf` / `progress/unit3.conf`. Dokončené síťové jednotky se -ukládají do `progress/net.conf`, hardwarové do `progress/hw.conf`. +```bash +# macOS +brew install gtk4 gcc make pkg-config -#### Klávesové zkratky +# Debian / Ubuntu +sudo apt install build-essential pkg-config libgtk-4-dev -| Zkratka | Akce | -| ------------------- | ----------------- | -| `Super/Cmd` + `Q` | Ukončit aplikaci | -| `Alt` + `F4` | Ukončit aplikaci | +# Fedora +sudo dnf install gcc make pkgconf-pkg-config gtk4-devel -### Struktura projektu - -``` -maturita.h sdílené typy, makra, globální proměnné a prototypy -globals.c sdílený globální stav (okno, stack, jednotky, téma, …) -theme.c palety témat, vkládání stylu a soubor nastavení -i18n.c české/anglické překlady a přepínání jazyka -icons.c vektorové ikony kreslené Cairem (fajfka, zámek, wifi, čip, …) -util.c pomocné funkce (normalizace odpovědí, feedback, poznámka) -progress.c postup cvičení jednotek (načtení/uložení/dokončení) -stats.c stránka statistik a agregace pokroku -navigation.c tlačítko zpět, horní lišta, úvodní stránka, zkratky -roadmap.c německá učební cesta -subjects.c mapa předmětů a katalog předmětů -unitmap.c mapa cvičení jednotlivých jednotek -exercise_common.c společné jádro cvičení + combo/skládání/výběr -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 výběr ročníku + cesta sítí (27 uzlů v 1. ročníku; - 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 -style.css GTK styl (barvy palety se vkládají za běhu) -Makefile build & run (Linux, macOS, MSYS2); `make bundle` vytvoří release balíček -scripts/bundle-linux.sh Linux AppImage (linuxdeploy + GTK plugin) -scripts/bundle-macos.sh macOS Maturita.app s přbalenými GTK dylibs -.github/workflows/ GitHub Actions release při tagu `v*` -CMakeLists.txt volitelný CMake build (Linux / macOS) -build-windows.bat legacy MSVC build (vyžaduje Visual Studio + gvsbuild GTK) -run-windows.bat legacy spouštění MSVC buildu s GTK DLL na PATH -README.md tento soubor -LICENSE licence GPL-3.0 -assets/ screenshoty do README (úvod, předměty, německá cesta) -progress/ vzniká za běhu - unit1.conf stav cvičení jednotky 1 - unit2.conf stav cvičení jednotky 2 - unit3.conf stav cvičení jednotky 3 - net.conf dokončení síťových lekcí - hw.conf dokončení hardwarových lekcí - settings.conf téma, režim a jazyk +# Arch +sudo pacman -S base-devel pkgconf gtk4 ``` -### Témata +```bash +git clone https://github.com/pepaskopec-blip/maturita.c.git +cd maturita.c +make +make run # nebo ./maturita +make bundle # AppImage / .app zip / Windows složka s DLL +``` -Aplikace má deset palet – Catppuccin, Nord, Dracula, Rose Pine, Ocean, Gruvbox, -Solarized, Everforest, Monokai a One Dark – každou ve světlém i tmavém režimu. -Barvy jsou v `theme.c`, vkládají se jako `@define-color` a spojují se s -pravidly v externím souboru `style.css` (a Cairo barvy pro koleje a ikony na -mapě). +Volitelně CMake: `cmake -S . -B build && cmake --build build`. -Vzhled změníte v nastavení, nebo upravte tabulky palet v `theme.c` / pravidla -v `style.css` a znovu zkompilujte. +#### Windows (MSYS2 UCRT64, bez Visual Studia) -### Jazyky +```cmd +winget install --id MSYS2.MSYS2 -e --source winget +C:\msys64\ucrt64.exe pacman -S --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-pkg-config make +``` -Rozhraní přepnete mezi češtinou a angličtinou v nastavení; změna platí hned a -zapamatuje se. Překlady jsou ve dvou tabulkách v `i18n.c`: `tr_ui` drží -texty rozhraní pod krátkými klíči, `tr_content` překládá české významy u -německých cvičení (klíčem je samotný český text). Widgety se registrují přes -`i18n_bind()`, aby je `apply_language()` přeložila na místě. +V terminálu **MSYS2 UCRT64**: -Německá zadání, názvy jednotek a cvičení zůstávají německá v obou jazycích -rozhraní. +```bash +cd /c/Users/Josef/maturita.c # C:\Users\Josef\maturita.c → /c/Users/Josef/maturita.c +make +./maturita.exe +make bundle # dist/maturita.exe jde spustit i z Průzkumníka +``` -### Plány do budoucna +### Struktura -- [ ] Napojit zbývající jednotky na skutečná cvičení slovní zásoby / gramatiky - - [x] Jednotka 1 („Neue Freunde“) – 13 interaktivních cvičení s ukládáním - - [x] Jednotka 2 („Aus aller Welt“) – 19 cvičení (včetně Hangmana) - - [x] Jednotka 3 („Bei uns zu Hause“) – 15 cvičení -- [x] Počítačové sítě: jednotky 1–10 (IP/VLSM + 9 teoretických s kvízy) -- [x] Ukládání postupu / statistiky pro síťovou cestu -- [x] Technické vybavení: jednotky 1–3 (architektura, historie, bit/byte + kvízy) -- [ ] Postupné odemykání zbývajících jednotek -- [ ] Audio / výslovnost -- [x] Panel nastavení (téma, režim, jazyk) -- [ ] Spaced repetition pro slovní zásobu -- [ ] Poslech a čtení s porozuměním -- [ ] Psaní s feedbackem -- [x] Statistiky postupu -- [x] Přesunout CSS do externího souboru -- [x] Rozdělit UI kód do více souborů -- [x] Internacionalizace (čeština a angličtina) -- [ ] Další jazyky rozhraní -- [ ] Unit testy +``` +*.c / maturita.h zdroj aplikace +style.css GTK styl (barvy se vkládají za běhu) +installers/ instalátory, které stáhnou aktuální build +scripts/ balení AppImage a .app +.github/workflows/build.yml CI: push na main → větev builds +assets/ ikona a screenshoty +progress/ vzniká za běhu (cvičení, nastavení) +``` -### Licence +Licence: [GPL-3.0](LICENSE). -Projekt je pod licencí GPL-3.0 – detaily viz soubor LICENSE. +--- -### Poděkování +## English -- Vzniklo jako cvičení v C a GTK -- Inspirováno jazykovými učebními aplikacemi -- Postaveno na GTK 4 +The UI is Czech and English. Four subjects are playable; the rest are locked +placeholders. After install the app updates itself. + +| Welcome | Subjects | German path | +| ------- | -------- | ----------- | +| ![Welcome](assets/welcomescreen.png) | ![Subjects](assets/subjectsscreen.png) | ![German path](assets/germanlection.png) | + +### Install + +There are no releases and no version numbers. CI writes packages to the +[`builds`](https://github.com/pepaskopec-blip/maturita.c/tree/builds) branch +whenever `main` changes. The installer carries no app of its own — it fetches +the current build when you run it, so the file never goes stale. + +**Start with the installer for your platform:** + +| Platform | File | How to run | +| -------- | ---- | ---------- | +| macOS (Apple Silicon) | [maturita-installer-macos.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-macos.zip) | Unzip, then right-click → **Open** | +| Windows (x64) | [maturita-installer-windows.cmd](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-windows.cmd) | Double-click; if SmartScreen appears, **More info → Run anyway** | +| Linux (x86_64) | [maturita-installer-linux.sh](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-installer-linux.sh) | `sh maturita-installer-linux.sh` | + +Install locations: `/Applications` or `~/Applications` (macOS), +`%LOCALAPPDATA%\Programs\Maturita` (Windows), `~/Applications` (Linux). + +The builds are unsigned, so the first launch needs the extra step above. +After that the app stays current: it compares its commit to `VERSION` on +`builds` and offers an update in a banner. Manual check: +**Settings → Updates**. + +#### Packages without the installer + +- [maturita-macos-arm64.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-macos-arm64.zip) +- [maturita-windows-x64.zip](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-windows-x64.zip) +- [maturita-linux-x86_64.AppImage](https://github.com/pepaskopec-blip/maturita.c/raw/builds/maturita-linux-x86_64.AppImage) + +Progress and settings live in `progress/` next to the `.app` / folder / +AppImage. + +Intel Mac, another architecture, or hacking on the code → +[build from source](#build-from-source). + +### What’s inside + +- **Deutsch** — 3 open units (Neue Freunde, Aus aller Welt, Bei uns zu Hause): + exercises, hints, vocabulary training +- **Computer networks** — year 1, 27 lessons (VLSM + theory/quizzes); + years 2–4 are locked +- **Computer hardware** — 3 lessons (architecture, history, bit/byte) +- **Czech language** — grammar (20 exercises) and required reading + (1984, Spalovač mrtvol); literature theory is still locked +- statistics, 10 palettes, dark/light mode, Czech/English +- quit with `Cmd/Super+Q` or `Alt+F4` + +### Usage + +1. **Continue** opens the subject map. +2. An open subject (flag, Wi‑Fi, chip, Czech flag) opens its path. +3. Exercise / lesson nodes open content; locked nodes do nothing. +4. **Statistics** (chart) and **Settings** (gear) sit in the top-right. + +### Build from source + +```bash +# macOS +brew install gtk4 gcc make pkg-config + +# Debian / Ubuntu +sudo apt install build-essential pkg-config libgtk-4-dev + +# Fedora +sudo dnf install gcc make pkgconf-pkg-config gtk4-devel + +# Arch +sudo pacman -S base-devel pkgconf gtk4 +``` + +```bash +git clone https://github.com/pepaskopec-blip/maturita.c.git +cd maturita.c +make +make run # or ./maturita +make bundle # AppImage / .app zip / Windows DLL folder +``` + +Optional CMake: `cmake -S . -B build && cmake --build build`. + +#### Windows (MSYS2 UCRT64, no Visual Studio) + +```cmd +winget install --id MSYS2.MSYS2 -e --source winget +C:\msys64\ucrt64.exe pacman -S --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-pkg-config make +``` + +In an **MSYS2 UCRT64** terminal: + +```bash +cd /c/Users/Josef/maturita.c # C:\Users\Josef\maturita.c → /c/Users/Josef/maturita.c +make +./maturita.exe +make bundle # dist/maturita.exe can be double-clicked +``` + +### Layout + +``` +*.c / maturita.h application sources +style.css GTK stylesheet (palette injected at runtime) +installers/ fetch-the-latest installers +scripts/ AppImage / .app bundlers +.github/workflows/build.yml CI: push to main → builds branch +assets/ icon and screenshots +progress/ created at runtime (exercises, settings) +``` + +License: [GPL-3.0](LICENSE). diff --git a/assets/germanlection.png b/assets/germanlection.png index ea0f83f..cb18d71 100644 Binary files a/assets/germanlection.png and b/assets/germanlection.png differ diff --git a/assets/subjectsscreen.png b/assets/subjectsscreen.png index 8a5488a..d0ffed6 100644 Binary files a/assets/subjectsscreen.png and b/assets/subjectsscreen.png differ diff --git a/assets/welcomescreen.png b/assets/welcomescreen.png index d57362a..51a1860 100644 Binary files a/assets/welcomescreen.png and b/assets/welcomescreen.png differ diff --git a/czech.c b/czech.c index 92eca33..28036ad 100644 --- a/czech.c +++ b/czech.c @@ -62,19 +62,27 @@ void czech_rail_theme_reset(void) { gtk_widget_queue_draw(cz_rail); } -static GtkWidget *cz_make_node(int index) { +static GtkWidget *cz_make_node(int index, gboolean locked) { GtkWidget *btn; - GtkWidget *label; btn = gtk_button_new(); gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); gtk_widget_set_can_focus(btn, FALSE); gtk_widget_set_size_request(btn, (int)CZ_BUBBLE, (int)CZ_BUBBLE); - label = gtk_label_new(cz_initials[index]); - gtk_widget_add_css_class(label, "unit-number"); - gtk_button_set_child(GTK_BUTTON(btn), label); + if (locked) { + gtk_widget_add_css_class(btn, "locked"); + gtk_widget_set_sensitive(btn, FALSE); + gtk_button_set_child(GTK_BUTTON(btn), + icon_area_new(draw_lock_icon, + 0.3451, 0.3569, 0.4392, 26)); + } else { + GtkWidget *label = gtk_label_new(cz_initials[index]); + + gtk_widget_add_css_class(btn, "current"); + gtk_widget_add_css_class(label, "unit-number"); + gtk_button_set_child(GTK_BUTTON(btn), label); + } return btn; } @@ -126,7 +134,9 @@ GtkWidget *build_czechmap_page(void) { cz_rail = rail; for (int i = 0; i < CZ_NODES; i++) { - GtkWidget *btn = cz_make_node(i); + /* Literatura has no lessons yet; keep the node visible but locked. */ + gboolean locked = (i == 0); + GtkWidget *btn = cz_make_node(i, locked); GtkWidget *name = gtk_label_new(NULL); if (i == 2) { @@ -146,6 +156,8 @@ GtkWidget *build_czechmap_page(void) { gtk_label_set_wrap(GTK_LABEL(name), TRUE); gtk_widget_add_css_class(name, "unit-name"); gtk_widget_add_css_class(name, "cz-label"); + if (locked) + gtk_widget_add_css_class(name, "unit-name-locked"); gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0); diff --git a/hw.c b/hw.c index e5a58ac..be01330 100644 --- a/hw.c +++ b/hw.c @@ -366,6 +366,7 @@ GtkWidget *build_hwmap_page(void) { g_signal_connect(va, "notify::page-size", G_CALLBACK(hw_adjust_notify), NULL); + hw_apply_layout(); hw_relayout_later(); refresh_hw_completion_ui(); diff --git a/installers/maturita-installer-linux.sh b/installers/maturita-installer-linux.sh index 24308b0..5b8ed63 100755 --- a/installers/maturita-installer-linux.sh +++ b/installers/maturita-installer-linux.sh @@ -41,7 +41,7 @@ mkdir -p "$DEST_DIR" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT INT TERM -say "Downloading the latest release..." +say "Downloading the latest build..." curl -fL --progress-bar -o "$tmp/$ASSET" "$URL" || die "the download failed. Check your internet connection." diff --git a/installers/maturita-installer-macos.command b/installers/maturita-installer-macos.command index 3bf8b23..1f64c98 100755 --- a/installers/maturita-installer-macos.command +++ b/installers/maturita-installer-macos.command @@ -40,7 +40,7 @@ fi tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT INT TERM -say "Downloading the latest release..." +say "Downloading the latest build..." curl -fL --progress-bar -o "$tmp/$ASSET" "$URL" || die "the download failed. Check your internet connection." diff --git a/installers/maturita-installer-windows.cmd b/installers/maturita-installer-windows.cmd index 4c0f5d4..b1125e5 100644 --- a/installers/maturita-installer-windows.cmd +++ b/installers/maturita-installer-windows.cmd @@ -25,7 +25,7 @@ set "TMP_DIR=%TEMP%\maturita-installer" rmdir /s /q "%TMP_DIR%" 2>nul mkdir "%TMP_DIR%" || goto :fail_tmp -echo Downloading the latest release... +echo Downloading the latest build... curl -fL --progress-bar -o "%TMP_DIR%\%ASSET%" "%URL%" || goto :fail_download echo Installing to %DEST% diff --git a/main.c b/main.c index ae5623a..607d845 100644 --- a/main.c +++ b/main.c @@ -310,6 +310,129 @@ static void setup_window_icon(GtkWindow *window) { G_CALLBACK(on_window_realize_icon), NULL); } +static gboolean open_settings_later(gpointer data) { + (void)data; + settings_open(); + return G_SOURCE_REMOVE; +} + +static gboolean save_window_png(const char *path) { + GtkWidget *widget; + int width, height; + GdkPaintable *paintable; + GtkSnapshot *snapshot; + GskRenderNode *node; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t st; + + if (!main_window || !path || !path[0]) + return FALSE; + + widget = GTK_WIDGET(main_window); + width = gtk_widget_get_width(widget); + height = gtk_widget_get_height(widget); + if (width < 80 || height < 80) + return FALSE; + + paintable = gtk_widget_paintable_new(widget); + snapshot = gtk_snapshot_new(); + gdk_paintable_snapshot(paintable, snapshot, width, height); + node = gtk_snapshot_free_to_node(snapshot); + g_object_unref(paintable); + if (!node) + return FALSE; + + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create(surface); + gsk_render_node_draw(node, cr); + gsk_render_node_unref(node); + cairo_destroy(cr); + st = cairo_surface_write_to_png(surface, path); + cairo_surface_destroy(surface); + return st == CAIRO_STATUS_SUCCESS; +} + +static void smoke_quit(int code) { + GtkApplication *app = main_window + ? gtk_window_get_application(main_window) : NULL; + + if (app) + g_application_quit(G_APPLICATION(app)); + else + exit(code); +} + +static gboolean shot_later(gpointer data) { + const char *path = g_getenv("MATURITA_SHOT"); + int *tries = data; + + if (!save_window_png(path)) { + if (tries && *tries < 20) { + (*tries)++; + return G_SOURCE_CONTINUE; + } + g_printerr("MATURITA_SHOT: could not capture window\n"); + smoke_quit(1); + return G_SOURCE_REMOVE; + } + if (g_getenv("MATURITA_SHOT_QUIT")) + smoke_quit(0); + return G_SOURCE_REMOVE; +} + +static gboolean run_smoke_test(gpointer data) { + static const char *pages[] = { + "welcome", "subjects", "roadmap", "stats", + "netyears", "netmap", "hwmap", "czechmap", + "mluvnice", "readinglist", + "cetba1984", "cetba1984quiz", "cetba1984dej", + "cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej", + "hwunit1", "hwex1", "hwunit2", "hwex2", "hwunit3", "hwex3", + "unit1", "unit2", "unit3", + "u1e1", "u1e13", "u2e1", "u2e19", "u3e1", "u3e15", + "u1vocab", "u2vocab", "u3vocab", + "mluve1", "mluve20", + "netunit1", "netex1", "netunit10", "netex10", + "netunit27", "netex27", + NULL + }; + const char *report = g_getenv("MATURITA_SMOKE"); + FILE *f; + int missing = 0; + int i; + + (void)data; + f = report && report[0] ? fopen(report, "w") : stdout; + if (!f) { + g_printerr("MATURITA_SMOKE: cannot write %s\n", report); + smoke_quit(1); + return G_SOURCE_REMOVE; + } + + fprintf(f, "commit=%s\n", APP_COMMIT); + fprintf(f, "css=%s\n", + g_file_test(CSS_FILE, G_FILE_TEST_IS_REGULAR) ? "ok" : "MISSING"); + fprintf(f, "progress_dir=%s\n", app_progress_dir ? app_progress_dir : "?"); + + for (i = 0; pages[i]; i++) { + GtkWidget *child = gtk_stack_get_child_by_name(main_stack, pages[i]); + + if (child) { + fprintf(f, "OK %s\n", pages[i]); + } else { + fprintf(f, "MISSING %s\n", pages[i]); + missing++; + } + } + + fprintf(f, "missing=%d\n", missing); + if (f != stdout) + fclose(f); + smoke_quit(missing ? 1 : 0); + return G_SOURCE_REMOVE; +} + void activate(GtkApplication *app, gpointer user_data) { GtkWindow *window; GtkWidget *headerbar; @@ -463,7 +586,18 @@ void activate(GtkApplication *app, gpointer user_data) { } } - gtk_stack_set_visible_child_name(main_stack, "welcome"); + { + const char *start = g_getenv("MATURITA_PAGE"); + const char *size = g_getenv("MATURITA_SIZE"); + int w, h; + + if (start && *start) + gtk_stack_set_visible_child_name(main_stack, start); + else + gtk_stack_set_visible_child_name(main_stack, "welcome"); + if (size && sscanf(size, "%dx%d", &w, &h) == 2) + gtk_window_set_default_size(window, w, h); + } refresh_completion_ui(); @@ -482,6 +616,18 @@ void activate(GtkApplication *app, gpointer user_data) { update_init(); gtk_window_present(window); + + if (g_getenv("MATURITA_SETTINGS")) + g_timeout_add(350, open_settings_later, NULL); + if (g_getenv("MATURITA_SMOKE")) + g_timeout_add(200, run_smoke_test, NULL); + if (g_getenv("MATURITA_SHOT")) { + static int shot_tries; + + shot_tries = 0; + g_timeout_add(g_getenv("MATURITA_SETTINGS") ? 700 : 400, + shot_later, &shot_tries); + } } int main(int argc, char **argv) { diff --git a/maturita.h b/maturita.h index 405f6e6..ba32bc9 100644 --- a/maturita.h +++ b/maturita.h @@ -839,6 +839,7 @@ void mluvnice_init(void); GtkWidget *build_mluvnice_page(void); GtkWidget *build_mluvnice_exercise_page(int n); void mluvnice_refresh_ui(void); +void progress_for_mluvnice(ProgressSum *out); GtkWidget *build_readinglist_page(void); GtkWidget *build_cetba1984_page(void); GtkWidget *build_cetba1984_quiz_page(void); @@ -1124,6 +1125,7 @@ GtkWidget *make_theme_card(ThemeId id, GtkToggleButton *group); void on_settings_clicked(GtkButton *button, gpointer user_data); GtkWidget *build_stats_button(void); GtkWidget *build_settings_button(void); +void settings_open(void); void unit_meta_init(void); void unit_configure(int idx, const char *const *names, int n); GtkWidget *build_exercise_page(UnitCtx *u, int n); diff --git a/mluvnice.c b/mluvnice.c index ab77ed9..b69b5b5 100644 --- a/mluvnice.c +++ b/mluvnice.c @@ -71,6 +71,19 @@ void mluvnice_init(void) { unit_load_progress(&mluv_unit); } +void progress_for_mluvnice(ProgressSum *out) { + int d; + + if (!out || mluv_unit.n_ex <= 0) + return; + d = unit_done_count(&mluv_unit); + out->total_ex += mluv_unit.n_ex; + out->open_units += 1; + out->done_ex += d; + if (d == mluv_unit.n_ex) + out->done_units++; +} + void mluvnice_refresh_ui(void) { for (int i = 0; i < mluv_unit.n_ex; i++) { GtkWidget *btn = mluv_unit.ex_cells[i]; diff --git a/net.c b/net.c index 4d7354d..50dcb18 100644 --- a/net.c +++ b/net.c @@ -687,6 +687,7 @@ GtkWidget *build_netmap_page(void) { g_signal_connect(va, "notify::page-size", G_CALLBACK(net_adjust_notify), NULL); + net_apply_layout(); net_relayout_later(); refresh_net_completion_ui(); diff --git a/roadmap.c b/roadmap.c index 6b1bf14..aed42c4 100644 --- a/roadmap.c +++ b/roadmap.c @@ -401,6 +401,7 @@ GtkWidget *build_roadmap_page(void) { g_signal_connect(va, "notify::page-size", G_CALLBACK(road_adjust_notify), NULL); + road_apply_layout(); road_relayout_later(); return page; diff --git a/settings.c b/settings.c index 47879f8..f954cb1 100644 --- a/settings.c +++ b/settings.c @@ -4,6 +4,13 @@ /* Settings */ /* ------------------------------------------------------------------ */ +static GtkWidget *settings_popover; + +void settings_open(void) { + if (settings_popover) + gtk_popover_popup(GTK_POPOVER(settings_popover)); +} + void draw_theme_swatch(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data) { ThemeId id = (ThemeId)GPOINTER_TO_INT(data); @@ -215,6 +222,7 @@ GtkWidget *build_settings_button(void) { G_CALLBACK(gtk_widget_queue_draw), icon); popover = gtk_popover_new(); + settings_popover = popover; gtk_widget_add_css_class(popover, "settings-popover"); gtk_popover_set_has_arrow(GTK_POPOVER(popover), TRUE); gtk_popover_set_position(GTK_POPOVER(popover), GTK_POS_BOTTOM); diff --git a/stats.c b/stats.c index dc31b9f..1904dbe 100644 --- a/stats.c +++ b/stats.c @@ -69,6 +69,8 @@ void refresh_stats_ui(void) { progress_for_net(&all); else if (s == HW_SUBJ) progress_for_hw(&all); + else if (s == CZ_SUBJ) + progress_for_mluvnice(&all); else progress_for_units(sub_unit_start[s], sub_unit_count[s], &all); } @@ -106,6 +108,8 @@ void refresh_stats_ui(void) { progress_for_net(&sp); else if (s == HW_SUBJ) progress_for_hw(&sp); + else if (s == CZ_SUBJ) + progress_for_mluvnice(&sp); else progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp); if (has_content) {