~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.
ae3c7ac5
—
pyrossh 1 month ago
Update navigation
- lib/app.dart +93 -9
- lib/navigation.dart +72 -123
- lib/screens/book_select_screen.dart +55 -42
- lib/screens/chapter_select_screen.dart +39 -18
- lib/widgets/sliver_heading.dart +4 -2
- pubspec.lock +8 -0
- pubspec.yaml +1 -0
lib/app.dart
CHANGED
|
@@ -1,20 +1,111 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
+
import "package:go_router/go_router.dart";
|
|
2
3
|
import "package:only_bible_app/l10n/app_localizations.dart";
|
|
3
4
|
import "package:only_bible_app/screens/bible_select_screen.dart";
|
|
5
|
+
import "package:only_bible_app/screens/book_select_screen.dart";
|
|
6
|
+
import "package:only_bible_app/screens/chapter_select_screen.dart";
|
|
4
7
|
import "package:only_bible_app/screens/chapter_view_screen.dart";
|
|
8
|
+
import "package:only_bible_app/screens/webview_screen.dart";
|
|
5
9
|
import "package:only_bible_app/store/state.dart";
|
|
6
10
|
import "package:only_bible_app/theme.dart";
|
|
7
11
|
import "package:only_bible_app/utils.dart";
|
|
8
12
|
|
|
9
13
|
final globalNavigatorKey = GlobalKey<NavigatorState>();
|
|
10
14
|
|
|
15
|
+
final router = GoRouter(
|
|
16
|
+
navigatorKey: globalNavigatorKey,
|
|
17
|
+
initialLocation: firstOpenAtom.value
|
|
18
|
+
? "/bible"
|
|
19
|
+
: "/chapter/${Uri.encodeComponent(bibleNameAtom.value)}/${savedBookAtom.value}/${savedChapterAtom.value}",
|
|
20
|
+
routes: [
|
|
21
|
+
GoRoute(
|
|
22
|
+
path: "/bible",
|
|
23
|
+
pageBuilder: (context, state) => const NoTransitionPage(
|
|
24
|
+
child: BibleSelectScreen(),
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
GoRoute(
|
|
28
|
+
path: "/chapter/:bibleName/:bookIndex/:chapterIndex",
|
|
29
|
+
pageBuilder: (context, state) {
|
|
30
|
+
final bibleName =
|
|
31
|
+
Uri.decodeComponent(state.pathParameters["bibleName"]!);
|
|
32
|
+
final bookIndex = int.parse(state.pathParameters["bookIndex"]!);
|
|
33
|
+
final chapterIndex = int.parse(state.pathParameters["chapterIndex"]!);
|
|
34
|
+
final slideDir = state.extra as TextDirection?;
|
|
35
|
+
if (slideDir != null) {
|
|
36
|
+
return CustomTransitionPage(
|
|
37
|
+
key: state.pageKey,
|
|
38
|
+
child: ChapterViewScreen(
|
|
39
|
+
bibleName: bibleName,
|
|
40
|
+
bookIndex: bookIndex,
|
|
41
|
+
chapterIndex: chapterIndex,
|
|
42
|
+
),
|
|
43
|
+
transitionsBuilder:
|
|
44
|
+
(context, animation, secondaryAnimation, child) {
|
|
45
|
+
const begin = Offset(1.0, 0.0);
|
|
46
|
+
const end = Offset.zero;
|
|
47
|
+
const curve = Curves.ease;
|
|
48
|
+
final tween =
|
|
49
|
+
Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
|
|
50
|
+
return SlideTransition(
|
|
51
|
+
textDirection: slideDir,
|
|
52
|
+
position: animation.drive(tween),
|
|
53
|
+
child: child,
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return NoTransitionPage(
|
|
59
|
+
key: state.pageKey,
|
|
60
|
+
child: ChapterViewScreen(
|
|
61
|
+
bibleName: bibleName,
|
|
62
|
+
bookIndex: bookIndex,
|
|
63
|
+
chapterIndex: chapterIndex,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
),
|
|
68
|
+
GoRoute(
|
|
69
|
+
path: "/books/:bibleName",
|
|
70
|
+
pageBuilder: (context, state) {
|
|
71
|
+
final bibleName =
|
|
72
|
+
Uri.decodeComponent(state.pathParameters["bibleName"]!);
|
|
73
|
+
return NoTransitionPage(
|
|
74
|
+
child: BookSelectScreen(bibleName: bibleName),
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
),
|
|
78
|
+
GoRoute(
|
|
79
|
+
path: "/chapters/:bibleName/:bookIndex",
|
|
80
|
+
pageBuilder: (context, state) {
|
|
81
|
+
final bibleName =
|
|
82
|
+
Uri.decodeComponent(state.pathParameters["bibleName"]!);
|
|
83
|
+
final bookIndex = int.parse(state.pathParameters["bookIndex"]!);
|
|
84
|
+
return NoTransitionPage(
|
|
85
|
+
child:
|
|
86
|
+
ChapterSelectScreen(bibleName: bibleName, bookIndex: bookIndex),
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
),
|
|
90
|
+
GoRoute(
|
|
91
|
+
path: "/webview",
|
|
92
|
+
pageBuilder: (context, state) {
|
|
93
|
+
final url = state.extra as String;
|
|
94
|
+
return NoTransitionPage(
|
|
95
|
+
child: WebViewScreen(url: url),
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
),
|
|
99
|
+
],
|
|
100
|
+
);
|
|
101
|
+
|
|
11
102
|
class App extends StatelessWidget {
|
|
12
103
|
const App({super.key});
|
|
13
104
|
|
|
14
105
|
@override
|
|
15
106
|
Widget build(BuildContext context) {
|
|
16
|
-
return MaterialApp(
|
|
107
|
+
return MaterialApp.router(
|
|
17
|
-
|
|
108
|
+
routerConfig: router,
|
|
18
109
|
onGenerateTitle: (context) => context.l.title,
|
|
19
110
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
20
111
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
@@ -23,13 +114,6 @@ class App extends StatelessWidget {
|
|
|
23
114
|
theme: lightTheme,
|
|
24
115
|
darkTheme: darkTheme,
|
|
25
116
|
locale: Locale(languageCodeAtom.watch(context)),
|
|
26
|
-
home: firstOpenAtom.value
|
|
27
|
-
? const BibleSelectScreen()
|
|
28
|
-
: ChapterViewScreen(
|
|
29
|
-
bibleName: bibleNameAtom.value,
|
|
30
|
-
bookIndex: savedBookAtom.value,
|
|
31
|
-
chapterIndex: savedChapterAtom.value,
|
|
32
|
-
),
|
|
33
117
|
);
|
|
34
118
|
}
|
|
35
119
|
}
|
lib/navigation.dart
CHANGED
|
@@ -2,18 +2,14 @@ import "package:atoms_state/atoms_state.dart";
|
|
|
2
2
|
import "package:flutter/material.dart";
|
|
3
3
|
import "package:flutter/services.dart";
|
|
4
4
|
import "package:app_review/app_review.dart";
|
|
5
|
+
import "package:go_router/go_router.dart";
|
|
5
6
|
import "package:only_bible_app/models.dart";
|
|
6
|
-
import "package:only_bible_app/screens/bible_select_screen.dart";
|
|
7
|
-
import "package:only_bible_app/screens/book_select_screen.dart";
|
|
8
|
-
import "package:only_bible_app/screens/chapter_select_screen.dart";
|
|
9
|
-
import "package:only_bible_app/screens/chapter_view_screen.dart";
|
|
10
7
|
import "package:only_bible_app/sheets/actions_sheet.dart";
|
|
11
8
|
import "package:only_bible_app/sheets/highlight_sheet.dart";
|
|
12
9
|
import "package:only_bible_app/sheets/settings_sheet.dart";
|
|
13
10
|
import "package:only_bible_app/store/actions.dart";
|
|
14
11
|
import "package:only_bible_app/store/state.dart";
|
|
15
12
|
import "package:only_bible_app/utils.dart";
|
|
16
|
-
import "package:only_bible_app/screens/webview_screen.dart";
|
|
17
13
|
import "package:share_plus/share_plus.dart";
|
|
18
14
|
|
|
19
15
|
final actionsShownAtom = Atom(
|
|
@@ -38,73 +34,42 @@ final highlightsShownAtom = Atom(
|
|
|
38
34
|
},
|
|
39
35
|
);
|
|
40
36
|
|
|
41
|
-
PageRouteBuilder<dynamic> createNoTransitionPageRoute(Widget page) {
|
|
42
|
-
return PageRouteBuilder(
|
|
43
|
-
opaque: false,
|
|
44
|
-
transitionDuration: Duration.zero,
|
|
45
|
-
reverseTransitionDuration: Duration.zero,
|
|
46
|
-
pageBuilder: (context, _, __) => page,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
PageRouteBuilder<dynamic> createSlideRoute({
|
|
51
|
-
required BuildContext context,
|
|
52
|
-
TextDirection? slideDir,
|
|
53
|
-
required Widget page,
|
|
54
|
-
}) {
|
|
55
|
-
if (slideDir == null) {
|
|
56
|
-
return PageRouteBuilder(
|
|
57
|
-
pageBuilder: (context, _, __) {
|
|
58
|
-
return page;
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
return PageRouteBuilder(
|
|
63
|
-
pageBuilder: (context, animation, secondaryAnimation) => page,
|
|
64
|
-
|
|
37
|
+
String _chapterPath(String bibleName, int book, int chapter) {
|
|
65
|
-
const begin = Offset(1.0, 0.0);
|
|
66
|
-
const end = Offset.zero;
|
|
67
|
-
const curve = Curves.ease;
|
|
68
|
-
|
|
38
|
+
return "/chapter/${Uri.encodeComponent(bibleName)}/$book/$chapter";
|
|
69
|
-
return SlideTransition(
|
|
70
|
-
textDirection: slideDir,
|
|
71
|
-
position: animation.drive(tween),
|
|
72
|
-
child: child,
|
|
73
|
-
);
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
39
|
}
|
|
77
40
|
|
|
78
41
|
void updateStatusBar(bool v) {
|
|
79
42
|
if (v) {
|
|
80
|
-
SystemChrome.setSystemUIOverlayStyle(
|
|
43
|
+
SystemChrome.setSystemUIOverlayStyle(
|
|
44
|
+
const SystemUiOverlayStyle(
|
|
81
|
-
|
|
45
|
+
systemNavigationBarColor: Color(0xFF1F1F22),
|
|
82
|
-
|
|
46
|
+
statusBarColor: Color(0xFF1F1F22),
|
|
83
|
-
|
|
47
|
+
systemNavigationBarIconBrightness: Brightness.light,
|
|
84
|
-
|
|
48
|
+
statusBarIconBrightness: Brightness.light,
|
|
85
|
-
|
|
49
|
+
),
|
|
50
|
+
);
|
|
86
51
|
} else {
|
|
87
|
-
SystemChrome.setSystemUIOverlayStyle(
|
|
52
|
+
SystemChrome.setSystemUIOverlayStyle(
|
|
53
|
+
const SystemUiOverlayStyle(
|
|
88
|
-
|
|
54
|
+
systemNavigationBarColor: Colors.white,
|
|
89
|
-
|
|
55
|
+
statusBarColor: Colors.white,
|
|
90
|
-
|
|
56
|
+
systemNavigationBarIconBrightness: Brightness.dark,
|
|
91
|
-
|
|
57
|
+
statusBarIconBrightness: Brightness.dark,
|
|
92
|
-
|
|
58
|
+
),
|
|
59
|
+
);
|
|
93
60
|
}
|
|
94
61
|
}
|
|
95
62
|
|
|
96
|
-
void pushBookChapter(
|
|
63
|
+
void pushBookChapter(
|
|
64
|
+
BuildContext context,
|
|
65
|
+
String bibleName,
|
|
66
|
+
int book,
|
|
67
|
+
int chapter,
|
|
97
|
-
|
|
68
|
+
TextDirection? dir,
|
|
69
|
+
) {
|
|
98
70
|
dispatch(UpdateChapter(book, chapter));
|
|
99
71
|
clearEvents(context);
|
|
100
|
-
Navigator.of(context).push(
|
|
101
|
-
createSlideRoute(
|
|
102
|
-
context: context,
|
|
103
|
-
slideDir: dir,
|
|
104
|
-
page: ChapterViewScreen(
|
|
105
|
-
|
|
72
|
+
context.push(_chapterPath(bibleName, book, chapter), extra: dir);
|
|
106
|
-
),
|
|
107
|
-
);
|
|
108
73
|
}
|
|
109
74
|
|
|
110
75
|
void replaceBookChapter(
|
|
@@ -115,27 +80,29 @@ void replaceBookChapter(
|
|
|
115
80
|
) {
|
|
116
81
|
dispatch(UpdateChapter(book, chapter));
|
|
117
82
|
clearEvents(context);
|
|
118
|
-
Navigator.of(context).pushReplacement(
|
|
119
|
-
createNoTransitionPageRoute(
|
|
120
|
-
ChapterViewScreen(
|
|
121
|
-
bibleName: bibleName,
|
|
122
|
-
bookIndex: book,
|
|
123
|
-
|
|
83
|
+
context.go(_chapterPath(bibleName, book, chapter));
|
|
124
|
-
),
|
|
125
|
-
),
|
|
126
|
-
);
|
|
127
84
|
}
|
|
128
85
|
|
|
129
86
|
void nextChapter(BuildContext context, Bible bible, int book, int chapter) {
|
|
130
87
|
final selectedBook = bible.books[book];
|
|
131
88
|
if (selectedBook.chapters.length > chapter + 1) {
|
|
89
|
+
pushBookChapter(
|
|
90
|
+
context,
|
|
91
|
+
bible.name,
|
|
132
|
-
|
|
92
|
+
selectedBook.index,
|
|
93
|
+
chapter + 1,
|
|
133
|
-
|
|
94
|
+
TextDirection.ltr,
|
|
95
|
+
);
|
|
134
96
|
} else {
|
|
135
97
|
if (selectedBook.index + 1 < bible.books.length) {
|
|
136
98
|
final nextBook = bible.books[selectedBook.index + 1];
|
|
137
99
|
pushBookChapter(
|
|
100
|
+
context,
|
|
101
|
+
bible.name,
|
|
102
|
+
nextBook.index,
|
|
103
|
+
0,
|
|
138
|
-
|
|
104
|
+
TextDirection.ltr,
|
|
105
|
+
);
|
|
139
106
|
}
|
|
140
107
|
}
|
|
141
108
|
}
|
|
@@ -146,85 +113,66 @@ void previousChapter(BuildContext context, Bible bible, int book, int chapter) {
|
|
|
146
113
|
// if (Navigator.of(context).canPop()) {
|
|
147
114
|
// Navigator.of(context).pop();
|
|
148
115
|
// } else {
|
|
116
|
+
pushBookChapter(
|
|
117
|
+
context,
|
|
118
|
+
bible.name,
|
|
149
|
-
|
|
119
|
+
selectedBook.index,
|
|
120
|
+
chapter - 1,
|
|
150
|
-
|
|
121
|
+
TextDirection.rtl,
|
|
122
|
+
);
|
|
151
123
|
// }
|
|
152
124
|
} else {
|
|
153
125
|
if (selectedBook.index - 1 >= 0) {
|
|
154
126
|
final prevBook = bible.books[selectedBook.index - 1];
|
|
155
|
-
pushBookChapter(
|
|
127
|
+
pushBookChapter(
|
|
128
|
+
context,
|
|
129
|
+
bible.name,
|
|
130
|
+
prevBook.index,
|
|
156
|
-
|
|
131
|
+
prevBook.chapters.length - 1,
|
|
132
|
+
TextDirection.rtl,
|
|
133
|
+
);
|
|
157
134
|
}
|
|
158
135
|
}
|
|
159
136
|
}
|
|
160
137
|
|
|
161
138
|
void showAboutUs(BuildContext context) {
|
|
162
|
-
Navigator.of(context).push(
|
|
163
|
-
createNoTransitionPageRoute(
|
|
164
|
-
const WebViewScreen(
|
|
165
|
-
|
|
139
|
+
context.push("/webview", extra: "https://onlybible.app/about-us");
|
|
166
|
-
),
|
|
167
|
-
),
|
|
168
|
-
);
|
|
169
140
|
}
|
|
170
141
|
|
|
171
142
|
void showPrivacyPolicy(BuildContext context) {
|
|
172
|
-
Navigator.of(context).push(
|
|
173
|
-
createNoTransitionPageRoute(
|
|
174
|
-
const WebViewScreen(
|
|
175
|
-
|
|
143
|
+
context.push("/webview", extra: "https://onlybible.app/privacy-policy");
|
|
176
|
-
),
|
|
177
|
-
),
|
|
178
|
-
);
|
|
179
144
|
}
|
|
180
145
|
|
|
181
146
|
void showTermsAndConditions(BuildContext context) {
|
|
182
|
-
Navigator.of(context).push(
|
|
183
|
-
createNoTransitionPageRoute(
|
|
184
|
-
const WebViewScreen(
|
|
185
|
-
|
|
147
|
+
context.push("/webview", extra: "https://onlybible.app/terms-and-conditions");
|
|
186
|
-
),
|
|
187
|
-
),
|
|
188
|
-
);
|
|
189
148
|
}
|
|
190
149
|
|
|
191
150
|
void changeBible(BuildContext context) {
|
|
192
|
-
Navigator.of(context).pushReplacement(
|
|
193
|
-
|
|
151
|
+
context.go("/bible");
|
|
194
|
-
const BibleSelectScreen(),
|
|
195
|
-
),
|
|
196
|
-
);
|
|
197
152
|
}
|
|
198
153
|
|
|
199
154
|
void changeBibleFromHeader(BuildContext context) {
|
|
200
|
-
Navigator.of(context).push(
|
|
201
|
-
|
|
155
|
+
context.push("/bible");
|
|
202
|
-
const BibleSelectScreen(),
|
|
203
|
-
),
|
|
204
|
-
);
|
|
205
156
|
}
|
|
206
157
|
|
|
207
158
|
void changeBook(BuildContext context, Bible bible) {
|
|
208
|
-
Navigator.of(context).push(
|
|
209
|
-
createNoTransitionPageRoute(
|
|
210
|
-
|
|
159
|
+
context.push("/books/${Uri.encodeComponent(bible.name)}");
|
|
211
|
-
),
|
|
212
|
-
);
|
|
213
160
|
}
|
|
214
161
|
|
|
215
162
|
void changeChapter(BuildContext context, Bible bible, Book book, int index) {
|
|
216
|
-
Navigator.of(context).push(
|
|
217
|
-
createNoTransitionPageRoute(
|
|
218
|
-
|
|
163
|
+
context.push("/chapters/${Uri.encodeComponent(bible.name)}/${book.index}");
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
164
|
}
|
|
222
165
|
|
|
223
|
-
Future<void> updateCurrentBible(
|
|
166
|
+
Future<void> updateCurrentBible(
|
|
167
|
+
BuildContext context,
|
|
168
|
+
String name,
|
|
169
|
+
String code,
|
|
170
|
+
int book,
|
|
224
|
-
|
|
171
|
+
int chapter,
|
|
172
|
+
) async {
|
|
225
173
|
hideActions(context);
|
|
226
174
|
dispatch(UpdateBible(name, code));
|
|
227
|
-
|
|
175
|
+
context.go(_chapterPath(name, book, chapter));
|
|
228
176
|
}
|
|
229
177
|
|
|
230
178
|
void shareAppLink(BuildContext context) {
|
|
@@ -245,7 +193,8 @@ Future<void> rateApp(BuildContext context) async {
|
|
|
245
193
|
AppReview.requestReview;
|
|
246
194
|
}
|
|
247
195
|
|
|
196
|
+
Future<void> shareVerses(
|
|
248
|
-
|
|
197
|
+
BuildContext context, Bible bible, List<Verse> verses) async {
|
|
249
198
|
final name = context.bookNames[verses.first.book];
|
|
250
199
|
final chapter = verses.first.chapter + 1;
|
|
251
200
|
final items = verses.sortedBy((e) => e.index).map((e) => e.index + 1);
|
lib/screens/book_select_screen.dart
CHANGED
|
@@ -1,66 +1,79 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
+
import "package:go_router/go_router.dart";
|
|
2
3
|
import "package:only_bible_app/navigation.dart";
|
|
4
|
+
import "package:only_bible_app/store/state.dart";
|
|
3
5
|
import "package:only_bible_app/utils.dart";
|
|
4
6
|
import "package:only_bible_app/widgets/scaffold_menu.dart";
|
|
5
|
-
import "package:only_bible_app/screens/chapter_select_screen.dart";
|
|
6
7
|
import "package:only_bible_app/widgets/sliver_heading.dart";
|
|
7
8
|
import "package:only_bible_app/widgets/sliver_tile_grid.dart";
|
|
8
9
|
import "package:only_bible_app/models.dart";
|
|
9
10
|
|
|
10
11
|
class BookSelectScreen extends StatelessWidget {
|
|
11
|
-
final
|
|
12
|
+
final String bibleName;
|
|
12
13
|
|
|
13
|
-
const BookSelectScreen({super.key, required this.
|
|
14
|
+
const BookSelectScreen({super.key, required this.bibleName});
|
|
14
15
|
|
|
15
|
-
dynamic onBookSelected(BuildContext context, int index) {
|
|
16
|
+
dynamic onBookSelected(BuildContext context, Bible bible, int index) {
|
|
16
17
|
final book = bible.books[index];
|
|
17
18
|
if (book.chapters.length == 1) {
|
|
18
19
|
return replaceBookChapter(context, bible.name, index, 0);
|
|
19
20
|
}
|
|
20
|
-
Navigator.of(context).pushReplacement(
|
|
21
|
-
PageRouteBuilder(
|
|
22
|
-
opaque: false,
|
|
23
|
-
transitionDuration: Duration.zero,
|
|
24
|
-
reverseTransitionDuration: Duration.zero,
|
|
25
|
-
|
|
21
|
+
context.go("/chapters/${Uri.encodeComponent(bible.name)}/${book.index}");
|
|
26
|
-
bible: bible,
|
|
27
|
-
book: book,
|
|
28
|
-
selectedBookIndex: index,
|
|
29
|
-
),
|
|
30
|
-
),
|
|
31
|
-
);
|
|
32
22
|
}
|
|
33
23
|
|
|
34
24
|
@override
|
|
35
25
|
Widget build(BuildContext context) {
|
|
36
|
-
return
|
|
26
|
+
return FutureBuilder(
|
|
27
|
+
future: bibleAtom.getValue(bibleName),
|
|
37
|
-
|
|
28
|
+
builder: (context, state) {
|
|
38
|
-
physics: const BouncingScrollPhysics(),
|
|
39
|
-
slivers: [
|
|
40
|
-
SliverHeading(title: context.l.oldTestamentTitle, showClose: true),
|
|
41
|
-
SliverTileGrid(
|
|
42
|
-
children: List.of(
|
|
43
|
-
bible.getOldBooks().map((book) {
|
|
44
|
-
|
|
29
|
+
return state.when(
|
|
30
|
+
loading: () => ColoredBox(
|
|
45
|
-
|
|
31
|
+
color: Theme.of(context).colorScheme.surface,
|
|
46
|
-
|
|
32
|
+
child: const Center(child: CircularProgressIndicator()),
|
|
47
|
-
);
|
|
48
|
-
}),
|
|
49
|
-
),
|
|
50
33
|
),
|
|
34
|
+
success: (Bible? bible) {
|
|
35
|
+
return ScaffoldMenu(
|
|
36
|
+
child: CustomScrollView(
|
|
37
|
+
physics: const BouncingScrollPhysics(),
|
|
38
|
+
slivers: [
|
|
39
|
+
SliverHeading(
|
|
51
|
-
|
|
40
|
+
title: context.l.oldTestamentTitle, showClose: true),
|
|
52
|
-
|
|
41
|
+
SliverTileGrid(
|
|
53
|
-
|
|
42
|
+
children: List.of(
|
|
43
|
+
bible!.getOldBooks().map((book) {
|
|
44
|
+
return TextButton(
|
|
45
|
+
child: Text(
|
|
46
|
+
book.shortName(context.bookNames[book.index])),
|
|
47
|
+
onPressed: () =>
|
|
48
|
+
onBookSelected(context, bible, book.index),
|
|
49
|
+
);
|
|
50
|
+
}),
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
SliverHeading(
|
|
54
|
+
title: context.l.newTestamentTitle, top: 30, bottom: 20),
|
|
55
|
+
SliverTileGrid(
|
|
56
|
+
children: List.of(
|
|
54
|
-
|
|
57
|
+
bible.getNewBooks().map((book) {
|
|
55
|
-
|
|
58
|
+
return TextButton(
|
|
59
|
+
child: Text(
|
|
56
|
-
|
|
60
|
+
book.shortName(context.bookNames[book.index])),
|
|
61
|
+
onPressed: () =>
|
|
57
|
-
|
|
62
|
+
onBookSelected(context, bible, book.index),
|
|
58
|
-
|
|
63
|
+
);
|
|
59
|
-
|
|
64
|
+
}),
|
|
60
|
-
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
],
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
error: () => ColoredBox(
|
|
72
|
+
color: Theme.of(context).colorScheme.surface,
|
|
73
|
+
child: Center(child: Text("Could not load bible ${state.error}")),
|
|
61
74
|
),
|
|
75
|
+
);
|
|
62
|
-
|
|
76
|
+
},
|
|
63
|
-
),
|
|
64
77
|
);
|
|
65
78
|
}
|
|
66
79
|
}
|
lib/screens/chapter_select_screen.dart
CHANGED
|
@@ -1,35 +1,56 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
2
|
import "package:only_bible_app/models.dart";
|
|
3
3
|
import "package:only_bible_app/navigation.dart";
|
|
4
|
+
import "package:only_bible_app/store/state.dart";
|
|
4
5
|
import "package:only_bible_app/utils.dart";
|
|
5
6
|
import "package:only_bible_app/widgets/scaffold_menu.dart";
|
|
6
7
|
import "package:only_bible_app/widgets/sliver_tile_grid.dart";
|
|
7
8
|
import "package:only_bible_app/widgets/sliver_heading.dart";
|
|
8
9
|
|
|
9
10
|
class ChapterSelectScreen extends StatelessWidget {
|
|
10
|
-
final
|
|
11
|
+
final String bibleName;
|
|
11
|
-
final Book book;
|
|
12
|
-
final int
|
|
12
|
+
final int bookIndex;
|
|
13
13
|
|
|
14
|
+
const ChapterSelectScreen(
|
|
14
|
-
|
|
15
|
+
{super.key, required this.bibleName, required this.bookIndex});
|
|
15
16
|
|
|
16
17
|
@override
|
|
17
18
|
Widget build(BuildContext context) {
|
|
18
|
-
return
|
|
19
|
+
return FutureBuilder(
|
|
20
|
+
future: bibleAtom.getValue(bibleName),
|
|
19
|
-
|
|
21
|
+
builder: (context, state) {
|
|
20
|
-
physics: const BouncingScrollPhysics(),
|
|
21
|
-
slivers: [
|
|
22
|
-
SliverHeading(title: context.bookNames[book.index], showClose: true),
|
|
23
|
-
SliverTileGrid(
|
|
24
|
-
children: List.generate(book.chapters.length, (index) {
|
|
25
|
-
|
|
22
|
+
return state.when(
|
|
23
|
+
loading: () => ColoredBox(
|
|
26
|
-
|
|
24
|
+
color: Theme.of(context).colorScheme.surface,
|
|
27
|
-
|
|
25
|
+
child: const Center(child: CircularProgressIndicator()),
|
|
28
|
-
);
|
|
29
|
-
}),
|
|
30
26
|
),
|
|
27
|
+
success: (Bible? bible) {
|
|
28
|
+
final book = bible!.books[bookIndex];
|
|
29
|
+
return ScaffoldMenu(
|
|
30
|
+
child: CustomScrollView(
|
|
31
|
+
physics: const BouncingScrollPhysics(),
|
|
32
|
+
slivers: [
|
|
33
|
+
SliverHeading(
|
|
34
|
+
title: context.bookNames[book.index], showClose: true),
|
|
35
|
+
SliverTileGrid(
|
|
36
|
+
children: List.generate(book.chapters.length, (index) {
|
|
37
|
+
return TextButton(
|
|
38
|
+
child: Text("${index + 1}"),
|
|
39
|
+
onPressed: () => replaceBookChapter(
|
|
40
|
+
context, bible.name, bookIndex, index),
|
|
41
|
+
);
|
|
42
|
+
}),
|
|
43
|
+
),
|
|
31
|
-
|
|
44
|
+
],
|
|
32
|
-
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
|
+
error: () => ColoredBox(
|
|
49
|
+
color: Theme.of(context).colorScheme.surface,
|
|
50
|
+
child: Center(child: Text("Could not load bible ${state.error}")),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
},
|
|
33
54
|
);
|
|
34
55
|
}
|
|
35
56
|
}
|
lib/widgets/sliver_heading.dart
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "package:flutter/material.dart";
|
|
2
|
+
import "package:go_router/go_router.dart";
|
|
2
3
|
|
|
3
4
|
class SliverHeading extends StatelessWidget {
|
|
4
5
|
final String title;
|
|
@@ -24,13 +25,14 @@ class SliverHeading extends StatelessWidget {
|
|
|
24
25
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
25
26
|
children: [
|
|
26
27
|
Expanded(
|
|
28
|
+
child: Text(title,
|
|
27
|
-
|
|
29
|
+
style: Theme.of(context).textTheme.headlineMedium),
|
|
28
30
|
),
|
|
29
31
|
if (showClose)
|
|
30
32
|
IconButton(
|
|
31
33
|
icon: const Icon(Icons.close, size: 26),
|
|
32
34
|
onPressed: () {
|
|
33
|
-
|
|
35
|
+
context.pop();
|
|
34
36
|
},
|
|
35
37
|
),
|
|
36
38
|
],
|
pubspec.lock
CHANGED
|
@@ -423,6 +423,14 @@ packages:
|
|
|
423
423
|
url: "https://pub.dev"
|
|
424
424
|
source: hosted
|
|
425
425
|
version: "2.1.3"
|
|
426
|
+
go_router:
|
|
427
|
+
dependency: "direct main"
|
|
428
|
+
description:
|
|
429
|
+
name: go_router
|
|
430
|
+
sha256: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896"
|
|
431
|
+
url: "https://pub.dev"
|
|
432
|
+
source: hosted
|
|
433
|
+
version: "17.1.0"
|
|
426
434
|
graphs:
|
|
427
435
|
dependency: transitive
|
|
428
436
|
description:
|
pubspec.yaml
CHANGED
|
@@ -30,6 +30,7 @@ dependencies:
|
|
|
30
30
|
atoms_state: ^0.0.2
|
|
31
31
|
webview_flutter: ^4.13.1
|
|
32
32
|
app_review: ^3.0.0
|
|
33
|
+
go_router: ^17.1.0
|
|
33
34
|
|
|
34
35
|
dev_dependencies:
|
|
35
36
|
flutter_test:
|