From f813595bbaebcbf76d0476cee6d52c51251d263e Mon Sep 17 00:00:00 2001 From: pepaskopec-blip Date: Tue, 22 Sep 2026 11:01:32 +0200 Subject: [PATCH] Add the full school maturita reading list of 82 books. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep full quizzes for 1984 and Spalovač mrtvol; other titles get catalog metadata stubs across Swift, GTK, and content.json. Co-authored-by: Cursor --- data/cetba-catalog.json | 543 +++++++++++++++++++++++++++++ ios/Maturita/Route.swift | 9 +- ios/Maturita/UI/Screens.swift | 39 ++- scripts/extract-android-content.py | 84 ++++- src/cetba.c | 181 +++++++++- src/cetba_catalog.inc | 98 ++++++ src/i18n.c | 4 + src/main.c | 1 + src/maturita.h | 6 + src/search.c | 29 +- 10 files changed, 949 insertions(+), 45 deletions(-) create mode 100644 data/cetba-catalog.json create mode 100644 src/cetba_catalog.inc diff --git a/data/cetba-catalog.json b/data/cetba-catalog.json new file mode 100644 index 0000000..da41486 --- /dev/null +++ b/data/cetba-catalog.json @@ -0,0 +1,543 @@ +[ + { + "id": "1984", + "author": "George Orwell", + "title": "1984", + "translator": "Šimečková", + "genre": "Próza", + "full": true, + "page": "cetba1984" + }, + { + "id": "fahrenheit451", + "author": "Ray Bradbury", + "title": "451 stupňů Fahrenheita", + "translator": "Nezval", + "genre": "Próza" + }, + { + "id": "audience", + "author": "Václav Havel", + "title": "Audience", + "genre": "Drama" + }, + { + "id": "bajecna-leta", + "author": "Michal Viewegh", + "title": "Báječná léta pod psa", + "genre": "Próza" + }, + { + "id": "bidnici", + "author": "Victor Hugo", + "title": "Bídníci", + "translator": "Pavlousková", + "genre": "Próza" + }, + { + "id": "bila-nemoc", + "author": "Karel Čapek", + "title": "Bílá nemoc", + "genre": "Drama" + }, + { + "id": "bylo-nas-pet", + "author": "Karel Poláček", + "title": "Bylo nás pět", + "genre": "Próza" + }, + { + "id": "cekani-na-godota", + "author": "Samuel Beckett", + "title": "Čekání na Godota", + "translator": "Ouředník", + "genre": "Drama" + }, + { + "id": "ceske-nebe", + "author": "Zdeněk Svěrák, Ladislav Smoljak", + "title": "České nebe", + "genre": "Drama" + }, + { + "id": "dekameron", + "author": "Giovanni Boccaccio", + "title": "Dekameron", + "translator": "Krátký", + "genre": "Próza" + }, + { + "id": "den-trifidu", + "author": "John Wyndham", + "title": "Den trifidů", + "translator": "Kořán", + "genre": "Próza" + }, + { + "id": "denik-anny-frankove", + "author": "Anne Franková", + "title": "Deník Anne Frankové", + "genre": "Próza" + }, + { + "id": "jekyll-hyde", + "author": "Robert Louis Stevenson", + "title": "Dr. Jekyll a Mr. Hyde", + "translator": "Kořán", + "genre": "Próza" + }, + { + "id": "edison", + "author": "Vítězslav Nezval", + "title": "Edison", + "genre": "Poezie" + }, + { + "id": "farma-zvirat", + "author": "George Orwell", + "title": "Farma zvířat", + "translator": "Gössell", + "genre": "Próza" + }, + { + "id": "gulliverovy-cesty", + "author": "Jonathan Swift", + "title": "Gulliverovy cesty", + "translator": "Skoumal", + "genre": "Próza" + }, + { + "id": "hamlet", + "author": "William Shakespeare", + "title": "Hamlet", + "translator": "Nevrla", + "genre": "Drama" + }, + { + "id": "havran", + "author": "Edgar Allan Poe", + "title": "Havran", + "genre": "Poezie" + }, + { + "id": "hladove-hry", + "author": "Suzanne Collins", + "title": "Hladové hry – I. Aréna smrti", + "translator": "Dušek", + "genre": "Próza" + }, + { + "id": "hlava-xxii", + "author": "Joseph Heller", + "title": "Hlava XXII", + "translator": "Jindra", + "genre": "Próza" + }, + { + "id": "chram-matky-bozi", + "author": "Victor Hugo", + "title": "Chrám Matky Boží", + "translator": "Tomášková", + "genre": "Próza" + }, + { + "id": "jak-jsem-vyhral-valku", + "author": "Patrick Ryan", + "title": "Jak jsem vyhrál válku", + "translator": "Vrba", + "genre": "Próza" + }, + { + "id": "jana-eyrova", + "author": "Charlotte Brontëová", + "title": "Jana Eyrová", + "translator": "Polák", + "genre": "Próza" + }, + { + "id": "ivan-denisovic", + "author": "Alexandr Solženicyn", + "title": "Jeden den Ivana Denisoviče", + "translator": "Machonin, Nováková", + "genre": "Próza" + }, + { + "id": "jmeno-ruze", + "author": "Umberto Eco", + "title": "Jméno růže", + "translator": "Frýbort", + "genre": "Próza" + }, + { + "id": "kalibuv-zlocin", + "author": "Karel Václav Rais", + "title": "Kalibův zločin", + "genre": "Próza" + }, + { + "id": "kniska-karla-kryla", + "author": "Karel Kryl", + "title": "Kníška Karla Kryla", + "genre": "Poezie" + }, + { + "id": "komu-zvoni-hrana", + "author": "Ernest Hemingway", + "title": "Komu zvoní hrana", + "translator": "Valja, Kobík", + "genre": "Próza" + }, + { + "id": "kral-oidipus", + "author": "Sofoklés", + "title": "Král Oidipus", + "translator": "Stiebitz", + "genre": "Drama" + }, + { + "id": "krysar", + "author": "Viktor Dyk", + "title": "Krysař", + "genre": "Próza" + }, + { + "id": "kulicka", + "author": "Guy de Maupassant", + "title": "Kulička", + "translator": "Guth", + "genre": "Próza" + }, + { + "id": "kvety-zla", + "author": "Charles Baudelaire", + "title": "Květy zla", + "translator": "Nezval", + "genre": "Poezie" + }, + { + "id": "kytice", + "author": "Karel Jaromír Erben", + "title": "Kytice", + "genre": "Poezie" + }, + { + "id": "lakomec", + "author": "Molière", + "title": "Lakomec", + "translator": "Mikeš", + "genre": "Drama" + }, + { + "id": "lolita", + "author": "Vladimir Nabokov", + "title": "Lolita", + "translator": "Kořínek", + "genre": "Próza" + }, + { + "id": "maj", + "author": "Karel Hynek Mácha", + "title": "Máj", + "genre": "Poezie" + }, + { + "id": "maly-princ", + "author": "Antoine de Saint-Exupéry", + "title": "Malý princ", + "translator": "Stavinohová", + "genre": "Próza" + }, + { + "id": "marysa", + "author": "Alois Mrštík, Vilém Mrštík", + "title": "Maryša", + "genre": "Drama" + }, + { + "id": "modlitba-pro-katerinu", + "author": "Arnošt Lustig", + "title": "Modlitba pro Kateřinu Horovitzovou", + "genre": "Próza" + }, + { + "id": "most-kwai", + "author": "Pierre Boulle", + "title": "Most přes řeku Kwai", + "translator": "Šup", + "genre": "Próza" + }, + { + "id": "stanice-zoo", + "author": "Christiane F.", + "title": "My děti ze stanice ZOO", + "translator": "Soukupová", + "genre": "Próza" + }, + { + "id": "na-ceste", + "author": "Jack Kerouac", + "title": "Na cestě", + "translator": "Popel", + "genre": "Próza" + }, + { + "id": "na-zapadni-fronte", + "author": "Erich Maria Remarque", + "title": "Na západní frontě klid", + "translator": "Gel", + "genre": "Próza" + }, + { + "id": "navsteva-stare-damy", + "author": "Friedrich Dürrenmatt", + "title": "Návštěva staré dámy", + "genre": "Drama" + }, + { + "id": "nebe-nezna-vyvolenych", + "author": "Erich Maria Remarque", + "title": "Nebe nezná vyvolených", + "translator": "V. a K. Holubovi", + "genre": "Próza" + }, + { + "id": "o-mysich-a-lidech", + "author": "John Steinbeck", + "title": "O myších a lidech", + "translator": "Vendyš", + "genre": "Próza" + }, + { + "id": "obraz-doriana-graye", + "author": "Oscar Wilde", + "title": "Obraz Doriana Graye", + "translator": "Novák", + "genre": "Próza" + }, + { + "id": "obsluhoval-jsem", + "author": "Bohumil Hrabal", + "title": "Obsluhoval jsem anglického krále", + "genre": "Próza" + }, + { + "id": "oliver-twist", + "author": "Charles Dickens", + "title": "Oliver Twist", + "translator": "E. a E. Tilschovi", + "genre": "Próza" + }, + { + "id": "ostre-sledovane-vlaky", + "author": "Bohumil Hrabal", + "title": "Ostře sledované vlaky", + "genre": "Próza" + }, + { + "id": "svejk", + "author": "Jaroslav Hašek", + "title": "Osudy dobrého vojáka Švejka za světové války", + "genre": "Próza" + }, + { + "id": "pan-much", + "author": "William Golding", + "title": "Pán much", + "translator": "Kovályová", + "genre": "Próza" + }, + { + "id": "pan-prstenu", + "author": "J. R. R. Tolkien", + "title": "Pán prstenů – Společenstvo prstenu", + "translator": "Pošustová", + "genre": "Próza" + }, + { + "id": "petr-a-lucie", + "author": "Romain Rolland", + "title": "Petr a Lucie", + "translator": "Zaorálek", + "genre": "Próza" + }, + { + "id": "poe-povidky", + "author": "Edgar Allan Poe", + "title": "Povídky", + "genre": "Próza" + }, + { + "id": "povidky-z-kapes", + "author": "Karel Čapek", + "title": "Povídky z jedné a druhé kapsy", + "genre": "Próza" + }, + { + "id": "promena", + "author": "Franz Kafka", + "title": "Proměna", + "genre": "Próza" + }, + { + "id": "pycha-a-predsudek", + "author": "Jane Austenová", + "title": "Pýcha a předsudek", + "translator": "Poláčková", + "genre": "Próza" + }, + { + "id": "rur", + "author": "Karel Čapek", + "title": "R. U. R.", + "genre": "Drama" + }, + { + "id": "revizor", + "author": "Nikolaj Vasiljevič Gogol", + "title": "Revizor", + "translator": "Mahler, Suchařípa, Morávková", + "genre": "Drama" + }, + { + "id": "romeo-a-julie", + "author": "William Shakespeare", + "title": "Romeo a Julie", + "translator": "Hilský", + "genre": "Drama" + }, + { + "id": "romeo-julie-a-tma", + "author": "Jan Otčenášek", + "title": "Romeo, Julie a tma", + "genre": "Próza" + }, + { + "id": "rozmarne-leto", + "author": "Vladislav Vančura", + "title": "Rozmarné léto", + "genre": "Próza" + }, + { + "id": "ruze-pro-algernon", + "author": "Daniel Keyes", + "title": "Růže pro Algernon", + "translator": "Podaný", + "genre": "Próza" + }, + { + "id": "saturnin", + "author": "Zdeněk Jirotka", + "title": "Saturnin", + "genre": "Próza" + }, + { + "id": "sluha-dvou-panu", + "author": "Carlo Goldoni", + "title": "Sluha dvou pánů", + "translator": "Bezděková", + "genre": "Drama" + }, + { + "id": "smrt-krasnych-srncu", + "author": "Ota Pavel", + "title": "Smrt krásných srnců", + "genre": "Próza" + }, + { + "id": "sofiina-volba", + "author": "William Styron", + "title": "Sofiina volba", + "translator": "Nenadál", + "genre": "Próza" + }, + { + "id": "fuks", + "author": "Ladislav Fuks", + "title": "Spalovač mrtvol", + "genre": "Próza", + "full": true, + "page": "cetbaFuks" + }, + { + "id": "stare-recke-baje", + "author": "Eduard Petiška", + "title": "Staré řecké báje a pověsti", + "genre": "Próza" + }, + { + "id": "starec-a-more", + "author": "Ernest Hemingway", + "title": "Stařec a moře", + "translator": "Vrba", + "genre": "Próza" + }, + { + "id": "svaty-xaverius", + "author": "Jakub Arbes", + "title": "Svatý Xaverius", + "genre": "Próza" + }, + { + "id": "tereza-raquinova", + "author": "Émile Zola", + "title": "Tereza Raquinová", + "genre": "Próza" + }, + { + "id": "tezka-hodina", + "author": "Jiří Wolker", + "title": "Těžká hodina", + "genre": "Poezie" + }, + { + "id": "tyrolske-elegie", + "author": "Karel Havlíček Borovský", + "title": "Tyrolské elegie", + "genre": "Poezie" + }, + { + "id": "valka-s-mloky", + "author": "Karel Čapek", + "title": "Válka s mloky", + "genre": "Próza" + }, + { + "id": "velky-cirkus", + "author": "Pierre Clostermann", + "title": "Velký cirkus", + "translator": "Jedlička", + "genre": "Próza" + }, + { + "id": "velky-gatsby", + "author": "F. Scott Fitzgerald", + "title": "Velký Gatsby", + "translator": "Dorůžka", + "genre": "Próza" + }, + { + "id": "tridni-kniha", + "author": "Ladislav Smoljak, Zdeněk Svěrák", + "title": "Vyšetřování ztráty třídní knihy", + "genre": "Drama" + }, + { + "id": "zabijak", + "author": "Émile Zola", + "title": "Zabiják", + "translator": "Kárl", + "genre": "Próza" + }, + { + "id": "zbabelci", + "author": "Josef Škvorecký", + "title": "Zbabělci", + "genre": "Próza" + }, + { + "id": "zert", + "author": "Milan Kundera", + "title": "Žert", + "genre": "Próza" + } +] diff --git a/ios/Maturita/Route.swift b/ios/Maturita/Route.swift index f7800eb..04845f9 100644 --- a/ios/Maturita/Route.swift +++ b/ios/Maturita/Route.swift @@ -50,7 +50,10 @@ enum Route: Hashable { case .mluvnice: return "mluvnice" case .mluvEx(let n): return "mluve\(n)" case .readingList: return "readinglist" - case .book(let id): return id == "1984" ? "cetba1984" : "cetbaFuks" + case .book(let id): + if id == "1984" { return "cetba1984" } + if id == "fuks" { return "cetbaFuks" } + return "cetba_" + id.replacingOccurrences(of: "-", with: "_") case .bookQuiz(let id): return id == "1984" ? "cetba1984quiz" : "cetbaFuksQuiz" case .bookPlot(let id): return id == "1984" ? "cetba1984dej" : "cetbaFuksDej" } @@ -120,6 +123,10 @@ func routeFromPage(_ page: String) -> Route? { case "cetbaFuksQuiz": return .bookQuiz("fuks") case "cetbaFuksDej": return .bookPlot("fuks") default: + if page.hasPrefix("cetba_") { + let slug = String(page.dropFirst(6)).replacingOccurrences(of: "_", with: "-") + return .book(slug) + } if let m = page.wholeMatch(of: /unit(\d+)/), let n = Int(m.1) { return .unitMap(n - 1) } diff --git a/ios/Maturita/UI/Screens.swift b/ios/Maturita/UI/Screens.swift index b996c37..f068b09 100644 --- a/ios/Maturita/UI/Screens.swift +++ b/ios/Maturita/UI/Screens.swift @@ -887,7 +887,10 @@ struct BookListScreen: View { Label { VStack(alignment: .leading) { Text(b.str("title")) - Text(vm.tr(b.str("subKey"))).font(.caption).foregroundStyle(.secondary) + let genre = b.str("genre") + Text(genre.isEmpty ? vm.tr(b.str("subKey")) : genre) + .font(.caption) + .foregroundStyle(.secondary) } } icon: { Image(systemName: "book.fill") @@ -907,25 +910,31 @@ struct BookScreen: View { var body: some View { if let b = vm.content.book(id) { + let hasQuiz = !b.arr("quiz").isEmpty + let hasPlot = !b.arr("plot").isEmpty List { - NavigationLink(value: Route.bookQuiz(id)) { - Label { - VStack(alignment: .leading) { - Text(vm.tr(b.str("quizTitle"))) - Text(vm.tr(b.str("quizSub"))).font(.caption).foregroundStyle(.secondary) + if hasQuiz { + NavigationLink(value: Route.bookQuiz(id)) { + Label { + VStack(alignment: .leading) { + Text(vm.tr(b.str("quizTitle"))) + Text(vm.tr(b.str("quizSub"))).font(.caption).foregroundStyle(.secondary) + } + } icon: { + Image(systemName: "questionmark.circle") } - } icon: { - Image(systemName: "questionmark.circle") } } - NavigationLink(value: Route.bookPlot(id)) { - Label { - VStack(alignment: .leading) { - Text(vm.tr(b.str("plotTitle"))) - Text(vm.tr(b.str("plotSub"))).font(.caption).foregroundStyle(.secondary) + if hasPlot { + NavigationLink(value: Route.bookPlot(id)) { + Label { + VStack(alignment: .leading) { + Text(vm.tr(b.str("plotTitle"))) + Text(vm.tr(b.str("plotSub"))).font(.caption).foregroundStyle(.secondary) + } + } icon: { + Image(systemName: "list.number") } - } icon: { - Image(systemName: "list.number") } } ForEach(Array(b.arr("notes").enumerated()), id: \.offset) { _, note in diff --git a/scripts/extract-android-content.py b/scripts/extract-android-content.py index 433f5ed..af9bb11 100644 --- a/scripts/extract-android-content.py +++ b/scripts/extract-android-content.py @@ -1165,10 +1165,11 @@ def main() -> int: def note_lines(fn, name): return str_list(A(f"{fn}.{name}")) - books = [ - { - "id": "1984", - "title": "George Orwell – 1984", + catalog_path = ROOT / "data" / "cetba-catalog.json" + catalog = json.loads(catalog_path.read_text(encoding="utf-8")) + + full_books = { + "1984": { "subKey": "cetba1984_sub", "page": "cetba1984", "quizTitle": "lit_quiz_title", @@ -1189,9 +1190,7 @@ def main() -> int: "plot": assembly_items(A("lit_plot_items")), "plotMeaning": str_list(A("lit_plot_meaning")), }, - { - "id": "fuks", - "title": "Ladislav Fuks – Spalovač mrtvol", + "fuks": { "subKey": "cetbaFuks_sub", "page": "cetbaFuks", "quizTitle": "lit_fuks_quiz_title", @@ -1212,7 +1211,78 @@ def main() -> int: "plot": assembly_items(A("fuks_plot_items")), "plotMeaning": str_list(A("fuks_plot_meaning")), }, + } + + books = [] + for entry in catalog: + bid = entry["id"] + display = f"{entry['author']} – {entry['title']}" + page = entry.get("page") or f"cetba_{bid.replace('-', '_')}" + if bid in full_books: + book = {"id": bid, "title": display, **full_books[bid]} + book["genre"] = entry.get("genre", "") + books.append(book) + continue + about = [f"Autor: {entry['author']}", f"Žánr: {entry['genre']}"] + if entry.get("translator"): + about.append(f"Překlad: {entry['translator']}") + about.append("Ze školního seznamu maturitní četby.") + books.append({ + "id": bid, + "title": display, + "subKey": "cetba_entry_sub", + "page": page, + "genre": entry["genre"], + "quizTitle": "", + "quizSub": "", + "plotTitle": "", + "plotSub": "", + "notes": [ + {"title": "O knize", "icon": "book", "lines": about}, + ], + "quiz": [], + "plot": [], + "plotMeaning": [], + }) + + # GTK catalog include for the reading-list path map + inc_lines = [ + "/* Generated from data/cetba-catalog.json – do not edit by hand. */", + f"#define BOOK_NODES {len(catalog)}", + "", + "typedef struct {", + " const char *title;", + " const char *target;", + " const char *author;", + " const char *work;", + " const char *genre;", + " const char *translator;", + " int full;", + "} BookDef;", + "", + "static const BookDef book_defs[BOOK_NODES] = {", ] + for entry in catalog: + bid = entry["id"] + display = f"{entry['author']} – {entry['title']}" + page = entry.get("page") or f"cetba_{bid.replace('-', '_')}" + if entry.get("full"): + target = entry.get("page") or page + full = 1 + else: + target = "cetbastub" + full = 0 + transl = entry.get("translator") or "" + def c_str(s: str) -> str: + return '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"' + transl_c = "NULL" if not transl else c_str(transl) + inc_lines.append( + f" {{{c_str(display)}, {c_str(target)}, {c_str(entry['author'])}, " + f"{c_str(entry['title'])}, {c_str(entry['genre'])}, {transl_c}, {full}}}," + ) + inc_lines.append("};") + inc_lines.append("") + (SRC / "cetba_catalog.inc").write_text("\n".join(inc_lines) + "\n", encoding="utf-8") subjects = [ {"key": "Deutsch", "open": True, "target": "roadmap", "icon": "de"}, diff --git a/src/cetba.c b/src/cetba.c index ec4b3e8..141fbea 100644 --- a/src/cetba.c +++ b/src/cetba.c @@ -1211,17 +1211,11 @@ static void lit_note_card(GtkWidget *parent, const char *title, /* Reading roadmap (Maturitní četba) */ /* ------------------------------------------------------------------ */ -#define BOOK_NODES 2 +#include "cetba_catalog.inc" -typedef struct { - const char *title; - const char *target; -} BookDef; - -static const BookDef book_defs[BOOK_NODES] = { - {"George Orwell – 1984", "cetba1984"}, - {"Ladislav Fuks – Spalovač mrtvol", "cetbaFuks"}, -}; +static int stub_book_idx = -1; +static GtkWidget *stub_title_lbl; +static GtkWidget *stub_about_box; static GtkWidget *book_rail; static GtkWidget *book_nodes[BOOK_NODES]; @@ -1340,6 +1334,58 @@ void book_rail_theme_reset(void) { gtk_widget_queue_draw(book_rail); } +static void rebuild_stub_about(int idx) { + GtkWidget *child; + static char author_buf[192]; + static char genre_buf[96]; + static char transl_buf[192]; + const char *lines[4]; + int n = 0; + + if (!stub_about_box || idx < 0 || idx >= BOOK_NODES) + return; + + while ((child = gtk_widget_get_first_child(stub_about_box))) + gtk_box_remove(GTK_BOX(stub_about_box), child); + + g_snprintf(author_buf, sizeof author_buf, "Autor: %s", + book_defs[idx].author); + g_snprintf(genre_buf, sizeof genre_buf, "Žánr: %s", + book_defs[idx].genre); + lines[n++] = author_buf; + lines[n++] = genre_buf; + if (book_defs[idx].translator) { + g_snprintf(transl_buf, sizeof transl_buf, "Překlad: %s", + book_defs[idx].translator); + lines[n++] = transl_buf; + } + lines[n++] = tr("cetba_stub_soon"); + + for (int i = 0; i < n; i++) { + GtkWidget *l = gtk_label_new(lines[i]); + gtk_widget_set_halign(l, GTK_ALIGN_START); + gtk_label_set_wrap(GTK_LABEL(l), TRUE); + gtk_label_set_xalign(GTK_LABEL(l), 0.0); + gtk_widget_add_css_class(l, "notes-body"); + gtk_box_append(GTK_BOX(stub_about_box), l); + } +} + +static void on_book_node_clicked(GtkButton *button, gpointer user_data) { + int idx = GPOINTER_TO_INT(user_data); + const char *target = book_defs[idx].target; + + (void)button; + if (!book_defs[idx].full) { + stub_book_idx = idx; + if (stub_title_lbl) + gtk_label_set_text(GTK_LABEL(stub_title_lbl), book_defs[idx].title); + rebuild_stub_about(idx); + } + if (main_stack && target) + gtk_stack_set_visible_child_name(main_stack, target); +} + static GtkWidget *book_make_node(int i) { GtkWidget *btn = gtk_button_new(); GtkWidget *icon = icon_area_new(draw_book_badge_icon, 0, 0, 0, 48); @@ -1351,9 +1397,8 @@ static GtkWidget *book_make_node(int i) { gtk_button_set_child(GTK_BUTTON(btn), icon); - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(book_defs[i].target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); + g_signal_connect(btn, "clicked", G_CALLBACK(on_book_node_clicked), + GINT_TO_POINTER(i)); return btn; } @@ -1593,3 +1638,113 @@ GtkWidget *build_cetba_fuks_page(void) { return page; } + +GtkWidget *build_cetba_stub_page(void) { + GtkWidget *page; + GtkWidget *top; + GtkWidget *center; + GtkWidget *scroll; + GtkWidget *box; + GtkWidget *card; + GtkWidget *head; + GtkWidget *ic; + GtkWidget *t; + GtkWidget *sub; + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + 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); + + top = gtk_center_box_new(); + gtk_widget_add_css_class(top, "page-top"); + gtk_widget_set_margin_top(top, 8); + gtk_widget_set_margin_bottom(top, 18); + gtk_center_box_set_start_widget(GTK_CENTER_BOX(top), + make_back_button("readinglist")); + + center = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); + gtk_widget_set_valign(center, GTK_ALIGN_CENTER); + gtk_center_box_set_center_widget(GTK_CENTER_BOX(top), center); + + stub_title_lbl = gtk_label_new("…"); + gtk_widget_set_halign(stub_title_lbl, GTK_ALIGN_CENTER); + gtk_label_set_wrap(GTK_LABEL(stub_title_lbl), TRUE); + gtk_widget_add_css_class(stub_title_lbl, "roadmap-title"); + gtk_box_append(GTK_BOX(center), stub_title_lbl); + + sub = gtk_label_new(NULL); + i18n_bind(sub, "cetba_entry_sub", 0); + gtk_widget_set_halign(sub, GTK_ALIGN_CENTER); + gtk_widget_add_css_class(sub, "roadmap-sub"); + gtk_label_set_wrap(GTK_LABEL(sub), TRUE); + gtk_box_append(GTK_BOX(center), sub); + + gtk_box_append(GTK_BOX(page), top); + + 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, 14); + gtk_widget_set_margin_bottom(scroll, 14); + gtk_box_append(GTK_BOX(page), scroll); + + box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), box); + + card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); + gtk_widget_add_css_class(card, "notes-card"); + gtk_widget_set_margin_bottom(card, 14); + gtk_box_append(GTK_BOX(box), card); + + head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_box_append(GTK_BOX(card), head); + ic = icon_area_new(draw_book_icon, 0, 0, 0, 26); + gtk_widget_set_valign(ic, GTK_ALIGN_CENTER); + gtk_box_append(GTK_BOX(head), ic); + t = gtk_label_new("O knize"); + gtk_widget_set_halign(t, GTK_ALIGN_START); + gtk_widget_set_valign(t, GTK_ALIGN_CENTER); + gtk_widget_add_css_class(t, "notes-title"); + gtk_box_append(GTK_BOX(head), t); + + stub_about_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); + gtk_box_append(GTK_BOX(card), stub_about_box); + + return page; +} + +void cetba_open_stub(int idx) { + if (idx < 0 || idx >= BOOK_NODES || book_defs[idx].full) + return; + stub_book_idx = idx; + if (stub_title_lbl) + gtk_label_set_text(GTK_LABEL(stub_title_lbl), book_defs[idx].title); + rebuild_stub_about(idx); + if (main_stack) + gtk_stack_set_visible_child_name(main_stack, "cetbastub"); +} + +void cetba_register_search(void) { + char target[32]; + + for (int i = 0; i < BOOK_NODES; i++) { + if (book_defs[i].full) { + search_catalog_add(book_defs[i].title, tr("search_book"), + book_defs[i].target, FALSE, 2, book_defs[i].author); + if (g_strcmp0(book_defs[i].target, "cetba1984") == 0) + search_catalog_add(tr("lit_quiz_title"), tr("search_exercise"), + "cetba1984quiz", FALSE, 3, "orwell kviz"); + else if (g_strcmp0(book_defs[i].target, "cetbaFuks") == 0) + search_catalog_add(tr("lit_fuks_quiz_title"), + tr("search_exercise"), "cetbaFuksQuiz", + FALSE, 3, "fuks kviz"); + } else { + g_snprintf(target, sizeof target, "cetbastub:%d", i); + search_catalog_add(book_defs[i].title, tr("search_book"), + target, FALSE, 2, book_defs[i].author); + } + } +} diff --git a/src/cetba_catalog.inc b/src/cetba_catalog.inc new file mode 100644 index 0000000..3a861f6 --- /dev/null +++ b/src/cetba_catalog.inc @@ -0,0 +1,98 @@ +/* Generated from data/cetba-catalog.json – do not edit by hand. */ +#define BOOK_NODES 82 + +typedef struct { + const char *title; + const char *target; + const char *author; + const char *work; + const char *genre; + const char *translator; + int full; +} BookDef; + +static const BookDef book_defs[BOOK_NODES] = { + {"George Orwell – 1984", "cetba1984", "George Orwell", "1984", "Próza", "Šimečková", 1}, + {"Ray Bradbury – 451 stupňů Fahrenheita", "cetbastub", "Ray Bradbury", "451 stupňů Fahrenheita", "Próza", "Nezval", 0}, + {"Václav Havel – Audience", "cetbastub", "Václav Havel", "Audience", "Drama", NULL, 0}, + {"Michal Viewegh – Báječná léta pod psa", "cetbastub", "Michal Viewegh", "Báječná léta pod psa", "Próza", NULL, 0}, + {"Victor Hugo – Bídníci", "cetbastub", "Victor Hugo", "Bídníci", "Próza", "Pavlousková", 0}, + {"Karel Čapek – Bílá nemoc", "cetbastub", "Karel Čapek", "Bílá nemoc", "Drama", NULL, 0}, + {"Karel Poláček – Bylo nás pět", "cetbastub", "Karel Poláček", "Bylo nás pět", "Próza", NULL, 0}, + {"Samuel Beckett – Čekání na Godota", "cetbastub", "Samuel Beckett", "Čekání na Godota", "Drama", "Ouředník", 0}, + {"Zdeněk Svěrák, Ladislav Smoljak – České nebe", "cetbastub", "Zdeněk Svěrák, Ladislav Smoljak", "České nebe", "Drama", NULL, 0}, + {"Giovanni Boccaccio – Dekameron", "cetbastub", "Giovanni Boccaccio", "Dekameron", "Próza", "Krátký", 0}, + {"John Wyndham – Den trifidů", "cetbastub", "John Wyndham", "Den trifidů", "Próza", "Kořán", 0}, + {"Anne Franková – Deník Anne Frankové", "cetbastub", "Anne Franková", "Deník Anne Frankové", "Próza", NULL, 0}, + {"Robert Louis Stevenson – Dr. Jekyll a Mr. Hyde", "cetbastub", "Robert Louis Stevenson", "Dr. Jekyll a Mr. Hyde", "Próza", "Kořán", 0}, + {"Vítězslav Nezval – Edison", "cetbastub", "Vítězslav Nezval", "Edison", "Poezie", NULL, 0}, + {"George Orwell – Farma zvířat", "cetbastub", "George Orwell", "Farma zvířat", "Próza", "Gössell", 0}, + {"Jonathan Swift – Gulliverovy cesty", "cetbastub", "Jonathan Swift", "Gulliverovy cesty", "Próza", "Skoumal", 0}, + {"William Shakespeare – Hamlet", "cetbastub", "William Shakespeare", "Hamlet", "Drama", "Nevrla", 0}, + {"Edgar Allan Poe – Havran", "cetbastub", "Edgar Allan Poe", "Havran", "Poezie", NULL, 0}, + {"Suzanne Collins – Hladové hry – I. Aréna smrti", "cetbastub", "Suzanne Collins", "Hladové hry – I. Aréna smrti", "Próza", "Dušek", 0}, + {"Joseph Heller – Hlava XXII", "cetbastub", "Joseph Heller", "Hlava XXII", "Próza", "Jindra", 0}, + {"Victor Hugo – Chrám Matky Boží", "cetbastub", "Victor Hugo", "Chrám Matky Boží", "Próza", "Tomášková", 0}, + {"Patrick Ryan – Jak jsem vyhrál válku", "cetbastub", "Patrick Ryan", "Jak jsem vyhrál válku", "Próza", "Vrba", 0}, + {"Charlotte Brontëová – Jana Eyrová", "cetbastub", "Charlotte Brontëová", "Jana Eyrová", "Próza", "Polák", 0}, + {"Alexandr Solženicyn – Jeden den Ivana Denisoviče", "cetbastub", "Alexandr Solženicyn", "Jeden den Ivana Denisoviče", "Próza", "Machonin, Nováková", 0}, + {"Umberto Eco – Jméno růže", "cetbastub", "Umberto Eco", "Jméno růže", "Próza", "Frýbort", 0}, + {"Karel Václav Rais – Kalibův zločin", "cetbastub", "Karel Václav Rais", "Kalibův zločin", "Próza", NULL, 0}, + {"Karel Kryl – Kníška Karla Kryla", "cetbastub", "Karel Kryl", "Kníška Karla Kryla", "Poezie", NULL, 0}, + {"Ernest Hemingway – Komu zvoní hrana", "cetbastub", "Ernest Hemingway", "Komu zvoní hrana", "Próza", "Valja, Kobík", 0}, + {"Sofoklés – Král Oidipus", "cetbastub", "Sofoklés", "Král Oidipus", "Drama", "Stiebitz", 0}, + {"Viktor Dyk – Krysař", "cetbastub", "Viktor Dyk", "Krysař", "Próza", NULL, 0}, + {"Guy de Maupassant – Kulička", "cetbastub", "Guy de Maupassant", "Kulička", "Próza", "Guth", 0}, + {"Charles Baudelaire – Květy zla", "cetbastub", "Charles Baudelaire", "Květy zla", "Poezie", "Nezval", 0}, + {"Karel Jaromír Erben – Kytice", "cetbastub", "Karel Jaromír Erben", "Kytice", "Poezie", NULL, 0}, + {"Molière – Lakomec", "cetbastub", "Molière", "Lakomec", "Drama", "Mikeš", 0}, + {"Vladimir Nabokov – Lolita", "cetbastub", "Vladimir Nabokov", "Lolita", "Próza", "Kořínek", 0}, + {"Karel Hynek Mácha – Máj", "cetbastub", "Karel Hynek Mácha", "Máj", "Poezie", NULL, 0}, + {"Antoine de Saint-Exupéry – Malý princ", "cetbastub", "Antoine de Saint-Exupéry", "Malý princ", "Próza", "Stavinohová", 0}, + {"Alois Mrštík, Vilém Mrštík – Maryša", "cetbastub", "Alois Mrštík, Vilém Mrštík", "Maryša", "Drama", NULL, 0}, + {"Arnošt Lustig – Modlitba pro Kateřinu Horovitzovou", "cetbastub", "Arnošt Lustig", "Modlitba pro Kateřinu Horovitzovou", "Próza", NULL, 0}, + {"Pierre Boulle – Most přes řeku Kwai", "cetbastub", "Pierre Boulle", "Most přes řeku Kwai", "Próza", "Šup", 0}, + {"Christiane F. – My děti ze stanice ZOO", "cetbastub", "Christiane F.", "My děti ze stanice ZOO", "Próza", "Soukupová", 0}, + {"Jack Kerouac – Na cestě", "cetbastub", "Jack Kerouac", "Na cestě", "Próza", "Popel", 0}, + {"Erich Maria Remarque – Na západní frontě klid", "cetbastub", "Erich Maria Remarque", "Na západní frontě klid", "Próza", "Gel", 0}, + {"Friedrich Dürrenmatt – Návštěva staré dámy", "cetbastub", "Friedrich Dürrenmatt", "Návštěva staré dámy", "Drama", NULL, 0}, + {"Erich Maria Remarque – Nebe nezná vyvolených", "cetbastub", "Erich Maria Remarque", "Nebe nezná vyvolených", "Próza", "V. a K. Holubovi", 0}, + {"John Steinbeck – O myších a lidech", "cetbastub", "John Steinbeck", "O myších a lidech", "Próza", "Vendyš", 0}, + {"Oscar Wilde – Obraz Doriana Graye", "cetbastub", "Oscar Wilde", "Obraz Doriana Graye", "Próza", "Novák", 0}, + {"Bohumil Hrabal – Obsluhoval jsem anglického krále", "cetbastub", "Bohumil Hrabal", "Obsluhoval jsem anglického krále", "Próza", NULL, 0}, + {"Charles Dickens – Oliver Twist", "cetbastub", "Charles Dickens", "Oliver Twist", "Próza", "E. a E. Tilschovi", 0}, + {"Bohumil Hrabal – Ostře sledované vlaky", "cetbastub", "Bohumil Hrabal", "Ostře sledované vlaky", "Próza", NULL, 0}, + {"Jaroslav Hašek – Osudy dobrého vojáka Švejka za světové války", "cetbastub", "Jaroslav Hašek", "Osudy dobrého vojáka Švejka za světové války", "Próza", NULL, 0}, + {"William Golding – Pán much", "cetbastub", "William Golding", "Pán much", "Próza", "Kovályová", 0}, + {"J. R. R. Tolkien – Pán prstenů – Společenstvo prstenu", "cetbastub", "J. R. R. Tolkien", "Pán prstenů – Společenstvo prstenu", "Próza", "Pošustová", 0}, + {"Romain Rolland – Petr a Lucie", "cetbastub", "Romain Rolland", "Petr a Lucie", "Próza", "Zaorálek", 0}, + {"Edgar Allan Poe – Povídky", "cetbastub", "Edgar Allan Poe", "Povídky", "Próza", NULL, 0}, + {"Karel Čapek – Povídky z jedné a druhé kapsy", "cetbastub", "Karel Čapek", "Povídky z jedné a druhé kapsy", "Próza", NULL, 0}, + {"Franz Kafka – Proměna", "cetbastub", "Franz Kafka", "Proměna", "Próza", NULL, 0}, + {"Jane Austenová – Pýcha a předsudek", "cetbastub", "Jane Austenová", "Pýcha a předsudek", "Próza", "Poláčková", 0}, + {"Karel Čapek – R. U. R.", "cetbastub", "Karel Čapek", "R. U. R.", "Drama", NULL, 0}, + {"Nikolaj Vasiljevič Gogol – Revizor", "cetbastub", "Nikolaj Vasiljevič Gogol", "Revizor", "Drama", "Mahler, Suchařípa, Morávková", 0}, + {"William Shakespeare – Romeo a Julie", "cetbastub", "William Shakespeare", "Romeo a Julie", "Drama", "Hilský", 0}, + {"Jan Otčenášek – Romeo, Julie a tma", "cetbastub", "Jan Otčenášek", "Romeo, Julie a tma", "Próza", NULL, 0}, + {"Vladislav Vančura – Rozmarné léto", "cetbastub", "Vladislav Vančura", "Rozmarné léto", "Próza", NULL, 0}, + {"Daniel Keyes – Růže pro Algernon", "cetbastub", "Daniel Keyes", "Růže pro Algernon", "Próza", "Podaný", 0}, + {"Zdeněk Jirotka – Saturnin", "cetbastub", "Zdeněk Jirotka", "Saturnin", "Próza", NULL, 0}, + {"Carlo Goldoni – Sluha dvou pánů", "cetbastub", "Carlo Goldoni", "Sluha dvou pánů", "Drama", "Bezděková", 0}, + {"Ota Pavel – Smrt krásných srnců", "cetbastub", "Ota Pavel", "Smrt krásných srnců", "Próza", NULL, 0}, + {"William Styron – Sofiina volba", "cetbastub", "William Styron", "Sofiina volba", "Próza", "Nenadál", 0}, + {"Ladislav Fuks – Spalovač mrtvol", "cetbaFuks", "Ladislav Fuks", "Spalovač mrtvol", "Próza", NULL, 1}, + {"Eduard Petiška – Staré řecké báje a pověsti", "cetbastub", "Eduard Petiška", "Staré řecké báje a pověsti", "Próza", NULL, 0}, + {"Ernest Hemingway – Stařec a moře", "cetbastub", "Ernest Hemingway", "Stařec a moře", "Próza", "Vrba", 0}, + {"Jakub Arbes – Svatý Xaverius", "cetbastub", "Jakub Arbes", "Svatý Xaverius", "Próza", NULL, 0}, + {"Émile Zola – Tereza Raquinová", "cetbastub", "Émile Zola", "Tereza Raquinová", "Próza", NULL, 0}, + {"Jiří Wolker – Těžká hodina", "cetbastub", "Jiří Wolker", "Těžká hodina", "Poezie", NULL, 0}, + {"Karel Havlíček Borovský – Tyrolské elegie", "cetbastub", "Karel Havlíček Borovský", "Tyrolské elegie", "Poezie", NULL, 0}, + {"Karel Čapek – Válka s mloky", "cetbastub", "Karel Čapek", "Válka s mloky", "Próza", NULL, 0}, + {"Pierre Clostermann – Velký cirkus", "cetbastub", "Pierre Clostermann", "Velký cirkus", "Próza", "Jedlička", 0}, + {"F. Scott Fitzgerald – Velký Gatsby", "cetbastub", "F. Scott Fitzgerald", "Velký Gatsby", "Próza", "Dorůžka", 0}, + {"Ladislav Smoljak, Zdeněk Svěrák – Vyšetřování ztráty třídní knihy", "cetbastub", "Ladislav Smoljak, Zdeněk Svěrák", "Vyšetřování ztráty třídní knihy", "Drama", NULL, 0}, + {"Émile Zola – Zabiják", "cetbastub", "Émile Zola", "Zabiják", "Próza", "Kárl", 0}, + {"Josef Škvorecký – Zbabělci", "cetbastub", "Josef Škvorecký", "Zbabělci", "Próza", NULL, 0}, + {"Milan Kundera – Žert", "cetbastub", "Milan Kundera", "Žert", "Próza", NULL, 0}, +}; + diff --git a/src/i18n.c b/src/i18n.c index 7921bd9..3360050 100644 --- a/src/i18n.c +++ b/src/i18n.c @@ -552,6 +552,10 @@ const TrEntry tr_ui[] = { {"book_1984_sub", "Antiutopický román • 1949", "Dystopian novel • 1949"}, {"cetba1984_sub", "Přehled knihy, klíčové pojmy a cvičení.", "Book overview, key terms and exercises."}, + {"cetba_entry_sub", "Údaje ze školního seznamu maturitní četby.", + "Details from the school maturita reading list."}, + {"cetba_stub_soon", "Podrobný přehled a cvičení zatím nejsou k dispozici.", + "A detailed overview and exercises are not available yet."}, {"lit_quiz_title", "Kvíz: George Orwell – 1984", "Quiz: George Orwell – 1984"}, {"lit_quiz_sub", "U každé otázky vyberte jednu správnou odpověď.", diff --git a/src/main.c b/src/main.c index ccb2da6..4cf4620 100644 --- a/src/main.c +++ b/src/main.c @@ -519,6 +519,7 @@ void activate(GtkApplication *app, gpointer user_data) { "cetbaFuksQuiz"); gtk_stack_add_named(main_stack, build_cetba_fuks_plot_page(), "cetbaFuksDej"); + gtk_stack_add_named(main_stack, build_cetba_stub_page(), "cetbastub"); gtk_stack_add_named(main_stack, build_hw_unit1_page(), "hwunit1"); gtk_stack_add_named(main_stack, build_hw_unit1_exercise_page(), "hwex1"); gtk_stack_add_named(main_stack, build_hw_unit2_page(), "hwunit2"); diff --git a/src/maturita.h b/src/maturita.h index 2ca7795..6e45df5 100644 --- a/src/maturita.h +++ b/src/maturita.h @@ -851,6 +851,12 @@ GtkWidget *build_cetba1984_plot_page(void); GtkWidget *build_cetba_fuks_page(void); GtkWidget *build_cetba_fuks_quiz_page(void); GtkWidget *build_cetba_fuks_plot_page(void); +GtkWidget *build_cetba_stub_page(void); +void cetba_register_search(void); +void cetba_open_stub(int idx); +void search_catalog_add(const char *title, const char *subtitle, + const char *target, gboolean locked, int rank, + const char *extra); void book_rail_theme_reset(void); GtkWidget *build_hw_unit1_page(void); GtkWidget *build_hw_unit1_exercise_page(void); diff --git a/src/search.c b/src/search.c index 7260300..9131b5a 100644 --- a/src/search.c +++ b/src/search.c @@ -1,5 +1,6 @@ #include "maturita.h" +#include #include #define SEARCH_MAX 24 @@ -90,12 +91,23 @@ static void item_free(gpointer p) { g_free(it); } +static void catalog_add(const char *title, const char *subtitle, + const char *target, gboolean locked, int rank, + const char *extra); + +void search_catalog_add(const char *title, const char *subtitle, + const char *target, gboolean locked, int rank, + const char *extra) { + catalog_add(title, subtitle, target, locked, rank, extra); +} + static void catalog_add(const char *title, const char *subtitle, const char *target, gboolean locked, int rank, const char *extra) { if (!title || !target) return; - if (main_stack && !gtk_stack_get_child_by_name(main_stack, target)) + if (main_stack && !gtk_stack_get_child_by_name(main_stack, target) + && strncmp(target, "cetbastub:", 10) != 0) return; g_ptr_array_add(search_items, item_new(title, subtitle, target, locked, rank, extra)); @@ -190,14 +202,7 @@ static void catalog_rebuild(void) { "gramatika grammar"); catalog_add_key("Maturitní četba", "search_book", "readinglist", FALSE, 1, "knihy books"); - catalog_add("George Orwell – 1984", tr("search_book"), "cetba1984", - FALSE, 2, "orwell dystopie"); - catalog_add(tr("lit_quiz_title"), tr("search_exercise"), "cetba1984quiz", - FALSE, 3, "orwell kviz"); - catalog_add("Ladislav Fuks – Spalovač mrtvol", tr("search_book"), - "cetbaFuks", FALSE, 2, "fuks cremator"); - catalog_add(tr("lit_fuks_quiz_title"), tr("search_exercise"), - "cetbaFuksQuiz", FALSE, 3, "fuks kviz"); + cetba_register_search(); { static const char *mluv_names[] = { @@ -247,6 +252,12 @@ static int cmp_item(gconstpointer a, gconstpointer b) { static void search_go(const char *target) { if (!target || !main_stack) return; + if (strncmp(target, "cetbastub:", 10) == 0) { + int idx = atoi(target + 10); + search_close(); + cetba_open_stub(idx); + return; + } if (!gtk_stack_get_child_by_name(main_stack, target)) return; search_close();