This repository contains a Flutter Bible app that serves two roles:
- It is a simple Bible-reading app.
- It is also a learning project that the maintainer is using to build toward a future, larger Bible app.
README.md is the public-facing roadmap and feature checklist. This file is the engineering context document for future coding agents and maintainers who need to understand the current codebase quickly.
Use TODO_STATUS.md beside this file as the execution tracker:
- record what was completed
- record what is in progress
- record the next recommended engineering step
- add a reminder whenever
README.mdshould be updated to match repo reality
- The core implemented feature is Bible reading.
- Bible content is bundled in
assets/bible/and can also be fetched from GitHub-defined translation URLs. - The app has translation selection for Bible data with
kjv,asv, andwebcurrently defined in code. - UI scaffolding exists for authentication, settings, themes, language selection, and menu-driven feature areas.
- Personal notes/highlights now exist as a separate user-data feature with a reader selection bar, note editor, and Notes screen.
- Several non-reader features are still placeholders, "coming soon" destinations, or partially scaffolded.
- Localization support exists in code/assets for English, French, Spanish, German, and Chinese.
- The app now follows a pragmatic MVVM-style feature layout on top of Riverpod.
- Use this mental model when adding or moving code:
models/= durable domain objects and DTO-style data structuresdata/= repositories and persistence/integration codeapplication/view_models/= Riverpod state, UI-facing orchestration, and screen/session statepresentation/= widgets, screens, layout, and interaction rendering
- This is intentionally an incremental MVVM setup, not a framework-heavy rewrite.
- Riverpod remains the state tool.
- Repositories remain the data boundary.
- Widgets still own local ephemeral UI state when it is truly view-only.
lib/main.dartinitializes Flutter bindings, sets up database factory behavior for web and desktop, configures desktop window sizing, and launches the app inside aProviderScope.- Platform-only runtime work now goes through helper files under
lib/src/platform/and platform-specific database executor helpers underlib/src/services/so web builds do not pull nativedart:io/ FFI code into the browser target.
lib/src/app.dartis the main app entry inside Flutter.- It wires Riverpod state into:
GoRouterauth-aware navigation- theme selection
- locale selection
- Current registered routes are:
//login/home/home/other/home/settings
lib/src/views/home/home_screen.dartis the main authenticated shell.- It provides a responsive layout:
- bottom navigation on smaller screens
NavigationRailon wider screens
- The three primary tabs are:
- Home
- Bible
- Menu
- The Bible tab also owns the app-bar actions for search/audio placeholders, translation selection, and Bible text size selection.
- The reader presentation layer now uses a coordinator-plus-parts layout instead of keeping the full screen implementation in one giant file.
- The reader presentation layer is now organized into subfolders by responsibility:
lib/src/features/reader/presentation/reader_view/lib/src/features/reader/presentation/reference_picker/
- Each of those folders now also has a small local
README.mdso maintainers can quickly see file ownership without reconstructing it from imports and part directives. reader_view/bible_viewer_tab.dartis now the coordinating screen/state entry.- Heavy reader responsibilities are split into focused part files under
reader_view/for:- core state and selection behavior
- rendering orchestration
- document-mode rendering
- annotation-sheet / span helpers
- extracted widget sections
- The outer reader shell file was also cleaned up so the chapter-bar behavior and verse-selection actions now route through named methods instead of one large callback-heavy build block.
- The outer reader shell now uses a small snapshot model for watched state so
bible_viewer_tab.dartreads more like screen composition and less like one long provider/spacing calculation block. - Shared verse-card and chapter-support rendering now flow through common helpers in the reader rendering layer instead of maintaining separate near-duplicate implementations for current-chapter and continuous-chapter paths.
- The reference-picker UI lives under
reference_picker/so:reference_picker/chapter_bar.dartowns the chapter barreference_picker/reference_picker_screen.dartowns the main picker screenreference_picker/reference_screen.dartowns the separate references screen
- Desktop/web style verse-range selection now exists only inside the Bible viewer.
Shift+Clickextends selection from a local reader anchor verse, but this behavior is intentionally scoped toreader_view/and should not be copied into reference pickers, editors, or future split-view note/document panes without an explicit product decision. - Source-study metadata in the verse details sheet such as
Strong's, lemma, morphology, and quote-speaker values is controlled by the reader settingShow Source Detailsand is intentionally off by default for cleaner reading.
This split is a structural maintenance improvement, not a feature change. Treat the current priority as regression confidence, not more reader-surface expansion.
- Reader-facing state is now split into explicit ViewModel files under
lib/src/features/reader/application/view_models/. - The main reader ViewModel groups are:
reader_session_view_models.dart- selected translation
- current Bible reference
reader_preferences_view_models.dart- layout mode
- continuous scrolling
- intro/selector visibility preferences
bible_library_view_models.dart- repository provider
- available translations
- shell/full Bible loading
current_chapter_view_model.dart- chapter hydration on demand
- Translation and reference state are persisted with
SharedPreferences. - Session-only remote reads are the exception: when a translation is opened
from the remote catalog without downloading, the current translation is moved
into memory for the current run only and is intentionally not written back to
SharedPreferences. - Bible content loading is exposed through Riverpod state notifiers and
AsyncValue.
lib/src/features/auth/application/view_models/auth_view_model.dartpresentation/login_screen.dart
lib/src/features/home/application/view_models/home_navigation_view_model.dartpresentation/home_screen.dart
lib/src/features/settings/application/view_models/app_launch_preferences_view_models.dartapplication/view_models/reader_display_preferences_view_models.dartpresentation/settings_screen.dartpresentation/advanced_settings_screen.dart
lib/src/features/annotations/models/user_annotations.dartdata/user_annotation_repository.dartapplication/view_models/annotation_data_view_models.dartapplication/view_models/annotation_selection_view_models.dartpresentation/notes_screen.dartpresentation/note_editor_screen.dart
lib/src/features/reader/application/view_models/for reader/session/loading statepresentation/reader_view/for the reading surfacepresentation/reference_picker/for reference selection flows
- If a change affects what the user sees or taps, start in
presentation/. - If a change affects screen state, selection, loading, or UI orchestration, place it in
application/view_models/. - If a change affects storage, parsing, persistence, or integration boundaries, place it in
data/orservices/. - If a type needs to survive across layers, make it a model instead of hiding it inside a widget or repository.
- Avoid adding fresh business logic directly into screens when the same logic could be tested as a ViewModel or repository method.
- Treat the MVVM-style feature layout as the default architecture for all new work.
- Do not recreate old top-level feature provider files under
application/.- Add the real implementation under
application/view_models/. - Import the concrete
view_models/file directly.
- Add the real implementation under
- Do not add repository or persistence logic directly inside widgets or screens.
- Do not add parser/content-source concerns into personal-annotation code paths.
- Before creating a new file, first check whether the code belongs in an existing feature folder under:
models/data/application/view_models/presentation/
- Prefer splitting by responsibility before a file becomes hard to scan.
- File-length rubric:
0-200lines: excellent- Keep doing what you're doing.
200-500lines: acceptable- Monitor for complexity; consider extracting widgets.
500-1000lines: heavy- Refactor immediately. Split logic from UI.
1000+lines: critical- Treat this as a God Object. It is likely difficult to test or maintain safely.
- Split by ownership, not arbitrarily.
- Good splits:
- screen widget vs reusable child widgets
- rendering helpers vs state orchestration
- repository vs mapper/serializer helpers
- session state vs preferences vs derived UI state
- Bad splits:
- one file per tiny helper with no clear ownership
- moving code into random
utilsfiles just to reduce line count
- Good splits:
- If a widget file has multiple major
switchbranches, multiple modal/sheet builders, and multiple long callbacks, that is usually a signal to extract subwidgets or view-model helpers. - If a provider file starts owning unrelated concerns, split it into focused
view_models/files instead of creating another "god provider" file.
- Ask:
- Does this code live in the right layer?
- Would this logic be easier to test outside the widget tree?
- Did this change make an existing file meaningfully harder to re-enter later?
- Should this be a new focused file rather than another section in a large one?
- If the answer is "yes" to the last two questions, split the file before continuing feature work.
lib/src/repositories/app_bible_repository.dartis the main repository for Bible data.- It can:
- load Bible content from bundled assets
- merge bundled translations with a GitHub-hosted remote translation catalog
- download Bible content from GitHub
- open supported remote XML translations in a session-only mode without persisting them locally
- parse Bible files with
bible_parser_flutter - cache parsed data through the app database layer
- Parsing is offloaded with
compute(...)so large Bible files do not block the UI thread. - Persisted remote downloads now prefer catalog
sqliteartifacts when the current platform can install raw SQLite files directly. Session-only reads currently support XML-family artifacts (usfx,osis,zefania) only. - Manual import now explicitly recognizes future
usfm/.zipinputs and returns clear "not connected yet" errors instead of pretending they are XML.
lib/src/services/app_database.dartdefines the Drift-backed storage layer.- It stores parsed Bible data as books, chapters, and verses.
- The repository reads from and writes to this layer for caching-oriented workflows.
- It also stores personal annotations in dedicated user-annotation tables separate from parser-originated footnotes/references.
- The personal annotations feature lives under
lib/src/features/annotations/. - It is intentionally separate from parser-provided footnotes and cross-references.
- The current model supports:
- standalone highlights
- standalone notes
- notes with connected highlight colors
- extra linked verses with saved translation metadata
- The first version is whole-verse only; partial-verse anchors are future work.
- The repository looks for local files using patterns like
assets/bible/$translationId.$ext. - Current bundled files use names such as:
eng-kjv2006_usfx.xmleng-web.usfx.xmlasv_osis.xml
- Because the IDs in code are
kjv,web, andasv, local lookup may miss bundled assets and fall back to download behavior.
- Non-web platforms use a file-backed SQLite path.
- Web Bible loading is intentionally session-memory only: browser builds parse XML into memory for the current session instead of maintaining a durable translation cache that survives reloads.
- Personal annotations on web still depend on the current web database path and should be treated separately from Bible-content loading behavior.
- Most placeholder menu routes still go through
/coming-soon/.... Notesis now a real route and should be treated as a live feature, not a placeholder.- Future navigation work should verify route registration before assuming a destination exists.
- The main app architecture lives under
lib/src/. - There is also older or non-core code in root-level files such as:
lib/TodoModal.dartlib/providerTodo.dartlib/todo_repository.dart
- Treat these as legacy or unrelated unless a task clearly requires them.
- Treat
lib/src/as the primary application code. - Use
README.mdfor roadmap intent, but validate current behavior against the actual code before making changes. - Verify route, provider, and storage assumptions before extending features.
- Keep the app functioning as a simple Bible reader first; add roadmap features in layers rather than assuming the scaffolding is already complete.
- When touching Bible loading or caching, check both the translation ID flow and the real persistence behavior.
- When touching notes/highlights, keep personal annotations separate from parser content at every layer.
- When touching the reader, prefer extending the split presentation files by responsibility instead of growing
bible_viewer_tab.dartback into a giant mixed-responsibility file. - When re-entering the reader after time away, start with the local
README.mdfiles underlib/src/features/reader/presentation/before diving into the implementation files.
Supporting Bible formatting from USFX, OSIS, and Zefania does not mean "just read the XML and save one string per verse."
The safer long-term approach is:
- parse the source file
- convert it into one shared app model
- save plain verse text for search and simple fallback display
- also save structured formatting data for real rendering
That structured data is where features such as these should live:
- footnotes
- cross-references
- red-letter text / words of Jesus
- poetry and quote indentation
- translator-added words
- word-level metadata such as Strong's numbers
In plain terms:
- raw XML is the import format
- normalized local database rows are the app's runtime format
- plain text is for search and simple reading
- structured spans/notes/references are for faithful display
If the app stores only flattened verse text, it loses too much meaning and later formatting features become much harder to build correctly.
The parser can already give you the list of books. In practice, that comes from the parser's books stream, which yields each parsed Bible book one at a time.
What it does not preserve well yet is the non-verse content around those books, such as:
- Bible prefaces
- book introductions
- TOC labels
- canonical titles and headings
- other front matter that appears before normal chapter/verse text
This matters because some real Bible XML files already include that content. For example:
- the WEB USFX file includes a
FRTpreface book and TOC/title data - USFX files include tags such as
handtoc - OSIS files often include
titleand other section/front-matter elements
So the short version is:
- yes, the parser can already produce the list of books
- no, it does not yet treat introductions and front matter as first-class content
If the app should eventually show introductions, then the parser and app model need to keep that content instead of dropping everything that is not a normal verse.
The long-term goal for this project is not just "parse enough to show chapters and verses."
The stronger goal is:
- support as much meaningful content from USFX, OSIS, and Zefania as the app can safely model
- normalize that content into one shared internal representation
- store enough structure locally so future reader and study features do not need the source XML to be reparsed every time
In practical terms, that means the project should eventually support:
- books, chapters, and verses
- introductions and front matter
- section titles and navigation labels
- footnotes and cross-references
- red-letter text
- poetry and quote structure
- translator-added words
- word-level metadata where useful
It does not mean every raw source tag must be exposed directly to the UI. The senior-developer approach is to map source-specific XML into shared app concepts first, then render those shared concepts in the app.
Before adding more parser features, the project should define one shared model that both the parser package and the app can understand.
Phase 1 is not "support every XML feature yet." Phase 1 is:
- define the canonical app/parser model
- keep current plain-text reading working
- make room for richer metadata without redesigning storage again
Create a shared data model that can support:
- plain verse text
- structured inline spans
- footnotes
- cross-references
- introductions and front matter
- section titles / TOC labels
These can come later after the model is stable:
- rendering every style in the UI
- lossless round-trip export of every source tag
- exposing raw XML tags directly to widgets
The current model is too small because it mainly assumes:
BookChapterVerse
Phase 1 should move toward these shared concepts:
BibleDocument- translation-level metadata
- optional Bible-level introduction / preface blocks
- list of parsed books
BibleBook- id
- number
- title
- short title / TOC labels
- optional book introduction blocks
- chapters
BibleChapter- chapter number
- optional structured blocks that belong at chapter level
- verses
BibleVerse- verse number
plainTextspansfootnotesreferences
These names can change, but the concepts should exist.
VerseSpantextkind- optional metadata
Suggested kind values:
-
normal
-
wordsOfJesus
-
translatorAddition
-
quote
-
poetry
-
word
-
Footnote- marker / caller
- optional label
- text or structured content
- optional nested references
-
CrossReference- label text
- normalized target if available
-
DocumentBlock- kind
- text or structured inline content
- optional level / metadata
Suggested DocumentBlock uses:
- preface paragraph
- book introduction paragraph
- heading
- TOC/title label
- poetry block
Do not store only one flattened verse string.
Phase 1 storage should keep:
- plain text for fast search
- structured metadata for richer rendering later
Senior-friendly storage direction:
- keep normalized book/chapter/verse rows
- add JSON columns or related tables for:
- spans
- footnotes
- references
- introduction/front-matter blocks
For this project, JSON-backed columns are acceptable in Phase 1 if they reduce migration complexity. The key requirement is: do not force another full schema redesign before richer reader features can be built.
Implement in this order:
- shared model in
bible_parser_flutter - app-side matching model/storage changes in
basic_bible - USFX support first
- OSIS support second
- Zefania support third
Why this order:
- USFX already has partial notes/reference support and matches local app assets well
- OSIS has important red-letter/title semantics
- Zefania should follow once the canonical model is stable
Phase 1 is complete when:
- parser and app agree on one richer shared model
- plain-text reading still works
- footnotes, references, and introduction/front-matter content can be preserved in parsed output
- storage can retain that richer output locally
- the next parser enhancements can be added without redesigning the model again
Phase 1 means:
- stop thinking "a verse is just one string"
- start thinking "a verse is text plus structured meaning"
- build the data model first
- then teach each parser format how to fill that model
- then render it in the app
- Start with
lib/main.dartandlib/src/app.dartto understand app startup and routing. - Move next to
lib/src/views/home/home_screen.dartto understand the main shell. - For Bible-reader work, inspect:
lib/src/providers/bible_provider.dartlib/src/repositories/app_bible_repository.dartlib/src/services/app_database.dart
- For feature/status questions, prefer repo truth over the README checklist.
- For execution tracking, update
TODO_STATUS.mdin the same commit or task that changes project behavior.