~repos /only-bible-app
git clone https://pyrossh.dev/repos/only-bible-app.git
The only bible app you will ever need. No ads. No in-app purchases. No distractions.
469b205a
—
pyrossh 2 years ago
improve state
- bible_app/lib/components/book_selector.dart +36 -12
- bible_app/lib/components/books_list.dart +11 -16
- bible_app/lib/components/chapters_list.dart +8 -14
- bible_app/lib/components/header.dart +2 -0
- bible_app/lib/components/play_button.dart +1 -0
- bible_app/lib/components/side_menu_page.dart +1 -1
- bible_app/lib/main.dart +1 -3
- bible_app/lib/models/book.dart +7 -0
- bible_app/lib/state.dart +0 -15
- bible_app/lib/utils/string.dart +0 -9
bible_app/lib/components/book_selector.dart
CHANGED
|
@@ -1,35 +1,59 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
-
import "package:flutter_reactive_value/flutter_reactive_value.dart";
|
|
3
|
-
import '
|
|
2
|
+
import 'package:go_router/go_router.dart';
|
|
4
|
-
import '../state.dart';
|
|
5
3
|
import 'books_list.dart';
|
|
6
4
|
import 'chapters_list.dart';
|
|
5
|
+
import '../state.dart';
|
|
7
6
|
|
|
8
|
-
// TODO: use local state for tab instead of global
|
|
9
|
-
|
|
10
|
-
class BookSelector extends
|
|
7
|
+
class BookSelector extends StatefulWidget {
|
|
11
8
|
const BookSelector({super.key});
|
|
12
9
|
|
|
10
|
+
@override
|
|
11
|
+
State<StatefulWidget> createState() => BookSelectorState();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class BookSelectorState extends State<BookSelector> {
|
|
15
|
+
int tab = 0;
|
|
16
|
+
int bookIndex = 0;
|
|
17
|
+
|
|
18
|
+
@override
|
|
19
|
+
void initState() {
|
|
20
|
+
super.initState();
|
|
21
|
+
tab = 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
onBookSelected(int index) {
|
|
25
|
+
setState(() {
|
|
26
|
+
bookIndex = index;
|
|
27
|
+
tab = 1;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onChapterSelected(int index) {
|
|
32
|
+
saveBookIndex(bookIndex, index);
|
|
33
|
+
context.push("/${selectedBible.value[bookIndex].name}/$index");
|
|
34
|
+
context.pop();
|
|
35
|
+
}
|
|
36
|
+
|
|
13
37
|
@override
|
|
14
38
|
Widget build(BuildContext context) {
|
|
15
|
-
final tab = tabIndex.reactiveValue(context);
|
|
16
39
|
if (tab == 1) {
|
|
40
|
+
final book = selectedBible.value[bookIndex];
|
|
17
41
|
return Container(
|
|
18
42
|
margin: const EdgeInsets.only(top: 15, left: 20),
|
|
19
|
-
child:
|
|
43
|
+
child: ChaptersList(title: book.name, length: book.chapters.length, onTap: onChapterSelected),
|
|
20
44
|
);
|
|
21
45
|
}
|
|
22
|
-
final oldTestament = selectedBible.value.where((it) => it.isOldTestament()).
|
|
46
|
+
final oldTestament = selectedBible.value.where((it) => it.isOldTestament()).toList();
|
|
23
|
-
final newTestament = selectedBible.value.where((it) => it.isNewTestament()).
|
|
47
|
+
final newTestament = selectedBible.value.where((it) => it.isNewTestament()).toList();
|
|
24
48
|
return Container(
|
|
25
49
|
margin: const EdgeInsets.only(top: 15, left: 20),
|
|
26
50
|
child: ListView(
|
|
27
51
|
children: [
|
|
28
|
-
BooksList(title: "Old Testament",
|
|
52
|
+
BooksList(title: "Old Testament", books: oldTestament, onTap: onBookSelected),
|
|
29
53
|
Container(
|
|
30
54
|
margin: const EdgeInsets.only(bottom: 10),
|
|
31
55
|
),
|
|
32
|
-
BooksList(title: "New Testament",
|
|
56
|
+
BooksList(title: "New Testament", books: newTestament, onTap: onBookSelected),
|
|
33
57
|
],
|
|
34
58
|
),
|
|
35
59
|
);
|
bible_app/lib/components/books_list.dart
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
-
import "../utils/string.dart";
|
|
3
|
-
import "../state.dart";
|
|
4
2
|
import "tile.dart";
|
|
3
|
+
import "../models/book.dart";
|
|
5
4
|
|
|
6
5
|
class BooksList extends StatelessWidget {
|
|
7
6
|
final String title;
|
|
8
|
-
final int offset;
|
|
9
|
-
final List<
|
|
7
|
+
final List<Book> books;
|
|
8
|
+
final Function(int) onTap;
|
|
10
9
|
|
|
11
|
-
const BooksList({super.key, required this.title, required this.
|
|
10
|
+
const BooksList({super.key, required this.title, required this.books, required this.onTap});
|
|
12
11
|
|
|
13
12
|
@override
|
|
14
13
|
Widget build(BuildContext context) {
|
|
@@ -17,24 +16,20 @@ class BooksList extends StatelessWidget {
|
|
|
17
16
|
children: [
|
|
18
17
|
Container(
|
|
19
18
|
margin: const EdgeInsets.only(bottom: 20),
|
|
20
|
-
child: Text(title, style: Theme
|
|
21
|
-
|
|
19
|
+
child: Text(
|
|
22
|
-
|
|
20
|
+
title,
|
|
23
|
-
|
|
21
|
+
style: Theme.of(context).textTheme.headlineMedium,
|
|
24
22
|
),
|
|
25
23
|
),
|
|
26
24
|
Wrap(
|
|
27
|
-
children: List.
|
|
25
|
+
children: List.of(books.map((book) {
|
|
28
|
-
final name =
|
|
26
|
+
final name = book.shortName();
|
|
29
27
|
return InkWell(
|
|
30
28
|
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
|
31
|
-
onTap: () {
|
|
32
|
-
|
|
29
|
+
onTap: () => onTap(book.index),
|
|
33
|
-
tabIndex.value = 1;
|
|
34
|
-
},
|
|
35
30
|
child: Tile(name: name),
|
|
36
31
|
);
|
|
37
|
-
}),
|
|
32
|
+
})),
|
|
38
33
|
),
|
|
39
34
|
],
|
|
40
35
|
);
|
bible_app/lib/components/chapters_list.dart
CHANGED
|
@@ -1,32 +1,26 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
-
import 'package:flutter_reactive_value/flutter_reactive_value.dart';
|
|
3
|
-
import 'package:go_router/go_router.dart';
|
|
4
|
-
import '../state.dart';
|
|
5
2
|
import 'tile.dart';
|
|
6
3
|
|
|
7
4
|
class ChaptersList extends StatelessWidget {
|
|
5
|
+
final String title;
|
|
6
|
+
final int length;
|
|
8
|
-
|
|
7
|
+
final Function(int) onTap;
|
|
8
|
+
|
|
9
|
+
const ChaptersList({super.key, required this.title, required this.length, required this.onTap});
|
|
9
10
|
|
|
10
11
|
@override
|
|
11
12
|
Widget build(BuildContext context) {
|
|
12
|
-
final bookIndex = tabBookIndex.reactiveValue(context);
|
|
13
|
-
final book = selectedBible.value[bookIndex];
|
|
14
13
|
return ListView(
|
|
15
14
|
children: [
|
|
16
15
|
Container(
|
|
17
16
|
margin: const EdgeInsets.only(bottom: 20),
|
|
18
|
-
child: Text(
|
|
17
|
+
child: Text(title, style: Theme.of(context).textTheme.headlineMedium),
|
|
19
18
|
),
|
|
20
19
|
Wrap(
|
|
21
|
-
children: List.generate(
|
|
20
|
+
children: List.generate(length, (index) {
|
|
22
21
|
return InkWell(
|
|
23
22
|
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
|
24
|
-
onTap: () {
|
|
25
|
-
|
|
23
|
+
onTap: () => onTap(index),
|
|
26
|
-
context.push("/${book.name}/$index");
|
|
27
|
-
context.pop();
|
|
28
|
-
resetTab();
|
|
29
|
-
},
|
|
30
24
|
child: Tile(name: "${index + 1}"),
|
|
31
25
|
);
|
|
32
26
|
}),
|
bible_app/lib/components/header.dart
CHANGED
|
@@ -2,6 +2,7 @@ import "dart:math";
|
|
|
2
2
|
import "package:flutter/material.dart";
|
|
3
3
|
import "./play_button.dart";
|
|
4
4
|
import "./side_menu_page.dart";
|
|
5
|
+
import "./menu.dart";
|
|
5
6
|
import '../models/book.dart';
|
|
6
7
|
import "../state.dart";
|
|
7
8
|
|
|
@@ -45,6 +46,7 @@ class Header extends StatelessWidget {
|
|
|
45
46
|
),
|
|
46
47
|
const Spacer(flex: 1),
|
|
47
48
|
PlayButton(book: book, chapter: chapter, verses: verses),
|
|
49
|
+
Menu(),
|
|
48
50
|
// const Spacer(flex: 1),
|
|
49
51
|
],
|
|
50
52
|
),
|
bible_app/lib/components/play_button.dart
CHANGED
|
@@ -16,6 +16,7 @@ class PlayButton extends StatelessWidget {
|
|
|
16
16
|
Widget build(BuildContext context) {
|
|
17
17
|
final icon = isPlaying.reactiveValue(context) ? Icons.pause_circle_filled : Icons.play_circle_fill;
|
|
18
18
|
return IconButton(
|
|
19
|
+
padding: EdgeInsets.symmetric(horizontal: 50),
|
|
19
20
|
icon: Icon(icon, size: 36),
|
|
20
21
|
onPressed: () async {
|
|
21
22
|
final player = AudioPlayer();
|
bible_app/lib/components/side_menu_page.dart
CHANGED
|
@@ -35,7 +35,7 @@ class SideMenuPage extends ModalRoute<void> {
|
|
|
35
35
|
child: Container(
|
|
36
36
|
color: Colors.white,
|
|
37
37
|
margin: EdgeInsets.only(left: 0, right: isDesktop() ? 650 : 0),
|
|
38
|
-
child: BookSelector(),
|
|
38
|
+
child: const BookSelector(),
|
|
39
39
|
),
|
|
40
40
|
);
|
|
41
41
|
}
|
bible_app/lib/main.dart
CHANGED
|
@@ -12,11 +12,9 @@ void main() async {
|
|
|
12
12
|
await initPersistentValueNotifier();
|
|
13
13
|
await loadBible();
|
|
14
14
|
runApp(MaterialApp.router(
|
|
15
|
-
debugShowCheckedModeBanner: false,
|
|
16
15
|
routerConfig: GoRouter(
|
|
17
|
-
navigatorKey: GlobalKey<NavigatorState>(),
|
|
18
|
-
initialLocation: "/${selectedBible.value[bookIndex.value].name}/${chapterIndex.value}",
|
|
19
16
|
debugLogDiagnostics: true,
|
|
17
|
+
initialLocation: "/${selectedBible.value[bookIndex.value].name}/${chapterIndex.value}",
|
|
20
18
|
routes: [
|
|
21
19
|
Shell(
|
|
22
20
|
routes: [
|
bible_app/lib/models/book.dart
CHANGED
|
@@ -9,6 +9,13 @@ class Book {
|
|
|
9
9
|
bool isOldTestament() => index < 39;
|
|
10
10
|
|
|
11
11
|
bool isNewTestament() => index >= 39;
|
|
12
|
+
|
|
13
|
+
String shortName() {
|
|
14
|
+
if (name[0] == "1" || name[0] == "2" || name[0] == "3") {
|
|
15
|
+
return "${name[0]}${name[2].toUpperCase()}${name.substring(3, 4).toLowerCase()}";
|
|
16
|
+
}
|
|
17
|
+
return "${name[0].toUpperCase()}${name.substring(1, 3).toLowerCase()}";
|
|
18
|
+
}
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
class Chapter {
|
bible_app/lib/state.dart
CHANGED
|
@@ -2,7 +2,6 @@ import 'dart:convert';
|
|
|
2
2
|
import 'dart:io' show GZipCodec, Platform;
|
|
3
3
|
import 'package:flutter/services.dart';
|
|
4
4
|
import 'package:flutter/material.dart';
|
|
5
|
-
import 'package:flutter/scheduler.dart';
|
|
6
5
|
import 'package:flutter_persistent_value_notifier/flutter_persistent_value_notifier.dart';
|
|
7
6
|
import 'package:flutter_reactive_value/flutter_reactive_value.dart';
|
|
8
7
|
import 'models/book.dart';
|
|
@@ -95,20 +94,6 @@ onVerseSelected(int i) {
|
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
final tabIndex = ValueNotifier(0);
|
|
99
|
-
final tabBookIndex = ValueNotifier(0);
|
|
100
|
-
|
|
101
|
-
onTabBookChange(int i) {
|
|
102
|
-
tabBookIndex.value = i;
|
|
103
|
-
tabIndex.value = 1;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
resetTab() {
|
|
107
|
-
SchedulerBinding.instance.addPostFrameCallback((_) {
|
|
108
|
-
tabIndex.value = 0;
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
97
|
bool isDesktop() {
|
|
113
98
|
return Platform.isMacOS || Platform.isLinux || Platform.isWindows;
|
|
114
99
|
}
|
bible_app/lib/utils/string.dart
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
extension StringExtension on String {
|
|
2
|
-
String bookShortName() {
|
|
3
|
-
// final name = replaceAll(" ", "").substring(0, 3);
|
|
4
|
-
if (this[0] == "1" || this[0] == "2" || this[0] == "3") {
|
|
5
|
-
return "${this[0]}${this[2].toUpperCase()}${substring(3, 4).toLowerCase()}";
|
|
6
|
-
}
|
|
7
|
-
return "${this[0].toUpperCase()}${substring(1, 3).toLowerCase()}";
|
|
8
|
-
}
|
|
9
|
-
}
|