~repos /only-bible-app

#kotlin#android#ios

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.


c322445f pyrossh

2 years ago
add loader
lib/atom.dart CHANGED
@@ -9,6 +9,14 @@ ensureAtomsInitialized(GetStorage box) async {
9
9
  await localBox.initStorage;
10
10
  }
11
11
 
12
+ class Cubit<T> extends ValueNotifier<T> {
13
+ Cubit(T initialState) : super(initialState);
14
+
15
+ void emit(T state) {
16
+ super.value = state;
17
+ }
18
+ }
19
+
12
20
  class Atom<T> extends ValueNotifier<T> {
13
21
  final String key;
14
22
  final bool persist;
lib/main.dart CHANGED
@@ -26,7 +26,7 @@ void main() async {
26
26
  usePathUrlStrategy();
27
27
  await initState();
28
28
  updateStatusBar(darkMode.value);
29
- await loadBible();
29
+ bibleCache.value = loadBible(bibleName.value);
30
30
  runApp(const App());
31
31
  FlutterNativeSplash.remove();
32
32
  }
lib/models.dart CHANGED
@@ -116,4 +116,4 @@ class HistoryFrame {
116
116
  final int chapter;
117
117
 
118
118
  const HistoryFrame({required this.book, required this.chapter});
119
- }
119
+ }
lib/navigation.dart CHANGED
@@ -31,6 +31,39 @@ final Atom<bool> highlightsShown = Atom<bool>(
31
31
  },
32
32
  );
33
33
 
34
+ createNoTransitionPageRoute(Widget page) {
35
+ return PageRouteBuilder(
36
+ opaque: false,
37
+ transitionDuration: Duration.zero,
38
+ reverseTransitionDuration: Duration.zero,
39
+ pageBuilder: (context, _, __) => page,
40
+ );
41
+ }
42
+
43
+ createSlideRoute({required BuildContext context, TextDirection? slideDir, required Widget page}) {
44
+ if (context.isWide || slideDir == null) {
45
+ return PageRouteBuilder(
46
+ pageBuilder: (context, _, __) {
47
+ return page;
48
+ },
49
+ );
50
+ }
51
+ return PageRouteBuilder(
52
+ pageBuilder: (context, animation, secondaryAnimation) => page,
53
+ transitionsBuilder: (context, animation, secondaryAnimation, child) {
54
+ const begin = Offset(1.0, 0.0);
55
+ const end = Offset.zero;
56
+ const curve = Curves.ease;
57
+ var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
58
+ return SlideTransition(
59
+ textDirection: slideDir,
60
+ position: animation.drive(tween),
61
+ child: child,
62
+ );
63
+ },
64
+ );
65
+ }
66
+
34
67
  updateStatusBar(bool v) {
35
68
  if (v) {
36
69
  SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
@@ -162,9 +195,9 @@ shareAppLink(BuildContext context) {
162
195
 
163
196
  rateApp(BuildContext context) {
164
197
  if (isAndroid()) {
165
- openUrl(context, "https://play.google.com/store/apps/details?id=packageName");
198
+ context.openUrl("https://play.google.com/store/apps/details?id=packageName");
166
199
  } else if (isIOS()) {
167
- openUrl(context, "https://apps.apple.com/us/app/only-bible-app/packageName");
200
+ context.openUrl("https://apps.apple.com/us/app/only-bible-app/packageName");
168
201
  }
169
202
  }
170
203
 
lib/screens/chapter_view_screen.dart CHANGED
@@ -1,10 +1,9 @@
1
1
  import "package:flutter/material.dart";
2
- import "package:only_bible_app/state.dart";
3
2
  import "package:only_bible_app/utils.dart";
3
+ import "package:only_bible_app/widgets/bible_loader.dart";
4
4
  import "package:only_bible_app/widgets/chapter_app_bar.dart";
5
5
  import "package:only_bible_app/widgets/sidebar.dart";
6
6
  import "package:only_bible_app/widgets/verses_view.dart";
7
- import "package:provider/provider.dart";
8
7
 
9
8
  class ChapterViewScreen extends StatelessWidget {
10
9
  final int bookIndex;
@@ -14,35 +13,19 @@ class ChapterViewScreen extends StatelessWidget {
14
13
 
15
14
  @override
16
15
  Widget build(BuildContext context) {
17
- // FutureBuilder(
18
- // future: loadData(), // This reloads everytime theme changes
19
- // builder: (context, snapshot) {
16
+ if (context.isWide) {
20
- // if (snapshot.hasData && snapshot.data != null && snapshot.connectionState == ConnectionState.done) {
21
- // return ChangeNotifierProvider(
22
- // create: (_) => BibleViewModel(bible: snapshot.data!.$1),
23
- // child: ChapterViewScreen(book: snapshot.data!.$2, chapter: snapshot.data!.$3),
24
- // );
25
- // }
17
+ return Scaffold(
26
- // return ColoredBox(
27
- // color: Theme.of(context).colorScheme.background,
18
+ backgroundColor: Theme.of(context).colorScheme.background,
28
- // child: const Center(
29
- // child: CircularProgressIndicator(),
30
- // ),
31
- // );
32
- // },
19
+ body: SafeArea(
20
+ child: Row(
21
+ children: [
33
- // ),
22
+ const Sidebar(),
23
+ Flexible(
24
+ child: BibleLoader(
25
+ builder: (bible) {
34
- final book = bible.watch(context).books[bookIndex];
26
+ final book = bible.books[bookIndex];
35
- final chapter = book.chapters[chapterIndex];
27
+ final chapter = book.chapters[chapterIndex];
36
- return Scaffold(
37
- appBar: context.isWide ? null : ChapterAppBar(book: book, chapter: chapter),
38
- backgroundColor: Theme.of(context).colorScheme.background,
39
- body: SafeArea(
40
- child: context.isWide
41
- ? Row(
42
- children: [
43
- const Sidebar(),
44
- Flexible(
45
- child: Column(
28
+ return Column(
46
29
  children: [
47
30
  ChapterAppBar(book: book, chapter: chapter),
48
31
  const Padding(
@@ -53,12 +36,27 @@ class ChapterViewScreen extends StatelessWidget {
53
36
  child: VersesView(chapter: chapter),
54
37
  ),
55
38
  ],
39
+ );
40
+ },
56
- ),
41
+ ),
57
- ),
42
+ ),
58
- ],
43
+ ],
59
- )
60
- : VersesView(chapter: chapter),
61
- ),
44
+ ),
45
+ ),
46
+ );
47
+ }
48
+ return BibleLoader(
49
+ builder: (bible) {
50
+ final book = bible.books[bookIndex];
51
+ final chapter = book.chapters[chapterIndex];
52
+ return Scaffold(
53
+ appBar: ChapterAppBar(book: book, chapter: chapter),
54
+ backgroundColor: Theme.of(context).colorScheme.background,
55
+ body: SafeArea(
56
+ child: VersesView(chapter: chapter),
57
+ ),
58
+ );
59
+ },
62
60
  );
63
61
  }
64
62
  }
lib/sheets/actions_sheet.dart CHANGED
@@ -36,7 +36,7 @@ class ActionsSheet extends StatelessWidget {
36
36
  if (audioEnabled) {
37
37
  onPlay(context);
38
38
  } else {
39
- showError(context, context.lEvent.audioNotAvailable);
39
+ showError(context, context.l.audioNotAvailable);
40
40
  }
41
41
  },
42
42
  icon: Icon(audioIcon, size: 34, color: audioEnabled ? iconColor : Colors.grey),
lib/state.dart CHANGED
@@ -1,7 +1,9 @@
1
+ import "dart:convert";
1
2
  import "dart:developer";
2
3
  import "package:firebase_crashlytics/firebase_crashlytics.dart";
3
4
  import "package:firebase_storage/firebase_storage.dart";
4
5
  import "package:flutter/material.dart";
6
+ import "package:flutter/services.dart";
5
7
  import "package:get_storage/get_storage.dart";
6
8
  import "package:just_audio/just_audio.dart";
7
9
  import "package:only_bible_app/atom.dart";
@@ -53,27 +55,44 @@ final Atom<Bible> bible = Atom<Bible>(
53
55
  },
54
56
  );
55
57
 
58
+ final bibleCache = Atom<Future<Bible?>?>(
59
+ key: "bible",
60
+ persist: false,
61
+ initialValue: null,
62
+ );
63
+
56
64
  updateCurrentBible(BuildContext context, Locale l, String name) async {
57
65
  languageCode.value = l.languageCode;
58
- bibleName.value = name;
66
+ bibleName.update!(name);
59
- await loadBible();
67
+ bibleCache.value = loadBible(name);
60
68
  }
61
69
 
62
- loadBible() async {
63
- // Trace customTrace;
64
- // if (!isDesktop()) {
65
- // customTrace = FirebasePerformance.instance.newTrace("loadBible");
66
- // await customTrace.start();
67
- // }
68
- final books = await getBibleFromAsset(bibleName.value);
70
+ Future<Bible> getBibleFromAsset(String file) async {
69
- // if (!isDesktop()) {
71
+ final bytes = await rootBundle.load("assets/bibles/$file.txt");
72
+ final books = getBibleFromText(utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
70
- // await customTrace.stop();
73
+ // await Future.delayed(Duration(seconds: 1));
71
- // }
72
- bible.update!(Bible.withBooks(
74
+ return Bible.withBooks(
73
75
  name: bibleName.value,
74
76
  books: books,
77
+ );
78
+ }
79
+
80
+ Future<Bible?> loadBible(String name) async {
81
+ print("loadBible ${name}");
82
+ return getBibleFromAsset(name).then((value) {
83
+ bible.update!(value);
84
+ return value;
75
- ));
85
+ });
76
86
  }
87
+ // Trace customTrace;
88
+ // if (!isDesktop()) {
89
+ // customTrace = FirebasePerformance.instance.newTrace("loadBible");
90
+ // await customTrace.start();
91
+ // }
92
+ // bibleLoading = Future.delayed(const Duration(seconds: 2)).then((value) => getBibleFromAsset(bibleName.value));
93
+ // if (!isDesktop()) {
94
+ // await customTrace.stop();
95
+ // }
77
96
 
78
97
  final Atom<bool> engTitles = Atom<bool>(
79
98
  key: "engTitles",
@@ -251,7 +270,7 @@ onPlay(BuildContext context) async {
251
270
  log("Could not play audio", name: "play", error: (err.toString(), pathname));
252
271
  FirebaseCrashlytics.instance.recordFlutterError(FlutterErrorDetails(exception: (err.toString(), pathname)));
253
272
  if (context.mounted) {
254
- showError(context, context.lEvent.audioError);
273
+ showError(context, context.l.audioError);
255
274
  }
256
275
  return;
257
276
  } finally {
lib/utils.dart CHANGED
@@ -1,13 +1,9 @@
1
- import "dart:convert";
2
1
  import "package:only_bible_app/dialog.dart";
3
2
  import "package:only_bible_app/state.dart";
4
3
  import "package:url_launcher/url_launcher.dart";
5
4
  import "package:flutter/foundation.dart" show defaultTargetPlatform, TargetPlatform;
6
5
  import "package:flutter/material.dart";
7
- import "package:flutter/services.dart";
8
- import "package:only_bible_app/models.dart";
9
6
  import "package:flutter_gen/gen_l10n/app_localizations.dart";
10
- import "package:provider/provider.dart";
11
7
 
12
8
  extension MyIterable<E> on Iterable<E> {
13
9
  Iterable<E> sortedBy(Comparable Function(E e) key) => toList()..sort((a, b) => key(a).compareTo(key(b)));
@@ -20,11 +16,7 @@ extension MyIterable<E> on Iterable<E> {
20
16
  extension AppContext on BuildContext {
21
17
  ThemeData get theme => Theme.of(this);
22
18
 
23
- AppLocalizations get l => engTitles.value && languageCode.value != "en"
19
+ AppLocalizations get l => engTitles.watch(this) && languageCode.watch(this) != "en"
24
- ? lookupAppLocalizations(const Locale("en"))
25
- : AppLocalizations.of(this)!;
26
-
27
- AppLocalizations get lEvent => engTitles.value && languageCode.value != "en"
28
20
  ? lookupAppLocalizations(const Locale("en"))
29
21
  : AppLocalizations.of(this)!;
30
22
 
@@ -125,6 +117,17 @@ extension AppContext on BuildContext {
125
117
  l.revelation,
126
118
  ];
127
119
  }
120
+
121
+ openUrl(String url) async {
122
+ final uri = Uri.parse(url);
123
+ if (await canLaunchUrl(uri)) {
124
+ if (await launchUrl(uri)) {
125
+ return;
126
+ }
127
+ }
128
+ if (!mounted) return;
129
+ showError(this, l.urlError);
130
+ }
128
131
  }
129
132
 
130
133
  bool isDesktop() {
@@ -140,52 +143,3 @@ bool isIOS() {
140
143
  bool isAndroid() {
141
144
  return defaultTargetPlatform == TargetPlatform.android;
142
145
  }
143
-
144
- createNoTransitionPageRoute(Widget page) {
145
- return PageRouteBuilder(
146
- opaque: false,
147
- transitionDuration: Duration.zero,
148
- reverseTransitionDuration: Duration.zero,
149
- pageBuilder: (context, _, __) => page,
150
- );
151
- }
152
-
153
- createSlideRoute({required BuildContext context, TextDirection? slideDir, required Widget page}) {
154
- if (context.isWide || slideDir == null) {
155
- return PageRouteBuilder(
156
- pageBuilder: (context, _, __) {
157
- return page;
158
- },
159
- );
160
- }
161
- return PageRouteBuilder(
162
- pageBuilder: (context, animation, secondaryAnimation) => page,
163
- transitionsBuilder: (context, animation, secondaryAnimation, child) {
164
- const begin = Offset(1.0, 0.0);
165
- const end = Offset.zero;
166
- const curve = Curves.ease;
167
- var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
168
- return SlideTransition(
169
- textDirection: slideDir,
170
- position: animation.drive(tween),
171
- child: child,
172
- );
173
- },
174
- );
175
- }
176
-
177
- getBibleFromAsset(String file) async {
178
- final bytes = await rootBundle.load("assets/bibles/$file.txt");
179
- return getBibleFromText(utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
180
- }
181
-
182
- openUrl(BuildContext context, String url) async {
183
- final uri = Uri.parse(url);
184
- if (await canLaunchUrl(uri)) {
185
- if (await launchUrl(uri)) {
186
- return;
187
- }
188
- }
189
- if (!context.mounted) return;
190
- showError(context, context.l.urlError);
191
- }
lib/widgets/bible_loader.dart ADDED
@@ -0,0 +1,27 @@
1
+ import "package:flutter/material.dart";
2
+ import "package:only_bible_app/models.dart";
3
+ import "package:only_bible_app/state.dart";
4
+
5
+ class BibleLoader extends StatelessWidget {
6
+ final Function(Bible) builder;
7
+
8
+ const BibleLoader({super.key, required this.builder});
9
+
10
+ @override
11
+ Widget build(BuildContext context) {
12
+ return FutureBuilder(
13
+ future: bibleCache.watch(context),
14
+ builder: (context, snapshot) {
15
+ if (snapshot.connectionState == ConnectionState.done) {
16
+ return builder(snapshot.data!);
17
+ }
18
+ return ColoredBox(
19
+ color: Theme.of(context).colorScheme.background,
20
+ child: const Center(
21
+ child: CircularProgressIndicator(),
22
+ ),
23
+ );
24
+ },
25
+ );
26
+ }
27
+ }
lib/widgets/scaffold_markdown.dart CHANGED
@@ -29,7 +29,7 @@ class ScaffoldMarkdown extends StatelessWidget {
29
29
  ),
30
30
  data: snapshot.data!,
31
31
  onTapLink: (text, href, title) {
32
- openUrl(context, href!);
32
+ context.openUrl(href!);
33
33
  },
34
34
  );
35
35
  }
pubspec.lock CHANGED
@@ -628,14 +628,6 @@ packages:
628
628
  url: "https://pub.dev"
629
629
  source: hosted
630
630
  version: "1.0.4"
631
- nested:
632
- dependency: transitive
633
- description:
634
- name: nested
635
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
636
- url: "https://pub.dev"
637
- source: hosted
638
- version: "1.0.0"
639
631
  package_config:
640
632
  dependency: transitive
641
633
  description:
@@ -764,14 +756,6 @@ packages:
764
756
  url: "https://pub.dev"
765
757
  source: hosted
766
758
  version: "4.2.4"
767
- provider:
768
- dependency: "direct main"
769
- description:
770
- name: provider
771
- sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
772
- url: "https://pub.dev"
773
- source: hosted
774
- version: "6.0.5"
775
759
  pub_semver:
776
760
  dependency: transitive
777
761
  description:
pubspec.yaml CHANGED
@@ -21,7 +21,6 @@ dependencies:
21
21
  flutter_swipe_detector: ^2.0.0
22
22
  cupertino_icons: ^1.0.5
23
23
  firebase_core: ^2.15.0
24
- provider: ^6.0.5
25
24
  firebase_crashlytics: ^3.3.4
26
25
  firebase_performance: ^0.9.2+4
27
26
  firebase_storage: ^11.2.5