aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/tests/test_hub.py22
-rw-r--r--app/tests/test_tui.py28
-rw-r--r--app/ui/hub.py18
-rw-r--r--app/ui/tui.py10
4 files changed, 56 insertions, 22 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index daa4abd..fbede75 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -364,20 +364,24 @@ class HubMenuTests(unittest.TestCase):
self.assertIn("qwen3_tts_1_7b_customvoice_q8_0", text)
self.assertIn("5. Go to Generate Audiobooks.", text)
# The "no need to manually start/stop" sentence sits on its own
- # indented line below the step-5 paragraph.
- self.assertIn("stop it.\nThere is no need to manually "
+ # indented line below the step-5 paragraph (one leading space
+ # beyond the 2-space indent, lining up with the step text).
+ self.assertIn("stop it.\n There is no need to manually "
"start/stop servers.", text)
self.assertIn("6. Generated audiobooks (m4b, mp3, etc.) will "
"output here:", text)
# The three folder paths are their own indented, white-bold
- # ("input") rows; the numbered steps start at the margin. They
- # resolve live from the converter module, so a Settings change
- # this session is reflected.
- self.assertIn(([(str(hub.converter_mod.BOOKS_FOLDER), "input")], 1),
+ # ("input") rows; the numbered steps start at the margin and
+ # the indented rows carry a leading space of their own, so
+ # they line up with the step text after the "N. " prefixes.
+ # They resolve live from the converter module, so a Settings
+ # change this session is reflected.
+ self.assertIn(([(" " + str(hub.converter_mod.BOOKS_FOLDER),
+ "input")], 1), items)
+ self.assertIn(([(" " + str(hub.common.VOICES_DIR), "input")], 1),
items)
- self.assertIn(([(str(hub.common.VOICES_DIR), "input")], 1), items)
- self.assertIn(([(str(hub.converter_mod.AUDIOBOOKS_FOLDER), "input")],
- 1), items)
+ self.assertIn(([(" " + str(hub.converter_mod.AUDIOBOOKS_FOLDER),
+ "input")], 1), items)
self.assertEqual(items[0][1], 0)
diff --git a/app/tests/test_tui.py b/app/tests/test_tui.py
index e12da76..e765e60 100644
--- a/app/tests/test_tui.py
+++ b/app/tests/test_tui.py
@@ -1147,6 +1147,34 @@ class CheckboxTreeTests(TuiTestCase):
picked = tui.checkbox_tree(screen, "Pick models", self.FAMILIES)
self.assertEqual(picked, [(0, "pkg-a")])
+ def test_space_toggles_option_row(self):
+ # Enter on the family checks pkg-a and expands; Down twice lands
+ # on the pkg-b option row; Space checks it; confirm returns both.
+ screen = FakeScreen(keys=[10, FakeCurses.KEY_DOWN,
+ FakeCurses.KEY_DOWN, ord(" "), 9, 10])
+ picked = tui.checkbox_tree(screen, "Pick models", self.FAMILIES)
+ self.assertEqual(picked, [(0, "pkg-a"), (0, "pkg-b")])
+
+ def test_enter_toggles_option_row(self):
+ # Enter on the family checks pkg-a and expands; Down lands on the
+ # pkg-a option row; Enter there unchecks it; Down to pkg-b, Space
+ # checks it. Confirm returns only pkg-b.
+ screen = FakeScreen(keys=[10, FakeCurses.KEY_DOWN, 10,
+ FakeCurses.KEY_DOWN, ord(" "), 9, 10])
+ picked = tui.checkbox_tree(screen, "Pick models", self.FAMILIES)
+ self.assertEqual(picked, [(0, "pkg-b")])
+
+ def test_unhandled_key_on_row_is_ignored(self):
+ # A key that is neither motion nor toggle (here "x") must not
+ # toggle anything or crash on either row kind; Esc then aborts.
+ marker = object()
+ screen = FakeScreen(keys=[ord("x"), FakeCurses.KEY_DOWN, ord("x"),
+ 27])
+ self.assertIs(
+ tui.checkbox_tree(screen, "Pick models", self.FAMILIES,
+ back_value=marker),
+ marker)
+
def test_prechecked_selection_confirmed(self):
# checked= seeds the tree (modify flow): Tab then Confirm accepts
# the pre-checked options without any extra key presses.
diff --git a/app/ui/hub.py b/app/ui/hub.py
index 68417f7..4fae67b 100644
--- a/app/ui/hub.py
+++ b/app/ui/hub.py
@@ -834,7 +834,9 @@ def _help_lines() -> list:
Items are text_viewer rows: "" (a blank line) or a (segments,
indent) pair — SEGMENTS are (text, kind) with KIND a theme key
(None = body). Numbered steps start at the margin; every other
- line is indented two spaces so it reads as part of its step. The
+ line is indented three spaces — Frame's two-space indent unit
+ plus a leading space in the row's first segment — so it lines up
+ with the step text after the "N. " prefixes. The
input/output folders are read from the converter module at call
time, so a Settings change this session is reflected without a
restart.
@@ -842,11 +844,11 @@ def _help_lines() -> list:
return [
([("1. ", "title"),
("Put your ebooks (epub, txt, or pdf) here:", None)], 0),
- ([(str(converter_mod.BOOKS_FOLDER), "input")], 1),
+ ([(" " + str(converter_mod.BOOKS_FOLDER), "input")], 1),
"",
([("2. ", "title"),
("Put any .wavs of voices to clone here:", None)], 0),
- ([(str(common.VOICES_DIR), "input")], 1),
+ ([(" " + str(common.VOICES_DIR), "input")], 1),
"",
([("3. ", "title"),
("If no backend is installed, go to ", None),
@@ -858,24 +860,24 @@ def _help_lines() -> list:
("Select TTS models to install. If you're unsure, try "
"these qwen3-tts models:", None)], 0),
"",
- ([("Voice cloning:", None), (" ", None),
+ ([(" Voice cloning:", None), (" ", None),
("qwen3_tts_1_7b_base_q8_0", "ok")], 1),
- ([("Built-in-voice:", None), (" ", None),
+ ([(" Built-in-voice:", None), (" ", None),
("qwen3_tts_1_7b_customvoice_q8_0", "ok")], 1),
"",
- ([("It will take a while to build audio.cpp and download "
+ ([(" It will take a while to build audio.cpp and download "
"the model files.", None)], 1),
"",
([("5. ", "title"), ("Go to ", None),
("Generate Audiobooks", "accent"),
(". It will automatically start the necessary server, "
"generate the books, and stop it.", None)], 0),
- ([("There is no need to manually start/stop servers.", None)], 1),
+ ([(" There is no need to manually start/stop servers.", None)], 1),
"",
([("6. ", "title"),
("Generated audiobooks (m4b, mp3, etc.) will output here:",
None)], 0),
- ([(str(converter_mod.AUDIOBOOKS_FOLDER), "input")], 1),
+ ([(" " + str(converter_mod.AUDIOBOOKS_FOLDER), "input")], 1),
]
diff --git a/app/ui/tui.py b/app/ui/tui.py
index 1997415..7da1dd1 100644
--- a/app/ui/tui.py
+++ b/app/ui/tui.py
@@ -1565,12 +1565,12 @@ def checkbox_tree(scr, title: str, families: List[dict],
if options:
checked.add((index, options[0]["key"]))
expanded.add(index)
- else:
- _, index, option_key = node
- if (index, option_key) in checked:
- checked.discard((index, option_key))
else:
- checked.add((index, option_key))
+ _, index, option_key = node
+ if (index, option_key) in checked:
+ checked.discard((index, option_key))
+ else:
+ checked.add((index, option_key))
# ---------------------------------------------------------------------------