From 88ad8cf7c23570f09b9fc28701e1d26883e97731 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:29:38 +0900 Subject: [PATCH 1/3] feat: expand all changelog nodes --- dzgui/views/pages/changelog.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/dzgui/views/pages/changelog.py b/dzgui/views/pages/changelog.py index 4d36637..9548b11 100644 --- a/dzgui/views/pages/changelog.py +++ b/dzgui/views/pages/changelog.py @@ -1,5 +1,6 @@ import logging import re +import textwrap from typing import TYPE_CHECKING from importlib import resources @@ -7,6 +8,7 @@ from importlib import resources from dzgui.const.constants import APP_NAME, APP_NAME_LOWER, CHANGELOG_PATH from dzgui.util.strings import missing_changelog from dzgui.util.format import format_pango +from dzgui.views.components.box import HBox, VBox from dzgui.views.mixins.help_menu_mixin import HelpMenuMixin from dzgui.views.mixins.scrollable_mixin import ScrollableMixin @@ -31,20 +33,40 @@ class Changelog(HelpMenuMixin, ScrollableMixin, Gtk.ScrolledWindow): # type: ig logger.critical(e) changelog = missing_changelog - # TODO: should long text be wrapped? + # FIXME: wrap long text self.controller = controller self.box = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, spacing=5, margin_top=10 ) self.add(self.box) + expand_all = Gtk.Button( + label="Expand all", halign=Gtk.Align.START, margin_start=20 + ) + expand_all.connect("clicked", self._on_expand_all_clicked) + self.box.add(expand_all) + + self.expanded = False + self.expanders: list[Gtk.Expander] = [] self.connect("key-press-event", self._on_keypress) self.connect("key-press-event", self._on_esc_keypress) changes = self._parse(changelog) self._generate_nodes(changes) + self.show_all() + def _on_expand_all_clicked(self, button: Gtk.Button) -> None: + self.expanded = not self.expanded + for expander in self.expanders: + # NOTE: simply setting set_expanded() does not trigger activate() signal, + # so margins are not applied + if expander.get_expanded() == self.expanded: + continue + expander.activate() + label = "Collapse all" if self.expanded else "Expand all" + button.set_label(label) + def grab_content_area(self) -> None: self.grab_focus() @@ -65,9 +87,7 @@ class Changelog(HelpMenuMixin, ScrollableMixin, Gtk.ScrolledWindow): # type: ig text = "\n".join(changes) formatted = format_pango(text) - container = Gtk.Box( - valign=Gtk.Align.START, halign=Gtk.Align.START - ) + container = Gtk.Box(valign=Gtk.Align.START, halign=Gtk.Align.START) label = Gtk.Label() label.set_markup(formatted) container.add(label) @@ -81,6 +101,7 @@ class Changelog(HelpMenuMixin, ScrollableMixin, Gtk.ScrolledWindow): # type: ig expander.add(container) expander.connect("activate", self._on_expand, container) self.box.add(expander) + self.expanders.append(expander) def _on_expand(self, expander: Gtk.Box, container: Gtk.Box) -> None: """ @@ -94,6 +115,7 @@ class Changelog(HelpMenuMixin, ScrollableMixin, Gtk.ScrolledWindow): # type: ig container.set_margin_bottom(15) def _parse(self, changelog: str) -> list[tuple[str, list[str]]]: + release = "" releases: list[tuple[str, list[str]]] = [] release_notes: list[str] = [] @@ -107,5 +129,5 @@ class Changelog(HelpMenuMixin, ScrollableMixin, Gtk.ScrolledWindow): # type: ig release = "" release = line continue - release_notes.append(line.rstrip()) + release_notes.append(textwrap.fill(line.rstrip(), width=120)) return releases From eeffdb57f36f7aa6eea51e1cc5501957363b7b7c Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:30:10 +0900 Subject: [PATCH 2/3] chore: remove unused imports --- dzgui/views/pages/changelog.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dzgui/views/pages/changelog.py b/dzgui/views/pages/changelog.py index 9548b11..35d6e48 100644 --- a/dzgui/views/pages/changelog.py +++ b/dzgui/views/pages/changelog.py @@ -8,7 +8,6 @@ from importlib import resources from dzgui.const.constants import APP_NAME, APP_NAME_LOWER, CHANGELOG_PATH from dzgui.util.strings import missing_changelog from dzgui.util.format import format_pango -from dzgui.views.components.box import HBox, VBox from dzgui.views.mixins.help_menu_mixin import HelpMenuMixin from dzgui.views.mixins.scrollable_mixin import ScrollableMixin From 79bbc25714e5fe72b3936d5f68d1b6951a6b40d6 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:59:13 +0900 Subject: [PATCH 3/3] chore: add test for changelog markdown headers --- tests/test_changelog.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 3eae186..acc6019 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -1,20 +1,34 @@ +import re import pytest -from importlib import resources -from dzgui.const.constants import APP_NAME_LOWER, CHANGELOG_PATH +from pathlib import Path @pytest.fixture -def changelog(): - path = resources.files(APP_NAME_LOWER).joinpath(CHANGELOG_PATH) - return path +def changelog(request) -> None: + root = request.config.rootpath + changelog = Path(root).joinpath("CHANGELOG.md").read_text() + return changelog -def test_headings(changelog): - with open(changelog, "r") as f: - lines = f.readlines() - for line in lines: - if line.startswith("#"): - pass - # TODO: use regex - pass +def count_hash(line: str) -> int: + cnt = 0 + for c in line: + if c == "#": + cnt += 1 + return cnt + + +@pytest.mark.FOO +def test_changelog_prefix(changelog) -> None: + r = r".*(\[.*\]).*" + lines = changelog.splitlines() + sort = sorted(lines) + match = [line for line in sort if line.startswith("#")] + for m in match: + if "Changelog" in m: + assert count_hash(m) == 1 + elif re.match(r, m) is not None: + assert count_hash(m) == 2 + else: + assert count_hash(m) == 3