~repos /only-bible-app
GIT_CONFIG_PARAMETERS="'http.version=HTTP/1.1'" git clone
https://git.pyrossh.dev/only-bible-app.git
Discussions:
https://groups.google.com/g/rust-embed-devs
The only bible app you will ever need. No ads. No in-app purchases. No distractions.
lib/widgets/book_select_sheet.dart
import "package:flutter/material.dart";import "package:only_bible_app/gen/bible.gen.dart";import "package:only_bible_app/store/app_state.dart";import "package:only_bible_app/utils.dart";import "package:only_bible_app/widgets/book_tile.dart";
class BookSelectSheet extends StatefulWidget { final Bible bible; final BuildContext parentContext; final void Function(int bookIndex, int chapterIndex) onChapterSelected; final Book? initialBook;
const BookSelectSheet({ super.key, required this.bible, required this.parentContext, required this.onChapterSelected, this.initialBook, });
@override State<BookSelectSheet> createState() => _BookSelectSheetState();}
class _BookSelectSheetState extends State<BookSelectSheet> { late bool showOldTestament; late PageController _pageController; Book? _selectedBook;
@override void initState() { super.initState(); final currentBook = widget.parentContext.read().savedBook; showOldTestament = currentBook < 39; _selectedBook = widget.initialBook; _pageController = PageController(initialPage: _selectedBook != null ? 1 : 0); }
@override void dispose() { _pageController.dispose(); super.dispose(); }
void _onBookTapped(Book book) { if (book.chapters!.length == 1) { widget.onChapterSelected(book.index, 0); return; } setState(() => _selectedBook = book); _pageController.animateToPage( 1, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); }
void _onBackToBooks() { _pageController.animateToPage( 0, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); }
@override Widget build(BuildContext context) { final currentBook = widget.parentContext.read().savedBook; final currentChapter = widget.parentContext.read().savedChapter;
return PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), children: [ // Page 0: Book selection Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ ToggleButtons( onPressed: (int index) { setState(() { showOldTestament = index == 0; }); }, textStyle: Theme.of(context).textTheme.labelLarge, isSelected: [showOldTestament, !showOldTestament], children: [ Text(widget.bible.oldTestamentTitle!), Text(widget.bible.newTestamentTitle!), ], ), const SizedBox(height: 12), Expanded( child: GridView.count( crossAxisCount: 6, crossAxisSpacing: 6, mainAxisSpacing: 6, children: (showOldTestament ? widget.bible.getOldBooks() : widget.bible.getNewBooks()) .map((book) => BookTile( label: book.shortName(book.name!), isSelected: currentBook == book.index, onTap: () => _onBookTapped(book))) .toList(), ), ), ], ), ), // Page 1: Chapter selection Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ Row( children: [ IconButton( icon: const Icon(Icons.arrow_back), onPressed: _onBackToBooks, ), Text( _selectedBook?.name ?? "", style: Theme.of(context).textTheme.headlineMedium, ), ], ), const SizedBox(height: 12), Expanded( child: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 6, crossAxisSpacing: 6, mainAxisSpacing: 6, ), itemCount: _selectedBook?.chapters?.length ?? 0, itemBuilder: (_, index) { final isSelected = currentBook == _selectedBook?.index && currentChapter == index; return BookTile( label: "${index + 1}", isSelected: isSelected, onTap: () => widget.onChapterSelected(_selectedBook!.index, index), ); }, ), ), ], ), ), ], ); }}