"""Marking text, bookmarks and the list, in the reader.""" import asyncio import pytest from textual.widgets import Input, ListView from diora_tui import annotations, epub as epub_mod, progress from diora_tui.annotation_screens import AnnotationsScreen, NoteScreen from diora_tui.app import DioraTuiApp from diora_tui.library_screen import ChoiceScreen from diora_tui.reader_screen import ReaderScreen @pytest.fixture def world(tmp_path, monkeypatch): monkeypatch.setattr(progress, "_default", progress.ProgressStore(tmp_path / "p.json")) store = annotations.AnnotationStore(tmp_path / "ann") monkeypatch.setattr(annotations, "_default", store) lib = tmp_path / "lib" lib.mkdir() return lib, store def book(epub): body = "

Anfang

\n" + "\n".join(f"

\n Absatz {i} eins zwei drei vier fünf sechs sieben.\n

" for i in range(30)) return epub([body], title="Marken") async def open_reader(app, pilot, path): app.push_screen(ReaderScreen(path)) for _ in range(80): await pilot.pause(0.1) s = app.screen if isinstance(s, ReaderScreen) and s.book is not None and s._last_anchor is not None: await pilot.pause(0.2) return s raise AssertionError("reader did not load") def run(lib, epub, scenario): path = book(epub) async def go(): app = DioraTuiApp(lib) async with app.run_test(size=(100, 30)) as pilot: reader = await open_reader(app, pilot, path) await scenario(app, reader, pilot, epub_mod._book_id(path)) asyncio.run(go()) def painted_with(reader, color_hex): wanted = color_hex.lstrip("#").lower() return any(seg.style and seg.style.bgcolor and seg.style.bgcolor.get_truecolor().hex.lstrip("#").lower() == wanted for strip in reader.book_layout.row_strips for seg in strip) def test_mark_text_then_list_edit_and_delete(world, epub): lib, store = world async def scenario(app, reader, pilot, key): await pilot.press("v") assert reader._sel is not None and reader._sel["phase"] == "start" await pilot.press("l", "l") # two words on await pilot.press("enter") # start assert reader._sel["phase"] == "end" await pilot.press("l", "l", "l") await pilot.press("enter") # end: pick a colour assert isinstance(app.screen, ChoiceScreen) await pilot.press("down", "enter") # Grün await pilot.pause(0.2) assert reader._sel is None hs = store.get(key).highlights assert len(hs) == 1 and hs[0]["color"] == "green" and hs[0]["type"] == "highlight" a = hs[0]["anchor"] assert a["startBlockIndex"] == a["endBlockIndex"] and a["quote"] and a["startChar"] < a["endChar"] assert a["quote"] == reader._marks.maps(a["startBlockIndex"]).raw[a["startChar"]:a["endChar"]] assert painted_with(reader, "#2ecc71") assert store.get(key).dirty["highlights"] await pilot.press("b") bm = store.get(key).bookmarks assert len(bm) == 1 and bm[0]["anchor"].endswith("c0.xhtml") and bm[0]["label"] == "c0" await pilot.press("a") assert isinstance(app.screen, AnnotationsScreen) lv = app.screen.query_one(ListView) assert len(app.screen.rows) == 2 and app.screen.rows[0].kind == "bookmarks" await pilot.press("down", "e") # edit the note of the highlight assert isinstance(app.screen, NoteScreen) app.screen.query_one(Input).value = "klug" await pilot.press("enter") await pilot.pause(0.2) assert store.get(key).highlights[0]["note"] == "klug" await pilot.press("d") # delete the highlight await pilot.pause(0.2) assert store.get(key).highlights == [] and not painted_with(reader, "#2ecc71") await pilot.press("escape") assert isinstance(app.screen, ReaderScreen) run(lib, epub, scenario) def test_note_on_a_word_and_escape_leaves_the_selection(world, epub): lib, store = world async def scenario(app, reader, pilot, key): await pilot.press("v", "l") await pilot.press("escape") assert reader._sel is None and isinstance(app.screen, ReaderScreen) assert store.get(key).highlights == [] await pilot.press("v", "l", "n") # n while marking: a freeform note on this word assert isinstance(app.screen, NoteScreen) app.screen.query_one(Input).value = "merken" await pilot.press("enter") await pilot.pause(0.2) h = store.get(key).highlights assert len(h) == 1 and h[0]["type"] == "note" and h[0]["note"] == "merken" and h[0]["color"] is None a = h[0]["anchor"] assert reader._marks.maps(a["startBlockIndex"]).raw[a["startChar"]:a["endChar"]] == a["quote"] run(lib, epub, scenario) def test_jump_from_the_list_is_not_reading(world, epub): lib, store = world async def scenario(app, reader, pilot, key): store.add(key, "bookmarks", annotations.new_bookmark("c0", "OEBPS/c0.xhtml", 0.5)) await pilot.press("a", "enter") await pilot.pause(0.3) assert isinstance(app.screen, ReaderScreen) reader._save_progress() assert progress.default().get(key) is None # nothing written by the jump run(lib, epub, scenario)