~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.


0a263db5 pyrossh

2 years ago
use bloc
lib/app.dart CHANGED
@@ -1,5 +1,7 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:flutter_bloc/flutter_bloc.dart";
2
3
  import "package:flutter_gen/gen_l10n/app_localizations.dart";
4
+ import "package:only_bible_app/blocs/bible_bloc.dart";
3
5
  import "package:only_bible_app/screens/bible_select_screen.dart";
4
6
  import "package:only_bible_app/screens/chapter_view_screen.dart";
5
7
  import "package:only_bible_app/state.dart";
@@ -12,28 +14,39 @@ class App extends StatelessWidget {
12
14
 
13
15
  @override
14
16
  Widget build(BuildContext context) {
17
+ return BlocProvider<BibleBloc>(
18
+ create: (context) => BibleBloc(null)
19
+ ..add(
20
+ firstOpen.value ? const BibleEvent.firstLoad() : BibleEvent.load(bibleName.value),
21
+ ),
22
+ child: Builder(
23
+ builder: (context) {
15
- return MaterialApp(
24
+ return MaterialApp(
16
- onGenerateTitle: (context) => context.l.title,
25
+ onGenerateTitle: (context) => context.l.title,
17
- localizationsDelegates: AppLocalizations.localizationsDelegates,
26
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
18
- supportedLocales: AppLocalizations.supportedLocales,
27
+ supportedLocales: AppLocalizations.supportedLocales,
19
- debugShowCheckedModeBanner: false,
28
+ debugShowCheckedModeBanner: false,
20
- themeMode: darkMode.watch(context) ? ThemeMode.dark : ThemeMode.light,
29
+ themeMode: darkMode.watch(context) ? ThemeMode.dark : ThemeMode.light,
21
- theme: lightTheme,
30
+ theme: lightTheme,
22
- darkTheme: darkTheme,
31
+ darkTheme: darkTheme,
23
- locale: Locale(languageCode.watch(context)),
32
+ locale: Locale(languageCode.watch(context)),
24
- // initialRoute: "",
33
+ // initialRoute: "",
25
- routes: {
34
+ routes: {
26
- // TODO: maybe have a landing page
35
+ // TODO: maybe have a landing page
27
- // "/": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
36
+ // "/": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
37
+ "/privacy-policy": (context) =>
28
- "/privacy-policy": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
38
+ const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
29
- "/about-us": (context) => const ScaffoldMarkdown(title: "About Us", file: "about-us.md"),
39
+ "/about-us": (context) => const ScaffoldMarkdown(title: "About Us", file: "about-us.md"),
30
- },
40
+ },
31
- home: firstOpen.value
41
+ home: firstOpen.value
32
- ? const BibleSelectScreen()
42
+ ? const BibleSelectScreen()
33
- : ChapterViewScreen(
43
+ : ChapterViewScreen(
34
- bookIndex: savedBook.value,
44
+ bookIndex: savedBook.value,
35
- chapterIndex: savedChapter.value,
45
+ chapterIndex: savedChapter.value,
36
- ),
46
+ ),
47
+ );
48
+ },
49
+ ),
37
50
  );
38
51
  }
39
52
  }
lib/atom.dart CHANGED
@@ -64,3 +64,42 @@ class Atom<T> extends ValueNotifier<T> {
64
64
  class _ListenerWrapper {
65
65
  void Function()? listener;
66
66
  }
67
+
68
+ class AsyncAtom<T> extends ValueNotifier<T> {
69
+ final T Function(T) callback;
70
+
71
+ AsyncAtom(super._value, this.callback);
72
+
73
+ @override
74
+ get value {
75
+ return callback(this.value);
76
+ }
77
+
78
+ T watch(BuildContext context) {
79
+ final elementRef = WeakReference(context as Element);
80
+ final listenerWrapper = _ListenerWrapper();
81
+ listenerWrapper.listener = () {
82
+ assert(
83
+ SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks,
84
+ """
85
+ Do not mutate state (by setting the value of the ValueNotifier
86
+ that you are subscribed to) during a `build` method. If you need
87
+ to schedule a value update after `build` has completed, use
88
+ `SchedulerBinding.instance.scheduleTask(updateTask, Priority.idle)`,
89
+ `SchedulerBinding.addPostFrameCallback(updateTask)`, '
90
+ or similar.
91
+ """,
92
+ );
93
+ // If the element has not been garbage collected (causing
94
+ // `elementRef.target` to be null), or unmounted
95
+ if (elementRef.target?.mounted ?? false) {
96
+ // Mark the element as needing to be rebuilt
97
+ elementRef.target!.markNeedsBuild();
98
+ }
99
+ // Remove the listener -- only listen to one change per `build`
100
+ removeListener(listenerWrapper.listener!);
101
+ };
102
+ addListener(listenerWrapper.listener!);
103
+ return value;
104
+ }
105
+ }
lib/blocs/bible_bloc.dart ADDED
@@ -0,0 +1,28 @@
1
+ import "package:bloc/bloc.dart";
2
+ import "package:freezed_annotation/freezed_annotation.dart";
3
+ import "package:only_bible_app/models.dart";
4
+ import "package:only_bible_app/state.dart";
5
+
6
+ part "bible_bloc.freezed.dart";
7
+
8
+ part "bible_event.dart";
9
+
10
+ part "bible_state.dart";
11
+
12
+ class BibleBloc extends Bloc<BibleEvent, BibleState> {
13
+ final String? bibleName;
14
+ BibleBloc(this.bibleName) : super(const _Loading()) {
15
+ on<NoBible>((event, emit) {
16
+ emit(const _Loading());
17
+ });
18
+ on<LoadBible>((event, emit) async {
19
+ try {
20
+ emit(const _Loading());
21
+ final bible = await loadBible(event.name);
22
+ emit(_Success(bible!));
23
+ } catch (e) {
24
+ emit(const _Error());
25
+ }
26
+ });
27
+ }
28
+ }
lib/blocs/bible_bloc.freezed.dart ADDED
@@ -0,0 +1,725 @@
1
+ // coverage:ignore-file
2
+ // GENERATED CODE - DO NOT MODIFY BY HAND
3
+ // ignore_for_file: type=lint
4
+ // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
5
+
6
+ part of 'bible_bloc.dart';
7
+
8
+ // **************************************************************************
9
+ // FreezedGenerator
10
+ // **************************************************************************
11
+
12
+ T _$identity<T>(T value) => value;
13
+
14
+ final _privateConstructorUsedError = UnsupportedError(
15
+ 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
16
+
17
+ /// @nodoc
18
+ mixin _$BibleEvent {
19
+ @optionalTypeArgs
20
+ TResult when<TResult extends Object?>({
21
+ required TResult Function() firstLoad,
22
+ required TResult Function(String name) load,
23
+ }) =>
24
+ throw _privateConstructorUsedError;
25
+ @optionalTypeArgs
26
+ TResult? whenOrNull<TResult extends Object?>({
27
+ TResult? Function()? firstLoad,
28
+ TResult? Function(String name)? load,
29
+ }) =>
30
+ throw _privateConstructorUsedError;
31
+ @optionalTypeArgs
32
+ TResult maybeWhen<TResult extends Object?>({
33
+ TResult Function()? firstLoad,
34
+ TResult Function(String name)? load,
35
+ required TResult orElse(),
36
+ }) =>
37
+ throw _privateConstructorUsedError;
38
+ @optionalTypeArgs
39
+ TResult map<TResult extends Object?>({
40
+ required TResult Function(NoBible value) firstLoad,
41
+ required TResult Function(LoadBible value) load,
42
+ }) =>
43
+ throw _privateConstructorUsedError;
44
+ @optionalTypeArgs
45
+ TResult? mapOrNull<TResult extends Object?>({
46
+ TResult? Function(NoBible value)? firstLoad,
47
+ TResult? Function(LoadBible value)? load,
48
+ }) =>
49
+ throw _privateConstructorUsedError;
50
+ @optionalTypeArgs
51
+ TResult maybeMap<TResult extends Object?>({
52
+ TResult Function(NoBible value)? firstLoad,
53
+ TResult Function(LoadBible value)? load,
54
+ required TResult orElse(),
55
+ }) =>
56
+ throw _privateConstructorUsedError;
57
+ }
58
+
59
+ /// @nodoc
60
+ abstract class $BibleEventCopyWith<$Res> {
61
+ factory $BibleEventCopyWith(
62
+ BibleEvent value, $Res Function(BibleEvent) then) =
63
+ _$BibleEventCopyWithImpl<$Res, BibleEvent>;
64
+ }
65
+
66
+ /// @nodoc
67
+ class _$BibleEventCopyWithImpl<$Res, $Val extends BibleEvent>
68
+ implements $BibleEventCopyWith<$Res> {
69
+ _$BibleEventCopyWithImpl(this._value, this._then);
70
+
71
+ // ignore: unused_field
72
+ final $Val _value;
73
+ // ignore: unused_field
74
+ final $Res Function($Val) _then;
75
+ }
76
+
77
+ /// @nodoc
78
+ abstract class _$$NoBibleCopyWith<$Res> {
79
+ factory _$$NoBibleCopyWith(_$NoBible value, $Res Function(_$NoBible) then) =
80
+ __$$NoBibleCopyWithImpl<$Res>;
81
+ }
82
+
83
+ /// @nodoc
84
+ class __$$NoBibleCopyWithImpl<$Res>
85
+ extends _$BibleEventCopyWithImpl<$Res, _$NoBible>
86
+ implements _$$NoBibleCopyWith<$Res> {
87
+ __$$NoBibleCopyWithImpl(_$NoBible _value, $Res Function(_$NoBible) _then)
88
+ : super(_value, _then);
89
+ }
90
+
91
+ /// @nodoc
92
+
93
+ class _$NoBible implements NoBible {
94
+ const _$NoBible();
95
+
96
+ @override
97
+ String toString() {
98
+ return 'BibleEvent.firstLoad()';
99
+ }
100
+
101
+ @override
102
+ bool operator ==(dynamic other) {
103
+ return identical(this, other) ||
104
+ (other.runtimeType == runtimeType && other is _$NoBible);
105
+ }
106
+
107
+ @override
108
+ int get hashCode => runtimeType.hashCode;
109
+
110
+ @override
111
+ @optionalTypeArgs
112
+ TResult when<TResult extends Object?>({
113
+ required TResult Function() firstLoad,
114
+ required TResult Function(String name) load,
115
+ }) {
116
+ return firstLoad();
117
+ }
118
+
119
+ @override
120
+ @optionalTypeArgs
121
+ TResult? whenOrNull<TResult extends Object?>({
122
+ TResult? Function()? firstLoad,
123
+ TResult? Function(String name)? load,
124
+ }) {
125
+ return firstLoad?.call();
126
+ }
127
+
128
+ @override
129
+ @optionalTypeArgs
130
+ TResult maybeWhen<TResult extends Object?>({
131
+ TResult Function()? firstLoad,
132
+ TResult Function(String name)? load,
133
+ required TResult orElse(),
134
+ }) {
135
+ if (firstLoad != null) {
136
+ return firstLoad();
137
+ }
138
+ return orElse();
139
+ }
140
+
141
+ @override
142
+ @optionalTypeArgs
143
+ TResult map<TResult extends Object?>({
144
+ required TResult Function(NoBible value) firstLoad,
145
+ required TResult Function(LoadBible value) load,
146
+ }) {
147
+ return firstLoad(this);
148
+ }
149
+
150
+ @override
151
+ @optionalTypeArgs
152
+ TResult? mapOrNull<TResult extends Object?>({
153
+ TResult? Function(NoBible value)? firstLoad,
154
+ TResult? Function(LoadBible value)? load,
155
+ }) {
156
+ return firstLoad?.call(this);
157
+ }
158
+
159
+ @override
160
+ @optionalTypeArgs
161
+ TResult maybeMap<TResult extends Object?>({
162
+ TResult Function(NoBible value)? firstLoad,
163
+ TResult Function(LoadBible value)? load,
164
+ required TResult orElse(),
165
+ }) {
166
+ if (firstLoad != null) {
167
+ return firstLoad(this);
168
+ }
169
+ return orElse();
170
+ }
171
+ }
172
+
173
+ abstract class NoBible implements BibleEvent {
174
+ const factory NoBible() = _$NoBible;
175
+ }
176
+
177
+ /// @nodoc
178
+ abstract class _$$LoadBibleCopyWith<$Res> {
179
+ factory _$$LoadBibleCopyWith(
180
+ _$LoadBible value, $Res Function(_$LoadBible) then) =
181
+ __$$LoadBibleCopyWithImpl<$Res>;
182
+ @useResult
183
+ $Res call({String name});
184
+ }
185
+
186
+ /// @nodoc
187
+ class __$$LoadBibleCopyWithImpl<$Res>
188
+ extends _$BibleEventCopyWithImpl<$Res, _$LoadBible>
189
+ implements _$$LoadBibleCopyWith<$Res> {
190
+ __$$LoadBibleCopyWithImpl(
191
+ _$LoadBible _value, $Res Function(_$LoadBible) _then)
192
+ : super(_value, _then);
193
+
194
+ @pragma('vm:prefer-inline')
195
+ @override
196
+ $Res call({
197
+ Object? name = null,
198
+ }) {
199
+ return _then(_$LoadBible(
200
+ null == name
201
+ ? _value.name
202
+ : name // ignore: cast_nullable_to_non_nullable
203
+ as String,
204
+ ));
205
+ }
206
+ }
207
+
208
+ /// @nodoc
209
+
210
+ class _$LoadBible implements LoadBible {
211
+ const _$LoadBible(this.name);
212
+
213
+ @override
214
+ final String name;
215
+
216
+ @override
217
+ String toString() {
218
+ return 'BibleEvent.load(name: $name)';
219
+ }
220
+
221
+ @override
222
+ bool operator ==(dynamic other) {
223
+ return identical(this, other) ||
224
+ (other.runtimeType == runtimeType &&
225
+ other is _$LoadBible &&
226
+ (identical(other.name, name) || other.name == name));
227
+ }
228
+
229
+ @override
230
+ int get hashCode => Object.hash(runtimeType, name);
231
+
232
+ @JsonKey(ignore: true)
233
+ @override
234
+ @pragma('vm:prefer-inline')
235
+ _$$LoadBibleCopyWith<_$LoadBible> get copyWith =>
236
+ __$$LoadBibleCopyWithImpl<_$LoadBible>(this, _$identity);
237
+
238
+ @override
239
+ @optionalTypeArgs
240
+ TResult when<TResult extends Object?>({
241
+ required TResult Function() firstLoad,
242
+ required TResult Function(String name) load,
243
+ }) {
244
+ return load(name);
245
+ }
246
+
247
+ @override
248
+ @optionalTypeArgs
249
+ TResult? whenOrNull<TResult extends Object?>({
250
+ TResult? Function()? firstLoad,
251
+ TResult? Function(String name)? load,
252
+ }) {
253
+ return load?.call(name);
254
+ }
255
+
256
+ @override
257
+ @optionalTypeArgs
258
+ TResult maybeWhen<TResult extends Object?>({
259
+ TResult Function()? firstLoad,
260
+ TResult Function(String name)? load,
261
+ required TResult orElse(),
262
+ }) {
263
+ if (load != null) {
264
+ return load(name);
265
+ }
266
+ return orElse();
267
+ }
268
+
269
+ @override
270
+ @optionalTypeArgs
271
+ TResult map<TResult extends Object?>({
272
+ required TResult Function(NoBible value) firstLoad,
273
+ required TResult Function(LoadBible value) load,
274
+ }) {
275
+ return load(this);
276
+ }
277
+
278
+ @override
279
+ @optionalTypeArgs
280
+ TResult? mapOrNull<TResult extends Object?>({
281
+ TResult? Function(NoBible value)? firstLoad,
282
+ TResult? Function(LoadBible value)? load,
283
+ }) {
284
+ return load?.call(this);
285
+ }
286
+
287
+ @override
288
+ @optionalTypeArgs
289
+ TResult maybeMap<TResult extends Object?>({
290
+ TResult Function(NoBible value)? firstLoad,
291
+ TResult Function(LoadBible value)? load,
292
+ required TResult orElse(),
293
+ }) {
294
+ if (load != null) {
295
+ return load(this);
296
+ }
297
+ return orElse();
298
+ }
299
+ }
300
+
301
+ abstract class LoadBible implements BibleEvent {
302
+ const factory LoadBible(final String name) = _$LoadBible;
303
+
304
+ String get name;
305
+ @JsonKey(ignore: true)
306
+ _$$LoadBibleCopyWith<_$LoadBible> get copyWith =>
307
+ throw _privateConstructorUsedError;
308
+ }
309
+
310
+ /// @nodoc
311
+ mixin _$BibleState {
312
+ @optionalTypeArgs
313
+ TResult when<TResult extends Object?>({
314
+ required TResult Function() loading,
315
+ required TResult Function(Bible bible) success,
316
+ required TResult Function() error,
317
+ }) =>
318
+ throw _privateConstructorUsedError;
319
+ @optionalTypeArgs
320
+ TResult? whenOrNull<TResult extends Object?>({
321
+ TResult? Function()? loading,
322
+ TResult? Function(Bible bible)? success,
323
+ TResult? Function()? error,
324
+ }) =>
325
+ throw _privateConstructorUsedError;
326
+ @optionalTypeArgs
327
+ TResult maybeWhen<TResult extends Object?>({
328
+ TResult Function()? loading,
329
+ TResult Function(Bible bible)? success,
330
+ TResult Function()? error,
331
+ required TResult orElse(),
332
+ }) =>
333
+ throw _privateConstructorUsedError;
334
+ @optionalTypeArgs
335
+ TResult map<TResult extends Object?>({
336
+ required TResult Function(_Loading value) loading,
337
+ required TResult Function(_Success value) success,
338
+ required TResult Function(_Error value) error,
339
+ }) =>
340
+ throw _privateConstructorUsedError;
341
+ @optionalTypeArgs
342
+ TResult? mapOrNull<TResult extends Object?>({
343
+ TResult? Function(_Loading value)? loading,
344
+ TResult? Function(_Success value)? success,
345
+ TResult? Function(_Error value)? error,
346
+ }) =>
347
+ throw _privateConstructorUsedError;
348
+ @optionalTypeArgs
349
+ TResult maybeMap<TResult extends Object?>({
350
+ TResult Function(_Loading value)? loading,
351
+ TResult Function(_Success value)? success,
352
+ TResult Function(_Error value)? error,
353
+ required TResult orElse(),
354
+ }) =>
355
+ throw _privateConstructorUsedError;
356
+ }
357
+
358
+ /// @nodoc
359
+ abstract class $BibleStateCopyWith<$Res> {
360
+ factory $BibleStateCopyWith(
361
+ BibleState value, $Res Function(BibleState) then) =
362
+ _$BibleStateCopyWithImpl<$Res, BibleState>;
363
+ }
364
+
365
+ /// @nodoc
366
+ class _$BibleStateCopyWithImpl<$Res, $Val extends BibleState>
367
+ implements $BibleStateCopyWith<$Res> {
368
+ _$BibleStateCopyWithImpl(this._value, this._then);
369
+
370
+ // ignore: unused_field
371
+ final $Val _value;
372
+ // ignore: unused_field
373
+ final $Res Function($Val) _then;
374
+ }
375
+
376
+ /// @nodoc
377
+ abstract class _$$_LoadingCopyWith<$Res> {
378
+ factory _$$_LoadingCopyWith(
379
+ _$_Loading value, $Res Function(_$_Loading) then) =
380
+ __$$_LoadingCopyWithImpl<$Res>;
381
+ }
382
+
383
+ /// @nodoc
384
+ class __$$_LoadingCopyWithImpl<$Res>
385
+ extends _$BibleStateCopyWithImpl<$Res, _$_Loading>
386
+ implements _$$_LoadingCopyWith<$Res> {
387
+ __$$_LoadingCopyWithImpl(_$_Loading _value, $Res Function(_$_Loading) _then)
388
+ : super(_value, _then);
389
+ }
390
+
391
+ /// @nodoc
392
+
393
+ class _$_Loading implements _Loading {
394
+ const _$_Loading();
395
+
396
+ @override
397
+ String toString() {
398
+ return 'BibleState.loading()';
399
+ }
400
+
401
+ @override
402
+ bool operator ==(dynamic other) {
403
+ return identical(this, other) ||
404
+ (other.runtimeType == runtimeType && other is _$_Loading);
405
+ }
406
+
407
+ @override
408
+ int get hashCode => runtimeType.hashCode;
409
+
410
+ @override
411
+ @optionalTypeArgs
412
+ TResult when<TResult extends Object?>({
413
+ required TResult Function() loading,
414
+ required TResult Function(Bible bible) success,
415
+ required TResult Function() error,
416
+ }) {
417
+ return loading();
418
+ }
419
+
420
+ @override
421
+ @optionalTypeArgs
422
+ TResult? whenOrNull<TResult extends Object?>({
423
+ TResult? Function()? loading,
424
+ TResult? Function(Bible bible)? success,
425
+ TResult? Function()? error,
426
+ }) {
427
+ return loading?.call();
428
+ }
429
+
430
+ @override
431
+ @optionalTypeArgs
432
+ TResult maybeWhen<TResult extends Object?>({
433
+ TResult Function()? loading,
434
+ TResult Function(Bible bible)? success,
435
+ TResult Function()? error,
436
+ required TResult orElse(),
437
+ }) {
438
+ if (loading != null) {
439
+ return loading();
440
+ }
441
+ return orElse();
442
+ }
443
+
444
+ @override
445
+ @optionalTypeArgs
446
+ TResult map<TResult extends Object?>({
447
+ required TResult Function(_Loading value) loading,
448
+ required TResult Function(_Success value) success,
449
+ required TResult Function(_Error value) error,
450
+ }) {
451
+ return loading(this);
452
+ }
453
+
454
+ @override
455
+ @optionalTypeArgs
456
+ TResult? mapOrNull<TResult extends Object?>({
457
+ TResult? Function(_Loading value)? loading,
458
+ TResult? Function(_Success value)? success,
459
+ TResult? Function(_Error value)? error,
460
+ }) {
461
+ return loading?.call(this);
462
+ }
463
+
464
+ @override
465
+ @optionalTypeArgs
466
+ TResult maybeMap<TResult extends Object?>({
467
+ TResult Function(_Loading value)? loading,
468
+ TResult Function(_Success value)? success,
469
+ TResult Function(_Error value)? error,
470
+ required TResult orElse(),
471
+ }) {
472
+ if (loading != null) {
473
+ return loading(this);
474
+ }
475
+ return orElse();
476
+ }
477
+ }
478
+
479
+ abstract class _Loading implements BibleState {
480
+ const factory _Loading() = _$_Loading;
481
+ }
482
+
483
+ /// @nodoc
484
+ abstract class _$$_SuccessCopyWith<$Res> {
485
+ factory _$$_SuccessCopyWith(
486
+ _$_Success value, $Res Function(_$_Success) then) =
487
+ __$$_SuccessCopyWithImpl<$Res>;
488
+ @useResult
489
+ $Res call({Bible bible});
490
+ }
491
+
492
+ /// @nodoc
493
+ class __$$_SuccessCopyWithImpl<$Res>
494
+ extends _$BibleStateCopyWithImpl<$Res, _$_Success>
495
+ implements _$$_SuccessCopyWith<$Res> {
496
+ __$$_SuccessCopyWithImpl(_$_Success _value, $Res Function(_$_Success) _then)
497
+ : super(_value, _then);
498
+
499
+ @pragma('vm:prefer-inline')
500
+ @override
501
+ $Res call({
502
+ Object? bible = null,
503
+ }) {
504
+ return _then(_$_Success(
505
+ null == bible
506
+ ? _value.bible
507
+ : bible // ignore: cast_nullable_to_non_nullable
508
+ as Bible,
509
+ ));
510
+ }
511
+ }
512
+
513
+ /// @nodoc
514
+
515
+ class _$_Success implements _Success {
516
+ const _$_Success(this.bible);
517
+
518
+ @override
519
+ final Bible bible;
520
+
521
+ @override
522
+ String toString() {
523
+ return 'BibleState.success(bible: $bible)';
524
+ }
525
+
526
+ @override
527
+ bool operator ==(dynamic other) {
528
+ return identical(this, other) ||
529
+ (other.runtimeType == runtimeType &&
530
+ other is _$_Success &&
531
+ (identical(other.bible, bible) || other.bible == bible));
532
+ }
533
+
534
+ @override
535
+ int get hashCode => Object.hash(runtimeType, bible);
536
+
537
+ @JsonKey(ignore: true)
538
+ @override
539
+ @pragma('vm:prefer-inline')
540
+ _$$_SuccessCopyWith<_$_Success> get copyWith =>
541
+ __$$_SuccessCopyWithImpl<_$_Success>(this, _$identity);
542
+
543
+ @override
544
+ @optionalTypeArgs
545
+ TResult when<TResult extends Object?>({
546
+ required TResult Function() loading,
547
+ required TResult Function(Bible bible) success,
548
+ required TResult Function() error,
549
+ }) {
550
+ return success(bible);
551
+ }
552
+
553
+ @override
554
+ @optionalTypeArgs
555
+ TResult? whenOrNull<TResult extends Object?>({
556
+ TResult? Function()? loading,
557
+ TResult? Function(Bible bible)? success,
558
+ TResult? Function()? error,
559
+ }) {
560
+ return success?.call(bible);
561
+ }
562
+
563
+ @override
564
+ @optionalTypeArgs
565
+ TResult maybeWhen<TResult extends Object?>({
566
+ TResult Function()? loading,
567
+ TResult Function(Bible bible)? success,
568
+ TResult Function()? error,
569
+ required TResult orElse(),
570
+ }) {
571
+ if (success != null) {
572
+ return success(bible);
573
+ }
574
+ return orElse();
575
+ }
576
+
577
+ @override
578
+ @optionalTypeArgs
579
+ TResult map<TResult extends Object?>({
580
+ required TResult Function(_Loading value) loading,
581
+ required TResult Function(_Success value) success,
582
+ required TResult Function(_Error value) error,
583
+ }) {
584
+ return success(this);
585
+ }
586
+
587
+ @override
588
+ @optionalTypeArgs
589
+ TResult? mapOrNull<TResult extends Object?>({
590
+ TResult? Function(_Loading value)? loading,
591
+ TResult? Function(_Success value)? success,
592
+ TResult? Function(_Error value)? error,
593
+ }) {
594
+ return success?.call(this);
595
+ }
596
+
597
+ @override
598
+ @optionalTypeArgs
599
+ TResult maybeMap<TResult extends Object?>({
600
+ TResult Function(_Loading value)? loading,
601
+ TResult Function(_Success value)? success,
602
+ TResult Function(_Error value)? error,
603
+ required TResult orElse(),
604
+ }) {
605
+ if (success != null) {
606
+ return success(this);
607
+ }
608
+ return orElse();
609
+ }
610
+ }
611
+
612
+ abstract class _Success implements BibleState {
613
+ const factory _Success(final Bible bible) = _$_Success;
614
+
615
+ Bible get bible;
616
+ @JsonKey(ignore: true)
617
+ _$$_SuccessCopyWith<_$_Success> get copyWith =>
618
+ throw _privateConstructorUsedError;
619
+ }
620
+
621
+ /// @nodoc
622
+ abstract class _$$_ErrorCopyWith<$Res> {
623
+ factory _$$_ErrorCopyWith(_$_Error value, $Res Function(_$_Error) then) =
624
+ __$$_ErrorCopyWithImpl<$Res>;
625
+ }
626
+
627
+ /// @nodoc
628
+ class __$$_ErrorCopyWithImpl<$Res>
629
+ extends _$BibleStateCopyWithImpl<$Res, _$_Error>
630
+ implements _$$_ErrorCopyWith<$Res> {
631
+ __$$_ErrorCopyWithImpl(_$_Error _value, $Res Function(_$_Error) _then)
632
+ : super(_value, _then);
633
+ }
634
+
635
+ /// @nodoc
636
+
637
+ class _$_Error implements _Error {
638
+ const _$_Error();
639
+
640
+ @override
641
+ String toString() {
642
+ return 'BibleState.error()';
643
+ }
644
+
645
+ @override
646
+ bool operator ==(dynamic other) {
647
+ return identical(this, other) ||
648
+ (other.runtimeType == runtimeType && other is _$_Error);
649
+ }
650
+
651
+ @override
652
+ int get hashCode => runtimeType.hashCode;
653
+
654
+ @override
655
+ @optionalTypeArgs
656
+ TResult when<TResult extends Object?>({
657
+ required TResult Function() loading,
658
+ required TResult Function(Bible bible) success,
659
+ required TResult Function() error,
660
+ }) {
661
+ return error();
662
+ }
663
+
664
+ @override
665
+ @optionalTypeArgs
666
+ TResult? whenOrNull<TResult extends Object?>({
667
+ TResult? Function()? loading,
668
+ TResult? Function(Bible bible)? success,
669
+ TResult? Function()? error,
670
+ }) {
671
+ return error?.call();
672
+ }
673
+
674
+ @override
675
+ @optionalTypeArgs
676
+ TResult maybeWhen<TResult extends Object?>({
677
+ TResult Function()? loading,
678
+ TResult Function(Bible bible)? success,
679
+ TResult Function()? error,
680
+ required TResult orElse(),
681
+ }) {
682
+ if (error != null) {
683
+ return error();
684
+ }
685
+ return orElse();
686
+ }
687
+
688
+ @override
689
+ @optionalTypeArgs
690
+ TResult map<TResult extends Object?>({
691
+ required TResult Function(_Loading value) loading,
692
+ required TResult Function(_Success value) success,
693
+ required TResult Function(_Error value) error,
694
+ }) {
695
+ return error(this);
696
+ }
697
+
698
+ @override
699
+ @optionalTypeArgs
700
+ TResult? mapOrNull<TResult extends Object?>({
701
+ TResult? Function(_Loading value)? loading,
702
+ TResult? Function(_Success value)? success,
703
+ TResult? Function(_Error value)? error,
704
+ }) {
705
+ return error?.call(this);
706
+ }
707
+
708
+ @override
709
+ @optionalTypeArgs
710
+ TResult maybeMap<TResult extends Object?>({
711
+ TResult Function(_Loading value)? loading,
712
+ TResult Function(_Success value)? success,
713
+ TResult Function(_Error value)? error,
714
+ required TResult orElse(),
715
+ }) {
716
+ if (error != null) {
717
+ return error(this);
718
+ }
719
+ return orElse();
720
+ }
721
+ }
722
+
723
+ abstract class _Error implements BibleState {
724
+ const factory _Error() = _$_Error;
725
+ }
lib/blocs/bible_event.dart ADDED
@@ -0,0 +1,7 @@
1
+ part of "bible_bloc.dart";
2
+
3
+ @freezed
4
+ class BibleEvent with _$BibleEvent {
5
+ const factory BibleEvent.firstLoad() = NoBible;
6
+ const factory BibleEvent.load(String name) = LoadBible;
7
+ }
lib/blocs/bible_state.dart ADDED
@@ -0,0 +1,8 @@
1
+ part of "bible_bloc.dart";
2
+
3
+ @freezed
4
+ class BibleState with _$BibleState {
5
+ const factory BibleState.loading() = _Loading;
6
+ const factory BibleState.success(Bible bible) = _Success;
7
+ const factory BibleState.error() = _Error;
8
+ }
lib/main.dart CHANGED
@@ -34,7 +34,6 @@ void main() async {
34
34
  );
35
35
  await initState();
36
36
  updateStatusBar(darkMode.value);
37
- bibleCache.value = loadBible(bibleName.value);
38
37
  runApp(const App());
39
38
  FlutterNativeSplash.remove();
40
39
  }
lib/models.dart CHANGED
@@ -63,14 +63,21 @@ class Chapter {
63
63
 
64
64
  class Verse {
65
65
  final int index;
66
+ final String bibleName;
66
67
  final int book;
67
68
  final int chapter;
68
69
  final String text;
69
70
 
71
+ const Verse({
72
+ required this.index,
73
+ required this.text,
74
+ required this.bibleName,
70
- const Verse({required this.index, required this.text, required this.chapter, required this.book});
75
+ required this.chapter,
76
+ required this.book,
77
+ });
71
78
  }
72
79
 
73
- List<Book> getBibleFromText(String text) {
80
+ List<Book> getBibleFromText(String bibleName, String text) {
74
81
  final List<Book> books = [];
75
82
  final lines = text.split("\n");
76
83
  for (var (index, line) in lines.indexed) {
@@ -103,6 +110,7 @@ List<Book> getBibleFromText(String text) {
103
110
  Verse(
104
111
  index: verseNo - 1,
105
112
  text: verseText,
113
+ bibleName: bibleName,
106
114
  chapter: chapter - 1,
107
115
  book: book - 1,
108
116
  ),
lib/screens/bible_select_screen.dart CHANGED
@@ -1,4 +1,6 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:flutter_bloc/flutter_bloc.dart";
3
+ import "package:only_bible_app/blocs/bible_bloc.dart";
2
4
  import "package:only_bible_app/navigation.dart";
3
5
  import "package:only_bible_app/state.dart";
4
6
  import "package:only_bible_app/utils.dart";
@@ -29,6 +31,7 @@ class BibleSelectScreen extends StatelessWidget {
29
31
  // ],
30
32
  // ),
31
33
  onPressed: () {
34
+ context.read<BibleBloc>().add(BibleEvent.load(l.languageTitle));
32
35
  updateCurrentBible(context, Locale(l.localeName), l.languageTitle);
33
36
  if (firstOpen.value) {
34
37
  firstOpen.set!();
lib/screens/chapter_view_screen.dart CHANGED
@@ -1,11 +1,14 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:flutter_bloc/flutter_bloc.dart";
3
+ import "package:only_bible_app/blocs/bible_bloc.dart";
4
+ import "package:only_bible_app/models.dart";
2
5
  import "package:only_bible_app/utils.dart";
3
- import "package:only_bible_app/widgets/bible_loader.dart";
4
6
  import "package:only_bible_app/widgets/chapter_app_bar.dart";
5
7
  import "package:only_bible_app/widgets/sidebar.dart";
6
8
  import "package:only_bible_app/widgets/verses_view.dart";
7
9
 
8
10
  class ChapterViewScreen extends StatelessWidget {
11
+ // final String bibleName;
9
12
  final int bookIndex;
10
13
  final int chapterIndex;
11
14
 
@@ -13,50 +16,74 @@ class ChapterViewScreen extends StatelessWidget {
13
16
 
14
17
  @override
15
18
  Widget build(BuildContext context) {
19
+ return BlocBuilder<BibleBloc, BibleState>(builder: (context, state) {
16
- if (context.isWide) {
20
+ if (!context.isWide) {
21
+ return state.when(
22
+ loading: () => ColoredBox(
23
+ color: Theme.of(context).colorScheme.background,
24
+ child: const Center(
25
+ child: CircularProgressIndicator(),
26
+ ),
27
+ ),
28
+ success: (Bible bible) {
29
+ final book = bible.books[bookIndex];
30
+ final chapter = book.chapters[chapterIndex];
31
+ return Scaffold(
32
+ appBar: ChapterAppBar(book: book, chapter: chapter),
33
+ backgroundColor: Theme.of(context).colorScheme.background,
34
+ body: SafeArea(
35
+ child: VersesView(chapter: chapter),
36
+ ),
37
+ );
38
+ },
39
+ error: () => ColoredBox(
40
+ color: Theme.of(context).colorScheme.background,
41
+ child: const Center(
42
+ child: Text("Could not load the bible"),
43
+ ),
44
+ ),
45
+ );
46
+ }
17
47
  return Scaffold(
18
48
  backgroundColor: Theme.of(context).colorScheme.background,
19
- body: SafeArea(
20
- child: Row(
49
+ body: Row(
21
- children: [
50
+ children: [
22
- const Sidebar(),
51
+ const Sidebar(),
23
- Flexible(
52
+ Flexible(
24
- child: BibleLoader(
53
+ child: state.when(
54
+ loading: () => ColoredBox(
55
+ color: Theme.of(context).colorScheme.background,
56
+ child: const Center(
57
+ child: CircularProgressIndicator(),
58
+ ),
59
+ ),
25
- builder: (bible) {
60
+ success: (Bible bible) {
26
- final book = bible.books[bookIndex];
61
+ final book = bible.books[bookIndex];
27
- final chapter = book.chapters[chapterIndex];
62
+ final chapter = book.chapters[chapterIndex];
28
- return Column(
63
+ return Column(
29
- children: [
64
+ children: [
30
- ChapterAppBar(book: book, chapter: chapter),
65
+ ChapterAppBar(book: book, chapter: chapter),
31
- const Padding(
66
+ const Padding(
32
- padding: EdgeInsets.only(bottom: 10),
67
+ padding: EdgeInsets.only(bottom: 10),
33
- child: Divider(height: 5, indent: 20, endIndent: 20, thickness: 1.5),
68
+ child: Divider(height: 5, indent: 20, endIndent: 20, thickness: 1.5),
34
- ),
69
+ ),
35
- Flexible(
70
+ Flexible(
36
- child: VersesView(chapter: chapter),
71
+ child: VersesView(chapter: chapter),
37
- ),
72
+ ),
38
- ],
73
+ ],
39
- );
74
+ );
40
- },
75
+ },
76
+ error: () => ColoredBox(
77
+ color: Theme.of(context).colorScheme.background,
78
+ child: const Center(
79
+ child: Text("Could not load the bible"),
80
+ ),
41
81
  ),
42
82
  ),
83
+ ),
43
- ],
84
+ ],
44
- ),
45
85
  ),
46
86
  );
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
- );
87
+ });
59
- },
60
- );
61
88
  }
62
89
  }
lib/state.dart CHANGED
@@ -55,34 +55,23 @@ final Atom<Bible> bible = Atom<Bible>(
55
55
  },
56
56
  );
57
57
 
58
- final bibleCache = Atom<Future<Bible?>?>(
59
- key: "bible",
60
- initialValue: null,
61
- );
62
-
63
58
  updateCurrentBible(BuildContext context, Locale l, String name) async {
64
59
  hideActions(context);
65
60
  languageCode.value = l.languageCode;
66
61
  bibleName.update!(name);
67
- bibleCache.value = loadBible(name);
68
62
  }
69
63
 
70
- Future<Bible> getBibleFromAsset(String file) async {
64
+ Future<Bible> getBibleFromAsset(String bibleName) async {
71
- final bytes = await rootBundle.load("assets/bibles/$file.txt");
65
+ final bytes = await rootBundle.load("assets/bibles/$bibleName.txt");
72
- final books = getBibleFromText(utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
66
+ final books = getBibleFromText(bibleName, utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
73
67
  // await Future.delayed(Duration(seconds: 1));
74
68
  return Bible.withBooks(
75
- name: bibleName.value,
69
+ name: bibleName,
76
70
  books: books,
77
71
  );
78
72
  }
79
73
 
80
- // CachedValue(
81
- // () => factorial(originalValue),
82
- // ).withDependency(() => originalValue)
83
-
84
74
  Future<Bible?> loadBible(String name) async {
85
- print("loadBible ${name}");
86
75
  return getBibleFromAsset(name).then((value) {
87
76
  bible.update!(value);
88
77
  return value;
lib/widgets/bible_loader.dart DELETED
@@ -1,27 +0,0 @@
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
- }
macos/Podfile.lock CHANGED
@@ -6,9 +6,6 @@ PODS:
6
6
  - Firebase/Crashlytics (10.12.0):
7
7
  - Firebase/CoreOnly
8
8
  - FirebaseCrashlytics (~> 10.12.0)
9
- - Firebase/Storage (10.12.0):
10
- - Firebase/CoreOnly
11
- - FirebaseStorage (~> 10.12.0)
12
9
  - firebase_core (2.15.0):
13
10
  - Firebase/CoreOnly (~> 10.12.0)
14
11
  - FlutterMacOS
@@ -17,13 +14,6 @@ PODS:
17
14
  - Firebase/Crashlytics (~> 10.12.0)
18
15
  - firebase_core
19
16
  - FlutterMacOS
20
- - firebase_storage (11.2.5):
21
- - Firebase/CoreOnly (~> 10.12.0)
22
- - Firebase/Storage (~> 10.12.0)
23
- - firebase_core
24
- - FlutterMacOS
25
- - FirebaseAppCheckInterop (10.13.0)
26
- - FirebaseAuthInterop (10.13.0)
27
17
  - FirebaseCore (10.12.0):
28
18
  - FirebaseCoreInternal (~> 10.0)
29
19
  - GoogleUtilities/Environment (~> 7.8)
@@ -53,12 +43,6 @@ PODS:
53
43
  - GoogleUtilities/Environment (~> 7.10)
54
44
  - nanopb (< 2.30910.0, >= 2.30908.0)
55
45
  - PromisesSwift (~> 2.1)
56
- - FirebaseStorage (10.12.0):
57
- - FirebaseAppCheckInterop (~> 10.0)
58
- - FirebaseAuthInterop (~> 10.0)
59
- - FirebaseCore (~> 10.0)
60
- - FirebaseCoreExtension (~> 10.0)
61
- - GTMSessionFetcher/Core (< 4.0, >= 2.1)
62
46
  - FlutterMacOS (1.0.0)
63
47
  - GoogleDataTransport (9.2.5):
64
48
  - GoogleUtilities/Environment (~> 7.7)
@@ -71,7 +55,6 @@ PODS:
71
55
  - "GoogleUtilities/NSData+zlib (7.11.5)"
72
56
  - GoogleUtilities/UserDefaults (7.11.5):
73
57
  - GoogleUtilities/Logger
74
- - GTMSessionFetcher/Core (3.1.1)
75
58
  - just_audio (0.0.1):
76
59
  - FlutterMacOS
77
60
  - nanopb (2.30909.0):
@@ -99,7 +82,6 @@ DEPENDENCIES:
99
82
  - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
100
83
  - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
101
84
  - firebase_crashlytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos`)
102
- - firebase_storage (from `Flutter/ephemeral/.symlinks/plugins/firebase_storage/macos`)
103
85
  - FlutterMacOS (from `Flutter/ephemeral`)
104
86
  - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
105
87
  - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
@@ -111,18 +93,14 @@ DEPENDENCIES:
111
93
  SPEC REPOS:
112
94
  trunk:
113
95
  - Firebase
114
- - FirebaseAppCheckInterop
115
- - FirebaseAuthInterop
116
96
  - FirebaseCore
117
97
  - FirebaseCoreExtension
118
98
  - FirebaseCoreInternal
119
99
  - FirebaseCrashlytics
120
100
  - FirebaseInstallations
121
101
  - FirebaseSessions
122
- - FirebaseStorage
123
102
  - GoogleDataTransport
124
103
  - GoogleUtilities
125
- - GTMSessionFetcher
126
104
  - nanopb
127
105
  - PromisesObjC
128
106
  - PromisesSwift
@@ -134,8 +112,6 @@ EXTERNAL SOURCES:
134
112
  :path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos
135
113
  firebase_crashlytics:
136
114
  :path: Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos
137
- firebase_storage:
138
- :path: Flutter/ephemeral/.symlinks/plugins/firebase_storage/macos
139
115
  FlutterMacOS:
140
116
  :path: Flutter/ephemeral
141
117
  just_audio:
@@ -156,20 +132,15 @@ SPEC CHECKSUMS:
156
132
  Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0
157
133
  firebase_core: ff59797157ca9adda4440071643761b41fcd03b3
158
134
  firebase_crashlytics: 223f1e85437fa85822439e51db3cd0be7dd35b23
159
- firebase_storage: d873afdc6a0b5307ffa2bb4a5ca9282cb0b922f3
160
- FirebaseAppCheckInterop: 5e12dc623d443dedffcde9c6f3ed41510125d8ef
161
- FirebaseAuthInterop: 74875bde5d15636522a8fe98beb561df7a54db58
162
135
  FirebaseCore: f86a1394906b97ac445ae49c92552a9425831bed
163
136
  FirebaseCoreExtension: ce60f9db46d83944cf444664d6d587474128eeca
164
137
  FirebaseCoreInternal: b342e37cd4f5b4454ec34308f073420e7920858e
165
138
  FirebaseCrashlytics: c4d111b7430c49744c74bcc6346ea00868661ac8
166
139
  FirebaseInstallations: b28af1b9f997f1a799efe818c94695a3728c352f
167
140
  FirebaseSessions: 991fb4c20b3505eef125f7cbfa20a5b5b189c2a4
168
- FirebaseStorage: 1d7ca8c8953fc61ccacaa7c612696b5402968a0d
169
141
  FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
170
142
  GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
171
143
  GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084
172
- GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
173
144
  just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
174
145
  nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
175
146
  package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce