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


5eb27b64 pyrossh

2 years ago
improve state
lib/app.dart CHANGED
@@ -1,7 +1,5 @@
1
1
  import "package:flutter/material.dart";
2
- import "package:flutter_bloc/flutter_bloc.dart";
3
2
  import "package:flutter_gen/gen_l10n/app_localizations.dart";
4
- import "package:only_bible_app/blocs/bible_bloc.dart";
5
3
  import "package:only_bible_app/screens/bible_select_screen.dart";
6
4
  import "package:only_bible_app/screens/chapter_view_screen.dart";
7
5
  import "package:only_bible_app/state.dart";
@@ -14,39 +12,29 @@ class App extends StatelessWidget {
14
12
 
15
13
  @override
16
14
  Widget build(BuildContext context) {
17
- return BlocProvider<BibleBloc>(
15
+ return MaterialApp(
18
- create: (context) => BibleBloc(null)
16
+ onGenerateTitle: (context) => context.l.title,
19
- ..add(
20
- firstOpen.value ? const BibleEvent.firstLoad() : BibleEvent.load(bibleName.value),
17
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
18
+ supportedLocales: AppLocalizations.supportedLocales,
19
+ debugShowCheckedModeBanner: false,
20
+ themeMode: darkMode.watch(context) ? ThemeMode.dark : ThemeMode.light,
21
+ theme: lightTheme,
22
+ darkTheme: darkTheme,
23
+ locale: Locale(languageCode.watch(context)),
24
+ // initialRoute: "",
25
+ routes: {
26
+ // TODO: maybe have a landing page
27
+ // "/": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
28
+ "/privacy-policy": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
29
+ "/about-us": (context) => const ScaffoldMarkdown(title: "About Us", file: "about-us.md"),
30
+ },
31
+ home: firstOpen.value
32
+ ? const BibleSelectScreen()
33
+ : ChapterViewScreen(
34
+ bibleName: bibleName.value,
35
+ bookIndex: savedBook.value,
36
+ chapterIndex: savedChapter.value,
21
- ),
37
+ ),
22
- child: Builder(
23
- builder: (context) {
24
- return MaterialApp(
25
- onGenerateTitle: (context) => context.l.title,
26
- localizationsDelegates: AppLocalizations.localizationsDelegates,
27
- supportedLocales: AppLocalizations.supportedLocales,
28
- debugShowCheckedModeBanner: false,
29
- themeMode: darkMode.watch(context) ? ThemeMode.dark : ThemeMode.light,
30
- theme: lightTheme,
31
- darkTheme: darkTheme,
32
- locale: Locale(languageCode.watch(context)),
33
- // initialRoute: "",
34
- routes: {
35
- // TODO: maybe have a landing page
36
- // "/": (context) => const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
37
- "/privacy-policy": (context) =>
38
- const ScaffoldMarkdown(title: "Privacy Policy", file: "privacy-policy.md"),
39
- "/about-us": (context) => const ScaffoldMarkdown(title: "About Us", file: "about-us.md"),
40
- },
41
- home: firstOpen.value
42
- ? const BibleSelectScreen()
43
- : ChapterViewScreen(
44
- bookIndex: savedBook.value,
45
- chapterIndex: savedChapter.value,
46
- ),
47
- );
48
- },
49
- ),
50
38
  );
51
39
  }
52
40
  }
lib/atom.dart CHANGED
@@ -65,41 +65,18 @@ class _ListenerWrapper {
65
65
  void Function()? listener;
66
66
  }
67
67
 
68
- class AsyncAtom<T> extends ValueNotifier<T> {
68
+ class AsyncAtom<P extends String, E extends Future> {
69
+ final Map<P, E> cache = {};
69
- final T Function(T) callback;
70
+ final E Function(P) callback;
70
71
 
71
- AsyncAtom(super._value, this.callback);
72
+ AsyncAtom({required this.callback});
72
73
 
73
- @override
74
- get value {
74
+ E getValue(P param) {
75
+ if (cache.containsKey(param)) {
75
- return callback(this.value);
76
+ return cache[param]!;
76
- }
77
+ }
77
-
78
- T watch(BuildContext context) {
79
- final elementRef = WeakReference(context as Element);
80
- final listenerWrapper = _ListenerWrapper();
78
+ final v = callback(param);
81
- listenerWrapper.listener = () {
82
- assert(
83
- SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks,
84
- """
79
+ cache[param] = v;
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;
80
+ return v;
104
81
  }
105
- }
82
+ }
lib/blocs/bible_bloc.dart DELETED
@@ -1,28 +0,0 @@
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 DELETED
@@ -1,725 +0,0 @@
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 DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,8 +0,0 @@
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/models.dart CHANGED
@@ -1,18 +1,17 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:freezed_annotation/freezed_annotation.dart";
2
3
  import "package:only_bible_app/utils.dart";
4
+ part "models.freezed.dart";
3
5
 
6
+ @freezed
4
- class Bible {
7
+ class Bible with _$Bible {
5
- final String name;
6
- List<Book> books = [];
7
8
 
8
- Bible({
9
+ const Bible._();
9
- required this.name,
10
- });
11
10
 
12
- Bible.withBooks({
11
+ const factory Bible({
13
- required this.name,
12
+ required String name,
14
- required this.books,
13
+ required List<Book> books,
15
- });
14
+ }) = _Bible;
16
15
 
17
16
  String shortName() {
18
17
  return name.substring(0, 3).toUpperCase();
@@ -99,22 +98,22 @@ List<Book> getBibleFromText(String bibleName, String text) {
99
98
  }
100
99
  if (books[book - 1].chapters.length < chapter) {
101
100
  books[book - 1].chapters.add(
102
- Chapter(
101
+ Chapter(
103
- index: chapter - 1,
102
+ index: chapter - 1,
104
- book: book - 1,
103
+ book: book - 1,
105
- verses: [],
104
+ verses: [],
106
- ),
105
+ ),
107
- );
106
+ );
108
107
  }
109
108
  books[book - 1].chapters[chapter - 1].verses.add(
110
- Verse(
109
+ Verse(
111
- index: verseNo - 1,
110
+ index: verseNo - 1,
112
- text: verseText,
111
+ text: verseText,
113
- bibleName: bibleName,
112
+ bibleName: bibleName,
114
- chapter: chapter - 1,
113
+ chapter: chapter - 1,
115
- book: book - 1,
114
+ book: book - 1,
116
- ),
115
+ ),
117
- );
116
+ );
118
117
  }
119
118
  return books;
120
119
  }
lib/models.freezed.dart ADDED
@@ -0,0 +1,152 @@
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 'models.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 _$Bible {
19
+ String get name => throw _privateConstructorUsedError;
20
+ List<Book> get books => throw _privateConstructorUsedError;
21
+
22
+ @JsonKey(ignore: true)
23
+ $BibleCopyWith<Bible> get copyWith => throw _privateConstructorUsedError;
24
+ }
25
+
26
+ /// @nodoc
27
+ abstract class $BibleCopyWith<$Res> {
28
+ factory $BibleCopyWith(Bible value, $Res Function(Bible) then) =
29
+ _$BibleCopyWithImpl<$Res, Bible>;
30
+ @useResult
31
+ $Res call({String name, List<Book> books});
32
+ }
33
+
34
+ /// @nodoc
35
+ class _$BibleCopyWithImpl<$Res, $Val extends Bible>
36
+ implements $BibleCopyWith<$Res> {
37
+ _$BibleCopyWithImpl(this._value, this._then);
38
+
39
+ // ignore: unused_field
40
+ final $Val _value;
41
+ // ignore: unused_field
42
+ final $Res Function($Val) _then;
43
+
44
+ @pragma('vm:prefer-inline')
45
+ @override
46
+ $Res call({
47
+ Object? name = null,
48
+ Object? books = null,
49
+ }) {
50
+ return _then(_value.copyWith(
51
+ name: null == name
52
+ ? _value.name
53
+ : name // ignore: cast_nullable_to_non_nullable
54
+ as String,
55
+ books: null == books
56
+ ? _value.books
57
+ : books // ignore: cast_nullable_to_non_nullable
58
+ as List<Book>,
59
+ ) as $Val);
60
+ }
61
+ }
62
+
63
+ /// @nodoc
64
+ abstract class _$$_BibleCopyWith<$Res> implements $BibleCopyWith<$Res> {
65
+ factory _$$_BibleCopyWith(_$_Bible value, $Res Function(_$_Bible) then) =
66
+ __$$_BibleCopyWithImpl<$Res>;
67
+ @override
68
+ @useResult
69
+ $Res call({String name, List<Book> books});
70
+ }
71
+
72
+ /// @nodoc
73
+ class __$$_BibleCopyWithImpl<$Res> extends _$BibleCopyWithImpl<$Res, _$_Bible>
74
+ implements _$$_BibleCopyWith<$Res> {
75
+ __$$_BibleCopyWithImpl(_$_Bible _value, $Res Function(_$_Bible) _then)
76
+ : super(_value, _then);
77
+
78
+ @pragma('vm:prefer-inline')
79
+ @override
80
+ $Res call({
81
+ Object? name = null,
82
+ Object? books = null,
83
+ }) {
84
+ return _then(_$_Bible(
85
+ name: null == name
86
+ ? _value.name
87
+ : name // ignore: cast_nullable_to_non_nullable
88
+ as String,
89
+ books: null == books
90
+ ? _value._books
91
+ : books // ignore: cast_nullable_to_non_nullable
92
+ as List<Book>,
93
+ ));
94
+ }
95
+ }
96
+
97
+ /// @nodoc
98
+
99
+ class _$_Bible extends _Bible {
100
+ const _$_Bible({required this.name, required final List<Book> books})
101
+ : _books = books,
102
+ super._();
103
+
104
+ @override
105
+ final String name;
106
+ final List<Book> _books;
107
+ @override
108
+ List<Book> get books {
109
+ if (_books is EqualUnmodifiableListView) return _books;
110
+ // ignore: implicit_dynamic_type
111
+ return EqualUnmodifiableListView(_books);
112
+ }
113
+
114
+ @override
115
+ String toString() {
116
+ return 'Bible(name: $name, books: $books)';
117
+ }
118
+
119
+ @override
120
+ bool operator ==(dynamic other) {
121
+ return identical(this, other) ||
122
+ (other.runtimeType == runtimeType &&
123
+ other is _$_Bible &&
124
+ (identical(other.name, name) || other.name == name) &&
125
+ const DeepCollectionEquality().equals(other._books, _books));
126
+ }
127
+
128
+ @override
129
+ int get hashCode => Object.hash(
130
+ runtimeType, name, const DeepCollectionEquality().hash(_books));
131
+
132
+ @JsonKey(ignore: true)
133
+ @override
134
+ @pragma('vm:prefer-inline')
135
+ _$$_BibleCopyWith<_$_Bible> get copyWith =>
136
+ __$$_BibleCopyWithImpl<_$_Bible>(this, _$identity);
137
+ }
138
+
139
+ abstract class _Bible extends Bible {
140
+ const factory _Bible(
141
+ {required final String name, required final List<Book> books}) = _$_Bible;
142
+ const _Bible._() : super._();
143
+
144
+ @override
145
+ String get name;
146
+ @override
147
+ List<Book> get books;
148
+ @override
149
+ @JsonKey(ignore: true)
150
+ _$$_BibleCopyWith<_$_Bible> get copyWith =>
151
+ throw _privateConstructorUsedError;
152
+ }
lib/navigation.dart CHANGED
@@ -81,7 +81,7 @@ updateStatusBar(bool v) {
81
81
  }
82
82
  }
83
83
 
84
- pushBookChapter(BuildContext context, int book, int chapter, TextDirection? dir) {
84
+ pushBookChapter(BuildContext context, String bibleName, int book, int chapter, TextDirection? dir) {
85
85
  savedBook.update!(book);
86
86
  savedChapter.update!(chapter);
87
87
  clearEvents(context);
@@ -89,18 +89,18 @@ pushBookChapter(BuildContext context, int book, int chapter, TextDirection? dir)
89
89
  createSlideRoute(
90
90
  context: context,
91
91
  slideDir: dir,
92
- page: ChapterViewScreen(bookIndex: book, chapterIndex: chapter),
92
+ page: ChapterViewScreen(bibleName: bibleName, bookIndex: book, chapterIndex: chapter),
93
93
  ),
94
94
  );
95
95
  }
96
96
 
97
- replaceBookChapter(BuildContext context, int book, int chapter) {
97
+ replaceBookChapter(BuildContext context, String bibleName, int book, int chapter) {
98
98
  savedBook.update!(book);
99
99
  savedChapter.update!(chapter);
100
100
  clearEvents(context);
101
101
  Navigator.of(context).pushReplacement(
102
102
  createNoTransitionPageRoute(
103
- ChapterViewScreen(bookIndex: book, chapterIndex: chapter),
103
+ ChapterViewScreen(bibleName: bibleName, bookIndex: book, chapterIndex: chapter),
104
104
  ),
105
105
  );
106
106
  }
@@ -108,11 +108,11 @@ replaceBookChapter(BuildContext context, int book, int chapter) {
108
108
  nextChapter(BuildContext context, Bible bible, int book, int chapter) {
109
109
  final selectedBook = bible.books[book];
110
110
  if (selectedBook.chapters.length > chapter + 1) {
111
- pushBookChapter(context, selectedBook.index, chapter + 1, TextDirection.ltr);
111
+ pushBookChapter(context, bible.name, selectedBook.index, chapter + 1, TextDirection.ltr);
112
112
  } else {
113
113
  if (selectedBook.index + 1 < bible.books.length) {
114
114
  final nextBook = bible.books[selectedBook.index + 1];
115
- pushBookChapter(context, nextBook.index, 0, TextDirection.ltr);
115
+ pushBookChapter(context, bible.name, nextBook.index, 0, TextDirection.ltr);
116
116
  }
117
117
  }
118
118
  }
@@ -123,12 +123,12 @@ previousChapter(BuildContext context, Bible bible, int book, int chapter) {
123
123
  // if (Navigator.of(context).canPop()) {
124
124
  // Navigator.of(context).pop();
125
125
  // } else {
126
- pushBookChapter(context, selectedBook.index, chapter - 1, TextDirection.rtl);
126
+ pushBookChapter(context, bible.name, selectedBook.index, chapter - 1, TextDirection.rtl);
127
127
  // }
128
128
  } else {
129
129
  if (selectedBook.index - 1 >= 0) {
130
130
  final prevBook = bible.books[selectedBook.index - 1];
131
- pushBookChapter(context, prevBook.index, prevBook.chapters.length - 1, TextDirection.rtl);
131
+ pushBookChapter(context, bible.name, prevBook.index, prevBook.chapters.length - 1, TextDirection.rtl);
132
132
  }
133
133
  }
134
134
  }
@@ -208,24 +208,24 @@ shareVerses(BuildContext context, Bible bible, List<Verse> verses) {
208
208
  Share.share("$title\n$text", subject: title);
209
209
  }
210
210
 
211
- showSettings(BuildContext context) {
211
+ showSettings(BuildContext context, Bible bible) {
212
212
  showModalBottomSheet(
213
213
  context: context,
214
214
  isDismissible: true,
215
215
  enableDrag: true,
216
216
  showDragHandle: true,
217
217
  useSafeArea: true,
218
- builder: (context) => const SettingsSheet(),
218
+ builder: (context) => SettingsSheet(bible: bible),
219
219
  );
220
220
  }
221
221
 
222
- showActions(BuildContext context) {
222
+ showActions(BuildContext context, Bible bible) {
223
223
  if (!actionsShown.value) {
224
224
  actionsShown.value = true;
225
225
  Scaffold.of(context).showBottomSheet(
226
226
  enableDrag: false,
227
227
  clipBehavior: Clip.antiAliasWithSaveLayer,
228
- (context) => const ActionsSheet(),
228
+ (context) => ActionsSheet(bible: bible),
229
229
  );
230
230
  }
231
231
  }
@@ -254,7 +254,7 @@ hideHighlights(BuildContext context) {
254
254
  }
255
255
  }
256
256
 
257
- showNoteField(BuildContext context, Verse v) {
257
+ showNoteField(BuildContext context, Bible bible, Verse v) {
258
258
  final noteText = box.read("${v.book}:${v.chapter}:${v.index}:note") ?? "";
259
259
  noteTextController.text = noteText;
260
260
  showModalBottomSheet(
@@ -264,7 +264,7 @@ showNoteField(BuildContext context, Verse v) {
264
264
  showDragHandle: true,
265
265
  useSafeArea: true,
266
266
  isScrollControlled: true,
267
- builder: (context) => NoteSheet(verse: v),
267
+ builder: (context) => NoteSheet(bible: bible, verse: v),
268
268
  );
269
269
  }
270
270
 
lib/screens/bible_select_screen.dart CHANGED
@@ -1,7 +1,4 @@
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/navigation.dart";
5
2
  import "package:only_bible_app/state.dart";
6
3
  import "package:only_bible_app/utils.dart";
7
4
  import "package:only_bible_app/widgets/scaffold_menu.dart";
@@ -31,14 +28,10 @@ class BibleSelectScreen extends StatelessWidget {
31
28
  // ],
32
29
  // ),
33
30
  onPressed: () {
34
- context.read<BibleBloc>().add(BibleEvent.load(l.languageTitle));
35
- updateCurrentBible(context, Locale(l.localeName), l.languageTitle);
36
31
  if (firstOpen.value) {
37
32
  firstOpen.set!();
38
- pushBookChapter(context, 0, 0, null);
39
- } else {
33
+ } else {}
40
- Navigator.of(context).pop();
34
+ updateCurrentBible(context, l.localeName, l.languageTitle);
41
- }
42
35
  },
43
36
  );
44
37
  }),
lib/screens/book_select_screen.dart CHANGED
@@ -18,6 +18,7 @@ class BookSelectScreen extends StatelessWidget {
18
18
  transitionDuration: Duration.zero,
19
19
  reverseTransitionDuration: Duration.zero,
20
20
  pageBuilder: (context, _, __) => ChapterSelectScreen(
21
+ bible: bible,
21
22
  book: bible.books[index],
22
23
  selectedBookIndex: index,
23
24
  ),
lib/screens/chapter_select_screen.dart CHANGED
@@ -6,10 +6,11 @@ import "package:only_bible_app/widgets/sliver_tile_grid.dart";
6
6
  import "package:only_bible_app/widgets/sliver_heading.dart";
7
7
 
8
8
  class ChapterSelectScreen extends StatelessWidget {
9
+ final Bible bible;
9
10
  final Book book;
10
11
  final int selectedBookIndex;
11
12
 
12
- const ChapterSelectScreen({super.key, required this.selectedBookIndex, required this.book});
13
+ const ChapterSelectScreen({super.key, required this.bible, required this.selectedBookIndex, required this.book});
13
14
 
14
15
  @override
15
16
  Widget build(BuildContext context) {
@@ -22,7 +23,7 @@ class ChapterSelectScreen extends StatelessWidget {
22
23
  children: List.generate(book.chapters.length, (index) {
23
24
  return TextButton(
24
25
  child: Text("${index + 1}"),
25
- onPressed: () => replaceBookChapter(context, selectedBookIndex, index),
26
+ onPressed: () => replaceBookChapter(context, bible.name, selectedBookIndex, index),
26
27
  );
27
28
  }),
28
29
  ),
lib/screens/chapter_view_screen.dart CHANGED
@@ -1,23 +1,65 @@
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
2
  import "package:only_bible_app/models.dart";
3
+ import "package:only_bible_app/state.dart";
5
4
  import "package:only_bible_app/utils.dart";
6
5
  import "package:only_bible_app/widgets/chapter_app_bar.dart";
7
6
  import "package:only_bible_app/widgets/sidebar.dart";
8
7
  import "package:only_bible_app/widgets/verses_view.dart";
9
8
 
10
9
  class ChapterViewScreen extends StatelessWidget {
11
- // final String bibleName;
10
+ final String bibleName;
12
11
  final int bookIndex;
13
12
  final int chapterIndex;
14
13
 
15
- const ChapterViewScreen({super.key, required this.bookIndex, required this.chapterIndex});
14
+ const ChapterViewScreen({super.key, required this.bibleName, required this.bookIndex, required this.chapterIndex});
16
15
 
17
16
  @override
18
17
  Widget build(BuildContext context) {
18
+ return FutureBuilder(
19
+ future: bibleAtom.getValue(bibleName),
19
- return BlocBuilder<BibleBloc, BibleState>(builder: (context, state) {
20
+ builder: (context, state) {
20
- if (!context.isWide) {
21
+ if (context.isWide) {
22
+ return Scaffold(
23
+ backgroundColor: Theme.of(context).colorScheme.background,
24
+ body: Row(
25
+ children: [
26
+ const Sidebar(),
27
+ Flexible(
28
+ child: state.when(
29
+ loading: () => ColoredBox(
30
+ color: Theme.of(context).colorScheme.background,
31
+ child: const Center(
32
+ child: CircularProgressIndicator(),
33
+ ),
34
+ ),
35
+ success: (Bible? bible) {
36
+ final book = bible!.books[bookIndex];
37
+ final chapter = book.chapters[chapterIndex];
38
+ return Column(
39
+ children: [
40
+ ChapterAppBar(bible: bible, book: book, chapter: chapter),
41
+ const Padding(
42
+ padding: EdgeInsets.only(bottom: 10),
43
+ child: Divider(height: 5, indent: 20, endIndent: 20, thickness: 1.5),
44
+ ),
45
+ Flexible(
46
+ child: VersesView(bible: bible, chapter: chapter),
47
+ ),
48
+ ],
49
+ );
50
+ },
51
+ error: () => ColoredBox(
52
+ color: Theme.of(context).colorScheme.background,
53
+ child: const Center(
54
+ child: Text("Could not load the bible"),
55
+ ),
56
+ ),
57
+ ),
58
+ ),
59
+ ],
60
+ ),
61
+ );
62
+ }
21
63
  return state.when(
22
64
  loading: () => ColoredBox(
23
65
  color: Theme.of(context).colorScheme.background,
@@ -25,14 +67,14 @@ class ChapterViewScreen extends StatelessWidget {
25
67
  child: CircularProgressIndicator(),
26
68
  ),
27
69
  ),
28
- success: (Bible bible) {
70
+ success: (Bible? bible) {
29
- final book = bible.books[bookIndex];
71
+ final book = bible!.books[bookIndex];
30
72
  final chapter = book.chapters[chapterIndex];
31
73
  return Scaffold(
32
- appBar: ChapterAppBar(book: book, chapter: chapter),
74
+ appBar: ChapterAppBar(bible: bible, book: book, chapter: chapter),
33
75
  backgroundColor: Theme.of(context).colorScheme.background,
34
76
  body: SafeArea(
35
- child: VersesView(chapter: chapter),
77
+ child: VersesView(bible: bible, chapter: chapter),
36
78
  ),
37
79
  );
38
80
  },
@@ -43,47 +85,7 @@ class ChapterViewScreen extends StatelessWidget {
43
85
  ),
44
86
  ),
45
87
  );
46
- }
47
- return Scaffold(
48
- backgroundColor: Theme.of(context).colorScheme.background,
49
- body: Row(
50
- children: [
51
- const Sidebar(),
52
- Flexible(
53
- child: state.when(
54
- loading: () => ColoredBox(
55
- color: Theme.of(context).colorScheme.background,
56
- child: const Center(
57
- child: CircularProgressIndicator(),
58
- ),
88
+ },
59
- ),
60
- success: (Bible bible) {
61
- final book = bible.books[bookIndex];
62
- final chapter = book.chapters[chapterIndex];
63
- return Column(
64
- children: [
65
- ChapterAppBar(book: book, chapter: chapter),
66
- const Padding(
67
- padding: EdgeInsets.only(bottom: 10),
68
- child: Divider(height: 5, indent: 20, endIndent: 20, thickness: 1.5),
69
- ),
70
- Flexible(
71
- child: VersesView(chapter: chapter),
72
- ),
73
- ],
74
- );
89
+ );
75
- },
76
- error: () => ColoredBox(
77
- color: Theme.of(context).colorScheme.background,
78
- child: const Center(
79
- child: Text("Could not load the bible"),
80
- ),
81
- ),
82
- ),
83
- ),
84
- ],
85
- ),
86
- );
87
- });
88
90
  }
89
91
  }
lib/sheets/actions_sheet.dart CHANGED
@@ -1,11 +1,13 @@
1
1
  import "package:flutter/material.dart";
2
2
  import "package:only_bible_app/dialog.dart";
3
+ import "package:only_bible_app/models.dart";
3
4
  import "package:only_bible_app/navigation.dart";
4
5
  import "package:only_bible_app/state.dart";
5
6
  import "package:only_bible_app/utils.dart";
6
7
 
7
8
  class ActionsSheet extends StatelessWidget {
9
+ final Bible bible;
8
- const ActionsSheet({super.key});
10
+ const ActionsSheet({super.key, required this.bible});
9
11
 
10
12
  @override
11
13
  Widget build(BuildContext context) {
@@ -34,7 +36,7 @@ class ActionsSheet extends StatelessWidget {
34
36
  padding: EdgeInsets.zero,
35
37
  onPressed: () {
36
38
  if (audioEnabled) {
37
- onPlay(context);
39
+ onPlay(context, bible);
38
40
  } else {
39
41
  showError(context, context.l.audioNotAvailable);
40
42
  }
@@ -43,12 +45,12 @@ class ActionsSheet extends StatelessWidget {
43
45
  ),
44
46
  IconButton(
45
47
  padding: EdgeInsets.zero,
46
- onPressed: () => showNoteField(context, selectedVerses.value.first),
48
+ onPressed: () => showNoteField(context, bible, selectedVerses.value.first),
47
49
  icon: Icon(Icons.post_add_outlined, size: 34, color: iconColor),
48
50
  ),
49
51
  IconButton(
50
52
  padding: EdgeInsets.zero,
51
- onPressed: () => shareVerses(context, bible.value, selectedVerses.value),
53
+ onPressed: () => shareVerses(context, bible, selectedVerses.value),
52
54
  icon: Icon(Icons.share_outlined, size: 34, color: iconColor),
53
55
  ),
54
56
  ],
lib/sheets/settings_sheet.dart CHANGED
@@ -1,11 +1,13 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:only_bible_app/models.dart";
2
3
  import "package:only_bible_app/navigation.dart";
3
4
  import "package:only_bible_app/state.dart";
4
5
  import "package:only_bible_app/utils.dart";
5
6
  import "package:settings_ui/settings_ui.dart";
6
7
 
7
8
  class SettingsSheet extends StatelessWidget {
9
+ final Bible bible;
8
- const SettingsSheet({super.key});
10
+ const SettingsSheet({super.key, required this.bible});
9
11
 
10
12
  @override
11
13
  Widget build(BuildContext context) {
@@ -26,7 +28,7 @@ class SettingsSheet extends StatelessWidget {
26
28
  SettingsTile.navigation(
27
29
  leading: const Icon(Icons.book_outlined, color: Colors.blueAccent),
28
30
  title: Text(context.l.bibleTitle),
29
- value: Text(bible.watch(context).name),
31
+ value: Text(bible.name),
30
32
  onPressed: changeBible,
31
33
  ),
32
34
  SettingsTile.navigation(
lib/state.dart CHANGED
@@ -20,6 +20,10 @@ initState() async {
20
20
  await box.initStorage;
21
21
  }
22
22
 
23
+ final bibleAtom = AsyncAtom(
24
+ callback: loadBible,
25
+ );
26
+
23
27
  final Atom<bool> firstOpen = Atom<bool>(
24
28
  box: box,
25
29
  key: "firstOpen",
@@ -47,36 +51,23 @@ final Atom<String> bibleName = Atom<String>(
47
51
  },
48
52
  );
49
53
 
50
- final Atom<Bible> bible = Atom<Bible>(
51
- key: "bible",
52
- initialValue: Bible(name: "English"),
53
- update: (Bible v) {
54
- bible.value = v;
55
- },
56
- );
57
-
58
- updateCurrentBible(BuildContext context, Locale l, String name) async {
54
+ updateCurrentBible(BuildContext context, String code, String name) async {
59
55
  hideActions(context);
60
- languageCode.value = l.languageCode;
56
+ languageCode.value = code;
61
57
  bibleName.update!(name);
58
+ pushBookChapter(context, name, 0, 0, null);
62
59
  }
63
60
 
64
- Future<Bible> getBibleFromAsset(String bibleName) async {
61
+ Future<Bible> loadBible(String name) async {
65
- final bytes = await rootBundle.load("assets/bibles/$bibleName.txt");
62
+ final bytes = await rootBundle.load("assets/bibles/$name.txt");
66
- final books = getBibleFromText(bibleName, utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
63
+ final books = getBibleFromText(name, utf8.decode(bytes.buffer.asUint8List(), allowMalformed: false));
67
- // await Future.delayed(Duration(seconds: 1));
64
+ // await Future.delayed(Duration(seconds: 2));
68
- return Bible.withBooks(
65
+ return Bible(
69
- name: bibleName,
66
+ name: name,
70
67
  books: books,
71
68
  );
72
69
  }
73
70
 
74
- Future<Bible?> loadBible(String name) async {
75
- return getBibleFromAsset(name).then((value) {
76
- bible.update!(value);
77
- return value;
78
- });
79
- }
80
71
  // Trace customTrace;
81
72
  // if (!isDesktop()) {
82
73
  // customTrace = FirebasePerformance.instance.newTrace("loadBible");
@@ -201,14 +192,14 @@ bool watchVerseSelected(BuildContext context, Verse v) {
201
192
  return selectedVerses.watch(context).any((el) => el.book == v.book && el.chapter == v.chapter && el.index == v.index);
202
193
  }
203
194
 
204
- void onVerseSelected(BuildContext context, Verse v) {
195
+ void onVerseSelected(BuildContext context, Bible bible, Verse v) {
205
196
  if (isVerseSelected(v)) {
206
197
  selectedVerses.update!(selectedVerses.value.removeBy((it) => it.index == v.index).toList());
207
198
  } else {
208
199
  selectedVerses.update!(selectedVerses.value.addBy(v).toList());
209
200
  }
210
201
  if (selectedVerses.value.isNotEmpty) {
211
- showActions(context);
202
+ showActions(context, bible);
212
203
  }
213
204
  if (selectedVerses.value.isEmpty) {
214
205
  hideActions(context);
@@ -269,14 +260,14 @@ class BufferAudioSource extends StreamAudioSource {
269
260
  }
270
261
  }
271
262
 
272
- onPlay(BuildContext context) async {
263
+ onPlay(BuildContext context, Bible bible) async {
273
264
  final versesToPlay = List<Verse>.from(selectedVerses.value);
274
265
  if (isPlaying.value) {
275
266
  pause();
276
267
  } else {
277
268
  isPlaying.value = true;
278
269
  for (final v in versesToPlay) {
279
- final pathname = "${bibleName.value}|${v.book}|${v.chapter}|${v.index}";
270
+ final pathname = "${bible.name}|${v.book}|${v.chapter}|${v.index}";
280
271
  try {
281
272
  final list = await convertText(context.l.audioVoice, v.text);
282
273
  await player.setAudioSource(BufferAudioSource(list));
lib/utils.dart CHANGED
@@ -7,7 +7,7 @@ import "package:flutter/material.dart";
7
7
  import "package:flutter_gen/gen_l10n/app_localizations.dart";
8
8
  import "package:flutter_azure_tts/flutter_azure_tts.dart";
9
9
 
10
- extension MyIterable<E> on Iterable<E> {
10
+ extension IterableUtils<E> on Iterable<E> {
11
11
  Iterable<E> sortedBy(Comparable Function(E e) key) => toList()..sort((a, b) => key(a).compareTo(key(b)));
12
12
 
13
13
  Iterable<E> removeBy(bool Function(E e) key) => toList()..removeWhere(key);
@@ -15,6 +15,22 @@ extension MyIterable<E> on Iterable<E> {
15
15
  Iterable<E> addBy(E e) => toList()..add(e);
16
16
  }
17
17
 
18
+ extension AsyncSnapshotUtils<E> on AsyncSnapshot<E> {
19
+ TResult when<TResult extends Object?>({
20
+ required TResult Function() loading,
21
+ required TResult Function(E? v) success,
22
+ required TResult Function() error,
23
+ }) {
24
+ if (hasError) {
25
+ return error();
26
+ }
27
+ if (connectionState == ConnectionState.done) {
28
+ return success(data);
29
+ }
30
+ return loading();
31
+ }
32
+ }
33
+
18
34
  extension AppContext on BuildContext {
19
35
  ThemeData get theme => Theme.of(this);
20
36
 
lib/widgets/chapter_app_bar.dart CHANGED
@@ -5,10 +5,11 @@ import "package:only_bible_app/state.dart";
5
5
  import "package:only_bible_app/utils.dart";
6
6
 
7
7
  class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
8
+ final Bible bible;
8
9
  final Book book;
9
10
  final Chapter chapter;
10
11
 
11
- const ChapterAppBar({super.key, required this.book, required this.chapter});
12
+ const ChapterAppBar({super.key, required this.book, required this.chapter, required this.bible});
12
13
 
13
14
  @override
14
15
  Size get preferredSize => const Size.fromHeight(40);
@@ -26,7 +27,7 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
26
27
  children: [
27
28
  InkWell(
28
29
  enableFeedback: true,
29
- onTap: () => changeBook(context, bible.value),
30
+ onTap: () => changeBook(context, bible),
30
31
  child: Row(
31
32
  children: [
32
33
  Text(
@@ -57,7 +58,7 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
57
58
  ),
58
59
  icon: const Icon(Icons.chevron_left),
59
60
  label: const Text("Prev"),
60
- onPressed: () => previousChapter(context, bible.value, book.index, chapter.index),
61
+ onPressed: () => previousChapter(context, bible, book.index, chapter.index),
61
62
  ),
62
63
  if (isDesktop) const SizedBox(width: 10),
63
64
  if (isDesktop)
@@ -71,7 +72,7 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
71
72
  ),
72
73
  icon: const Icon(Icons.chevron_right),
73
74
  label: const Text("Next"),
74
- onPressed: () => nextChapter(context, bible.value, book.index, chapter.index),
75
+ onPressed: () => nextChapter(context, bible, book.index, chapter.index),
75
76
  ),
76
77
  if (isDesktop) const SizedBox(width: 20),
77
78
  if (isDesktop)
@@ -89,7 +90,7 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
89
90
  ),
90
91
  ),
91
92
  icon: const Icon(Icons.book_outlined),
92
- label: Text(bible.watch(context).name),
93
+ label: Text(bible.name),
93
94
  onPressed: () => changeBibleFromHeader(context),
94
95
  ),
95
96
  Padding(
@@ -97,7 +98,7 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
97
98
  child: IconButton(
98
99
  padding: EdgeInsets.zero,
99
100
  icon: Icon(Icons.more_vert, size: isDesktop ? 28 : 24),
100
- onPressed: () => showSettings(context),
101
+ onPressed: () => showSettings(context, bible),
101
102
  ),
102
103
  ),
103
104
  ],
lib/widgets/note_sheet.dart CHANGED
@@ -4,9 +4,10 @@ import "package:only_bible_app/state.dart";
4
4
  import "package:only_bible_app/widgets/modal_button.dart";
5
5
 
6
6
  class NoteSheet extends StatelessWidget {
7
+ final Bible bible;
7
8
  final Verse verse;
8
9
 
9
- const NoteSheet({super.key, required this.verse});
10
+ const NoteSheet({super.key, required this.verse, required this.bible});
10
11
 
11
12
  @override
12
13
  Widget build(BuildContext context) {
@@ -23,7 +24,7 @@ class NoteSheet extends StatelessWidget {
23
24
  Padding(
24
25
  padding: const EdgeInsets.only(bottom: 5, left: 15),
25
26
  child: Text(
26
- "Note on ${bible.watch(context).books[verse.book].name(context)} ${verse.chapter + 1}:${verse.index + 1}",
27
+ "Note on ${bible.books[verse.book].name(context)} ${verse.chapter + 1}:${verse.index + 1}",
27
28
  style: Theme.of(context).textTheme.headlineMedium,
28
29
  ),
29
30
  ),
lib/widgets/verses_view.dart CHANGED
@@ -6,19 +6,20 @@ import "package:only_bible_app/navigation.dart";
6
6
  import "package:only_bible_app/state.dart";
7
7
 
8
8
  class VersesView extends StatelessWidget {
9
+ final Bible bible;
9
10
  final Chapter chapter;
10
11
 
11
- const VersesView({super.key, required this.chapter});
12
+ const VersesView({super.key, required this.bible, required this.chapter});
12
13
 
13
14
  @override
14
15
  Widget build(BuildContext context) {
15
16
  final textStyle = DefaultTextStyle.of(context).style;
16
17
  return SwipeDetector(
17
18
  onSwipeLeft: (offset) {
18
- nextChapter(context, bible.value, chapter.book, chapter.index);
19
+ nextChapter(context, bible, chapter.book, chapter.index);
19
20
  },
20
21
  onSwipeRight: (offset) {
21
- previousChapter(context, bible.value, chapter.book, chapter.index);
22
+ previousChapter(context, bible, chapter.book, chapter.index);
22
23
  },
23
24
  child: SingleChildScrollView(
24
25
  physics: const BouncingScrollPhysics(),
@@ -57,7 +58,7 @@ class VersesView extends StatelessWidget {
57
58
  padding: const EdgeInsets.only(left: 3, right: 3),
58
59
  child: GestureDetector(
59
60
  onTap: () {
60
- showNoteField(context, v);
61
+ showNoteField(context, bible, v);
61
62
  },
62
63
  child: const Icon(
63
64
  Icons.sticky_note_2_outlined,
@@ -72,7 +73,7 @@ class VersesView extends StatelessWidget {
72
73
  style: getHighlightStyle(context, v),
73
74
  recognizer: TapGestureRecognizer()
74
75
  ..onTap = () {
75
- onVerseSelected(context, v);
76
+ onVerseSelected(context, bible, v);
76
77
  },
77
78
  ),
78
79
  const WidgetSpan(
pubspec.lock CHANGED
@@ -57,14 +57,6 @@ packages:
57
57
  url: "https://pub.dev"
58
58
  source: hosted
59
59
  version: "0.1.16"
60
- bloc:
61
- dependency: "direct main"
62
- description:
63
- name: bloc
64
- sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
65
- url: "https://pub.dev"
66
- source: hosted
67
- version: "8.1.2"
68
60
  boolean_selector:
69
61
  dependency: transitive
70
62
  description:
@@ -366,14 +358,6 @@ packages:
366
358
  url: "https://pub.dev"
367
359
  source: hosted
368
360
  version: "0.1.6"
369
- flutter_bloc:
370
- dependency: "direct main"
371
- description:
372
- name: flutter_bloc
373
- sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
374
- url: "https://pub.dev"
375
- source: hosted
376
- version: "8.1.3"
377
361
  flutter_dotenv:
378
362
  dependency: "direct main"
379
363
  description:
@@ -387,6 +371,14 @@ packages:
387
371
  description: flutter
388
372
  source: sdk
389
373
  version: "0.0.0"
374
+ flutter_hooks:
375
+ dependency: "direct main"
376
+ description:
377
+ name: flutter_hooks
378
+ sha256: "6ae13b1145c589112cbd5c4fda6c65908993a9cb18d4f82042e9c28dd9fbf611"
379
+ url: "https://pub.dev"
380
+ source: hosted
381
+ version: "0.20.1"
390
382
  flutter_launcher_icons:
391
383
  dependency: "direct dev"
392
384
  description:
@@ -684,14 +676,6 @@ packages:
684
676
  url: "https://pub.dev"
685
677
  source: hosted
686
678
  version: "0.0.1"
687
- nested:
688
- dependency: transitive
689
- description:
690
- name: nested
691
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
692
- url: "https://pub.dev"
693
- source: hosted
694
- version: "1.0.0"
695
679
  node_preamble:
696
680
  dependency: transitive
697
681
  description:
@@ -828,14 +812,6 @@ packages:
828
812
  url: "https://pub.dev"
829
813
  source: hosted
830
814
  version: "4.2.4"
831
- provider:
832
- dependency: transitive
833
- description:
834
- name: provider
835
- sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
836
- url: "https://pub.dev"
837
- source: hosted
838
- version: "6.0.5"
839
815
  pub_semver:
840
816
  dependency: transitive
841
817
  description:
pubspec.yaml CHANGED
@@ -16,6 +16,8 @@ dependencies:
16
16
  intl: any
17
17
  path_provider: ^2.0.15
18
18
  just_audio: ^0.9.34
19
+ just_audio_windows: ^0.2.0
20
+ just_audio_mpv: ^0.1.7
19
21
  shared_preferences: ^2.2.0
20
22
  flutter_native_splash: ^2.3.1
21
23
  flutter_swipe_detector: ^2.0.0
@@ -33,11 +35,7 @@ dependencies:
33
35
  flutter_dotenv: ^5.1.0
34
36
  freezed: ^2.4.1
35
37
  freezed_annotation: ^2.4.1
36
- flutter_bloc: ^8.1.3
37
38
  equatable: ^2.0.5
38
- bloc: ^8.1.2
39
- just_audio_windows: ^0.2.0
40
- just_audio_mpv: ^0.1.7
41
39
 
42
40
  dev_dependencies:
43
41
  flutter_test: