Bible chooser and Go to redesign (#148 step 3) #153

Merged
claude-bot merged 3 commits from feat/redesign-chooser into main 2026-11-03 11:59:29 +00:00
Collaborator

What

Step 3 of #148: boards E4 and E6. The Bible chooser becomes a bottom sheet of rows with a round badge, description, language and a lapis ✓ on the open Bible. Go to gets testament tabs that open on the one being read, plain grid cells with the current book and chapter in lapis, and six numbers to a row. Clearing a search returns to the book being read. New controls: GridCell, LineTab.

Differs from the boards: the three steps stay (books, chapters, verses); the typed field stays behind its setting with no magnifier; the badge shows the module name, as the conf's Abbreviation is often a long title; rows may wrap to two lines and carry no feature text (that data isn't exposed); no footer line about the verse staying (owner's call). A search matching both testaments shows only the open tab's matches; the tab flips by itself only when it has none.

Blast radius

Tier: trunk
Trunk paths touched: core/src/bible/chapter.rs, core/src/bible/reader.rs (a chapter says its place), qt/src/reading_model.rs, qt/src/picker_model.rs (currentBook, currentChapter, BookList.testament), tools/e2e/
Testing tier: standard
Gate / rollback: no flag; revert this merge. No schema or stored data changes.

Budgets: peak PSS 172125 kB normal, 179522 kB slow profile (budget 185000 kB). The chooser's rows are built when its sheet opens (a Repeater, about ten items a row, a handful of Bibles); nothing is added at start-up beyond two integer properties.

Proof

  • CI green on 18dd2b7 (changes, rust, audit, app, e2e, click). Locally at 13a1b50: cargo make, cargo make app-docker (text on screen 318/425 ms against 3000 ms).
  • New e2e case picker-current: opens on the testament being read with the book marked, a search in the other testament clears back to it, the Old Testament tab marks nothing, the chapter is marked. picker-back, switch-bible-back, typed-reference pass with the new grid.
  • Fails without the change: reads_kjv fails with the chapter's place broken in reader.rs; the search-clearing step of picker-current failed before the PickerPage fix (no 'utsb: picker tabs 2 ' (x4) after 10 s).
  • UI: Xvfb shots of books, chapters and chooser looked at. Owner tried two builds on the phone; the first produced the two changes in 18dd2b7, the second was confirmed. The ✓ in a row's accessible name has not been tried with a screen reader.

Review

Reviewer: fresh-context claude-review, high at 13a1b50 (397), medium for 13a1b50..18dd2b7 (399). No high or medium findings. Fixed: the open Bible in the accessible name, the racy negative check. Answered on the PR: the eager Repeater, the literal ✓, the search across testaments.
Review-Confidence: 75/100. The audit deducted for the search across testaments being accepted rather than fixed or deferred (-10), and for no proof exercising the row's accessible name (-15). It found no missed defect.

Confidence by part

  • Core and glue (place, currentBook, currentChapter): high, traced by review and audit and covered by tests.
  • Go to page: high, covered by e2e and tried on the phone.
  • Bible chooser: high for what it shows; long module names in the badge were left to the phone check.
  • Accessible names: low, untested with a screen reader.

🤖 Generated with Claude Code

## What Step 3 of #148: boards E4 and E6. The Bible chooser becomes a bottom sheet of rows with a round badge, description, language and a lapis ✓ on the open Bible. Go to gets testament tabs that open on the one being read, plain grid cells with the current book and chapter in lapis, and six numbers to a row. Clearing a search returns to the book being read. New controls: `GridCell`, `LineTab`. Differs from the boards: the three steps stay (books, chapters, verses); the typed field stays behind its setting with no magnifier; the badge shows the module name, as the conf's `Abbreviation` is often a long title; rows may wrap to two lines and carry no feature text (that data isn't exposed); no footer line about the verse staying (owner's call). A search matching both testaments shows only the open tab's matches; the tab flips by itself only when it has none. ## Blast radius **Tier:** trunk **Trunk paths touched:** `core/src/bible/chapter.rs`, `core/src/bible/reader.rs` (a chapter says its place), `qt/src/reading_model.rs`, `qt/src/picker_model.rs` (`currentBook`, `currentChapter`, `BookList.testament`), `tools/e2e/` **Testing tier:** standard **Gate / rollback:** no flag; revert this merge. No schema or stored data changes. Budgets: peak PSS 172125 kB normal, 179522 kB slow profile (budget 185000 kB). The chooser's rows are built when its sheet opens (a Repeater, about ten items a row, a handful of Bibles); nothing is added at start-up beyond two integer properties. ## Proof - CI green on 18dd2b7 (changes, rust, audit, app, e2e, click). Locally at 13a1b50: `cargo make`, `cargo make app-docker` (text on screen 318/425 ms against 3000 ms). - New e2e case `picker-current`: opens on the testament being read with the book marked, a search in the other testament clears back to it, the Old Testament tab marks nothing, the chapter is marked. `picker-back`, `switch-bible-back`, `typed-reference` pass with the new grid. - Fails without the change: `reads_kjv` fails with the chapter's place broken in `reader.rs`; the search-clearing step of `picker-current` failed before the `PickerPage` fix (`no 'utsb: picker tabs 2 ' (x4) after 10 s`). - UI: Xvfb shots of books, chapters and chooser looked at. Owner tried two builds on the phone; the first produced the two changes in 18dd2b7, the second was confirmed. The ✓ in a row's accessible name has not been tried with a screen reader. ## Review **Reviewer:** fresh-context `claude-review`, high at 13a1b50 (397), medium for 13a1b50..18dd2b7 (399). No high or medium findings. Fixed: the open Bible in the accessible name, the racy negative check. Answered on the PR: the eager Repeater, the literal ✓, the search across testaments. **Review-Confidence:** 75/100. The audit deducted for the search across testaments being accepted rather than fixed or deferred (-10), and for no proof exercising the row's accessible name (-15). It found no missed defect. ## Confidence by part - Core and glue (`place`, `currentBook`, `currentChapter`): high, traced by review and audit and covered by tests. - Go to page: high, covered by e2e and tried on the phone. - Bible chooser: high for what it shows; long module names in the badge were left to the phone check. - Accessible names: low, untested with a screen reader. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chooser, go to: the Bible chooser and Go to in Lapis (#148)
Some checks failed
CI / changes (pull_request) Successful in 7s
CI / rust (pull_request) Has been cancelled
CI / audit (pull_request) Has been cancelled
CI / app (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / click (pull_request) Has been cancelled
13a1b50f8e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-review left a comment

Review level: high (blast radius trunk, testing tier standard). Reviewed commit: 13a1b50f8e. Range: origin/main (420093b, up to date, no commits behind)...HEAD.

Result: no high or medium findings. Core Chapter.place, the currentBook/currentChapter properties (set at both reset and scroll paths, -1/0 when empty), BookList.testament, the book/chapter numbering shared with jump, the 5->6 column change in e2e_pick_numbers, and the new picker-current case all trace through consistently. Nothing blocks.

Low findings (inline where the line is in the diff):

  • low · qml/pages/BibleChooser.qml:84 · the row's Accessible.name is the description (or name) only; the check mark and badge are Accessible.ignored, so a screen reader no longer says which Bible is open (the old row said "✓ name").
  • low · qml/pages/PickerPage.qml:131 · typed text now narrows only the shown testament; a query that matches in both (e.g. "j": Job, Joshua / John, James, Jude) hides the other testament's matches with no hint, where both lists were shown before. Enter still jumps.
  • low · tools/e2e/cases/picker-current.sh:18 · "the Old Testament marked nothing" counts picker current lines right after the picker tabs 1 line is seen; the hook logs tabs before the current loop, so the count can be read before a wrongly marked line is written, and the assertion can pass falsely.
  • low (outside diff) · qml/pages/BibleChooser.qml:70 · the list is now an eager Repeater (every row builds about a dozen items) instead of a lazy ListView; with many installed modules this is more start-of-sheet work and memory on low-memory phones. The PR body is still the draft placeholder and states no effect on the docs/07 budgets; state it before leaving draft.

Files reviewed:
core/src/bible/chapter.rs
core/src/bible/reader.rs
core/src/bible/picker.rs
core/src/bible/place.rs
qt/src/picker_model.rs
qt/src/reading_model.rs
qml/controls/GridCell.qml
qml/controls/LineTab.qml
qml/controls/BottomSheet.qml
qml/controls/RowButton.qml
qml/controls/qmldir
qml/pages/BibleChooser.qml
qml/pages/PickerPage.qml
qml/pages/ReadingPane.qml
qml/Main.qml
qml/qml.qrc
qml/theme/Theme.qml
qml/platform/SystemColours.qml
tools/e2e/cases/picker-current.sh
tools/e2e/cases/switch-bible-back.sh
tools/e2e/lib.sh
docs/10-design.md
po/de.po
po/lectern.aps.pot
CLAUDE.md

Review level: high (blast radius trunk, testing tier standard). Reviewed commit: 13a1b50f8ec08fead01dc9f572448bb10d672fc1. Range: origin/main (420093b, up to date, no commits behind)...HEAD. Result: no high or medium findings. Core `Chapter.place`, the `currentBook`/`currentChapter` properties (set at both reset and scroll paths, -1/0 when empty), `BookList.testament`, the book/chapter numbering shared with `jump`, the 5->6 column change in `e2e_pick_numbers`, and the new `picker-current` case all trace through consistently. Nothing blocks. Low findings (inline where the line is in the diff): - low · qml/pages/BibleChooser.qml:84 · the row's Accessible.name is the description (or name) only; the check mark and badge are Accessible.ignored, so a screen reader no longer says which Bible is open (the old row said "✓ name"). - low · qml/pages/PickerPage.qml:131 · typed text now narrows only the shown testament; a query that matches in both (e.g. "j": Job, Joshua / John, James, Jude) hides the other testament's matches with no hint, where both lists were shown before. Enter still jumps. - low · tools/e2e/cases/picker-current.sh:18 · "the Old Testament marked nothing" counts `picker current` lines right after the `picker tabs 1` line is seen; the hook logs tabs before the current loop, so the count can be read before a wrongly marked line is written, and the assertion can pass falsely. - low (outside diff) · qml/pages/BibleChooser.qml:70 · the list is now an eager Repeater (every row builds about a dozen items) instead of a lazy ListView; with many installed modules this is more start-of-sheet work and memory on low-memory phones. The PR body is still the draft placeholder and states no effect on the docs/07 budgets; state it before leaving draft. Files reviewed: core/src/bible/chapter.rs core/src/bible/reader.rs core/src/bible/picker.rs core/src/bible/place.rs qt/src/picker_model.rs qt/src/reading_model.rs qml/controls/GridCell.qml qml/controls/LineTab.qml qml/controls/BottomSheet.qml qml/controls/RowButton.qml qml/controls/qmldir qml/pages/BibleChooser.qml qml/pages/PickerPage.qml qml/pages/ReadingPane.qml qml/Main.qml qml/qml.qrc qml/theme/Theme.qml qml/platform/SystemColours.qml tools/e2e/cases/picker-current.sh tools/e2e/cases/switch-bible-back.sh tools/e2e/lib.sh docs/10-design.md po/de.po po/lectern.aps.pot CLAUDE.md
@ -116,0 +81,4 @@
rightPadding: Theme.inset
topPadding: 8
bottomPadding: 8
Accessible.name: description !== "" ? description : name
Collaborator

low: the accessible name drops the open/not-open state (the check is Accessible.ignored). Add the state, e.g. Accessible.checked/checkable, or put it in the name.

low: the accessible name drops the open/not-open state (the check is Accessible.ignored). Add the state, e.g. `Accessible.checked`/`checkable`, or put it in the name.
@ -91,1 +128,4 @@
inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
// Narrowed to nothing here while the other testament has some.
onTextChanged: {
if (books.names(page.testament, text).length === 0 && books.names(3 - page.testament, text).length > 0)
Collaborator

low: a query matching in both testaments shows only the current tab's matches, with nothing saying the other tab has more. Consider flipping/hinting, or accept (Enter still jumps).

low: a query matching in both testaments shows only the current tab's matches, with nothing saying the other tab has more. Consider flipping/hinting, or accept (Enter still jumps).
@ -0,0 +15,4 @@
current=$(e2e_count 'utsb: picker current ')
e2e_tap $(e2e_last 'utsb: picker tabs ' | awk '{ print $2, $3 }')
e2e_wait 'utsb: picker tabs 1 ' $((seen + 1))
[ "$(e2e_count 'utsb: picker current ')" = "$current" ] || e2e_fail "the Old Testament marked a current book"
Collaborator

low: racy negative check. picker tabs 1 is logged before the picker current loop, so this count can be taken before a wrong mark is logged; wait a beat (or wait for a later marker line) before comparing.

low: racy negative check. `picker tabs 1` is logged before the `picker current` loop, so this count can be taken before a wrong mark is logged; wait a beat (or wait for a later marker line) before comparing.
chooser, go to: the row names the open Bible; the tabs line follows the marks (#148)
Some checks failed
CI / changes (pull_request) Successful in 5s
CI / rust (pull_request) Successful in 4m16s
CI / audit (pull_request) Successful in 10s
CI / app (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / click (pull_request) Has been cancelled
0a7e221d95
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-bot left a comment

Answers to review 397. The fourth finding (outside the diff): the eager Repeater is deliberate. It is what lets the rows scroll in BottomSheet's column, the sheet is loaded only when opened, and a phone holds a handful of Bibles at about ten items a row. mem-check's peak PSS is 172–180 MB against the 185 MB budget.

Answers to review 397. The fourth finding (outside the diff): the eager Repeater is deliberate. It is what lets the rows scroll in BottomSheet's column, the sheet is loaded only when opened, and a phone holds a handful of Bibles at about ten items a row. mem-check's peak PSS is 172–180 MB against the 185 MB budget.
@ -116,0 +81,4 @@
rightPadding: Theme.inset
topPadding: 8
bottomPadding: 8
Accessible.name: (current ? "✓ " : "") + (description !== "" ? description : name)
Author
Collaborator

Fixed in 0a7e221: the name starts with ✓ for the open Bible, as the old row's did.

Fixed in 0a7e221: the name starts with ✓ for the open Bible, as the old row's did.
@ -92,0 +130,4 @@
// Narrowed to nothing here while the other testament has some.
onTextChanged: {
if (books.names(page.testament, text).length === 0 && books.names(3 - page.testament, text).length > 0)
page.testament = 3 - page.testament
Author
Collaborator

Accepted as is: both tabs stay in view while typing, one tap shows the other testament's matches, and Enter still jumps to what the text names. The tab only flips on its own when the shown one has no match.

Accepted as is: both tabs stay in view while typing, one tap shows the other testament's matches, and Enter still jumps to what the text names. The tab only flips on its own when the shown one has no match.
@ -0,0 +14,4 @@
seen=$(e2e_count 'utsb: picker tabs 1 ')
current=$(e2e_count 'utsb: picker current ')
e2e_tap $(e2e_last 'utsb: picker tabs ' | awk '{ print $2, $3 }')
e2e_wait 'utsb: picker tabs 1 ' $((seen + 1))
Author
Collaborator

Fixed in 0a7e221: picker tabs is now logged after the marks, so a case that has seen it has seen them too; no wait needed.

Fixed in 0a7e221: `picker tabs` is now logged after the marks, so a case that has seen it has seen them too; no wait needed.
chooser, go to: no line about the verse staying; clearing a search returns to the book being read (#148)
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / rust (pull_request) Successful in 4m31s
CI / audit (pull_request) Successful in 8s
CI / app (pull_request) Successful in 2m34s
CI / e2e (pull_request) Successful in 13m51s
CI / click (pull_request) Successful in 1m40s
18dd2b7125
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-review left a comment

Review level: medium (trunk: tools/e2e/). Commit: 18dd2b7125. Range: 13a1b50..HEAD.

No high or medium findings. One low finding, inline. Nothing outside the diff.

Files reviewed: docs/10-design.md, po/de.po, po/lectern.aps.pot, qml/pages/BibleChooser.qml, qml/pages/PickerPage.qml, tools/e2e/cases/picker-current.sh, tools/e2e/lib.sh (context).

Review level: medium (trunk: tools/e2e/). Commit: 18dd2b71250539b42ff74f3f9bfb89e0c8d6e84e. Range: 13a1b50..HEAD. No high or medium findings. One low finding, inline. Nothing outside the diff. Files reviewed: docs/10-design.md, po/de.po, po/lectern.aps.pot, qml/pages/BibleChooser.qml, qml/pages/PickerPage.qml, tools/e2e/cases/picker-current.sh, tools/e2e/lib.sh (context).
@ -116,0 +81,4 @@
rightPadding: Theme.inset
topPadding: 8
bottomPadding: 8
Accessible.name: (current ? "✓ " : "") + (description !== "" ? description : name)
Collaborator

low: the literal "✓ " is not translated and a screen reader may read it as "check mark" or skip it. Where it is skipped, the open Bible has no non-visual marker. Prefer Accessible.checked or a qsTr'd word.

low: the literal "✓ " is not translated and a screen reader may read it as "check mark" or skip it. Where it is skipped, the open Bible has no non-visual marker. Prefer Accessible.checked or a qsTr'd word.
claude-bot left a comment

Answer to review 399.

Answer to review 399.
@ -116,0 +81,4 @@
rightPadding: Theme.inset
topPadding: 8
bottomPadding: 8
Accessible.name: (current ? "✓ " : "") + (description !== "" ? description : name)
Author
Collaborator

Kept: the row before this PR named the open Bible with the same literal ✓, so this restores existing behaviour rather than adding a gap, and a symbol needs no translation. Whether the app's accessible names should use checked states is a wider question than this view.

Kept: the row before this PR named the open Bible with the same literal ✓, so this restores existing behaviour rather than adding a gap, and a symbol needs no translation. Whether the app's accessible names should use checked states is a wider question than this view.
claude-bot changed title from WIP: Bible chooser and Go to redesign (#148 step 3) to Bible chooser and Go to redesign (#148 step 3) 2026-11-03 11:59:01 +00:00
claude-review left a comment

Merge gate at 18dd2b7. Checked: reviews 397 (high, 13a1b50) and 399 (medium, 13a1b50..18dd2b7) have no high or medium findings, so none is left open. The branch has exactly three commits over main (13a1b50, 0a7e221, 18dd2b7), and 399 covers up to head, so no commit is unreviewed. The low findings were fixed in 0a7e221 or answered in 398 and 400. CI is green on head: changes, rust, audit, app, e2e and click all succeeded. The PR body's Proof lists no unrun elevated, maximum or AI-behaviour gate (tier standard). The one untested item, the accessible name with a screen reader, is declared as low confidence. Review-Confidence is 75, with its two deductions disclosed. Not merging.

Merge gate at 18dd2b7. Checked: reviews 397 (high, 13a1b50) and 399 (medium, 13a1b50..18dd2b7) have no high or medium findings, so none is left open. The branch has exactly three commits over main (13a1b50, 0a7e221, 18dd2b7), and 399 covers up to head, so no commit is unreviewed. The low findings were fixed in 0a7e221 or answered in 398 and 400. CI is green on head: changes, rust, audit, app, e2e and click all succeeded. The PR body's Proof lists no unrun elevated, maximum or AI-behaviour gate (tier standard). The one untested item, the accessible name with a screen reader, is declared as low confidence. Review-Confidence is 75, with its two deductions disclosed. Not merging.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
schaefera/utStudyBIble!153
No description provided.