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


3c9e3d1c pyrossh

2 years ago
remove old Atom
lib/atom.dart CHANGED
@@ -2,7 +2,7 @@ import "package:flutter/material.dart";
2
2
  import "package:flutter/scheduler.dart";
3
3
  import "package:get_storage/get_storage.dart";
4
4
 
5
- final List<Atom2> atoms = [];
5
+ final List<Atom> atoms = [];
6
6
 
7
7
  void dispatch<T, A>(A a) {
8
8
  for (final atom in atoms) {
@@ -19,13 +19,13 @@ void dispatch<T, A>(A a) {
19
19
  }
20
20
  }
21
21
 
22
- class Atom2<T, A> {
22
+ class Atom<T, A> {
23
23
  late ValueNotifier<T> valueNotifier;
24
24
  final String key;
25
25
  final GetStorage? box;
26
26
  final dynamic Function(dynamic, dynamic) reducer;
27
27
 
28
- Atom2({required this.key, required T initialState, this.box, required this.reducer}) {
28
+ Atom({required this.key, required T initialState, this.box, required this.reducer}) {
29
29
  valueNotifier = ValueNotifier(box != null ? box!.read<T>(key) ?? initialState : initialState);
30
30
  atoms.add(this);
31
31
  }
@@ -69,65 +69,6 @@ class Atom2<T, A> {
69
69
  }
70
70
  }
71
71
 
72
- class Atom<T> extends ValueNotifier<T> {
73
- final String key;
74
- final GetStorage? box;
75
- Function()? set;
76
- Function(T)? update;
77
-
78
- Atom({required this.key, required T initialValue, this.box, this.set, this.update})
79
- : super(box != null ? box.read<T>(key) ?? initialValue : initialValue);
80
-
81
- @override
82
- set value(T newValue) {
83
- super.value = newValue;
84
- if (box != null) {
85
- if (newValue == null) {
86
- box!.remove(key);
87
- } else {
88
- box!.write(key, newValue);
89
- }
90
- box!.save();
91
- }
92
- }
93
-
94
- T watch(BuildContext context) {
95
- final elementRef = WeakReference(context as Element);
96
- final listenerWrapper = _ListenerWrapper();
97
- listenerWrapper.listener = () {
98
- assert(
99
- SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks,
100
- """
101
- Do not mutate state (by setting the value of the ValueNotifier
102
- that you are subscribed to) during a `build` method. If you need
103
- to schedule a value update after `build` has completed, use
104
- `SchedulerBinding.instance.scheduleTask(updateTask, Priority.idle)`,
105
- `SchedulerBinding.addPostFrameCallback(updateTask)`, '
106
- or similar.
107
- """,
108
- );
109
- // If the element has not been garbage collected (causing
110
- // `elementRef.target` to be null), or unmounted
111
- if (elementRef.target?.mounted ?? false) {
112
- // Mark the element as needing to be rebuilt
113
- elementRef.target!.markNeedsBuild();
114
- }
115
- // Remove the listener -- only listen to one change per `build`
116
- removeListener(listenerWrapper.listener!);
117
- };
118
- addListener(listenerWrapper.listener!);
119
- return value;
120
- }
121
-
122
- /// Use this method to notify listeners of deeper changes, e.g. when a value
123
- /// is added to or removed from a set which is stored in the value of a
124
- /// `ValueNotifier<Set<T>>`.
125
- void notifyChanged() {
126
- // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
127
- notifyListeners();
128
- }
129
- }
130
-
131
72
  class _ListenerWrapper {
132
73
  void Function()? listener;
133
74
  }
lib/navigation.dart CHANGED
@@ -15,19 +15,25 @@ import "package:only_bible_app/widgets/scaffold_markdown.dart";
15
15
  import "package:share_plus/share_plus.dart";
16
16
  import "package:only_bible_app/atom.dart";
17
17
 
18
- final Atom<bool> actionsShown = Atom<bool>(
18
+ final actionsShownAtom = Atom(
19
19
  key: "actionsShown",
20
- initialValue: false,
20
+ initialState: false,
21
- update: (bool v) {
21
+ reducer: (state, action) {
22
+ if (action is SetActionsShown) {
22
- actionsShown.value = v;
23
+ return action.value;
24
+ }
25
+ return state;
23
26
  },
24
27
  );
25
28
 
26
- final Atom<bool> highlightsShown = Atom<bool>(
29
+ final highlightsShownAtom = Atom(
27
30
  key: "highlightsShown",
28
- initialValue: false,
31
+ initialState: false,
29
- update: (bool v) {
32
+ reducer: (state, action) {
33
+ if (action is SetHighlightsShown) {
30
- highlightsShown.value = v;
34
+ return action.value;
35
+ }
36
+ return state;
31
37
  },
32
38
  );
33
39
 
@@ -225,8 +231,8 @@ showSettings(BuildContext context, Bible bible) {
225
231
  }
226
232
 
227
233
  showActions(BuildContext context, Bible bible) {
228
- if (!actionsShown.value) {
234
+ if (!actionsShownAtom.value) {
229
- actionsShown.value = true;
235
+ dispatch(const SetActionsShown(true));
230
236
  Scaffold.of(context).showBottomSheet(
231
237
  enableDrag: false,
232
238
  clipBehavior: Clip.antiAliasWithSaveLayer,
@@ -236,15 +242,15 @@ showActions(BuildContext context, Bible bible) {
236
242
  }
237
243
 
238
244
  hideActions(BuildContext context) {
239
- if (actionsShown.value) {
245
+ if (actionsShownAtom.value) {
240
- actionsShown.value = false;
246
+ dispatch(const SetActionsShown(false));
241
- clearSelections();
247
+ dispatch(const ClearSelectedVerses());
242
248
  Navigator.of(context).pop();
243
249
  }
244
250
  }
245
251
 
246
252
  showHighlights(BuildContext context) {
247
- highlightsShown.value = true;
253
+ dispatch(const SetHighlightsShown(true));
248
254
  Scaffold.of(context).showBottomSheet(
249
255
  enableDrag: false,
250
256
  clipBehavior: Clip.antiAliasWithSaveLayer,
@@ -253,8 +259,8 @@ showHighlights(BuildContext context) {
253
259
  }
254
260
 
255
261
  hideHighlights(BuildContext context) {
256
- if (highlightsShown.value) {
262
+ if (highlightsShownAtom.value) {
257
- highlightsShown.value = false;
263
+ dispatch(const SetHighlightsShown(false));
258
264
  Navigator.of(context).pop();
259
265
  }
260
266
  }
lib/sheets/actions_sheet.dart CHANGED
@@ -40,12 +40,12 @@ class ActionsSheet extends StatelessWidget {
40
40
  ),
41
41
  IconButton(
42
42
  padding: EdgeInsets.zero,
43
- onPressed: () => showNoteField(context, bible, selectedVerses.value.first),
43
+ onPressed: () => showNoteField(context, bible, selectedVersesAtom.value.first),
44
44
  icon: Icon(Icons.post_add_outlined, size: 34, color: iconColor),
45
45
  ),
46
46
  IconButton(
47
47
  padding: EdgeInsets.zero,
48
- onPressed: () => shareVerses(context, bible, selectedVerses.value),
48
+ onPressed: () => shareVerses(context, bible, selectedVersesAtom.value),
49
49
  icon: Icon(Icons.share_outlined, size: 34, color: iconColor),
50
50
  ),
51
51
  ],
lib/store/actions.dart CHANGED
@@ -1,3 +1,5 @@
1
+ import "package:only_bible_app/models.dart";
2
+
1
3
  sealed class AppAction {}
2
4
 
3
5
  class FirstOpenDone implements AppAction {}
@@ -10,7 +12,9 @@ class UpdateBible implements AppAction {
10
12
  }
11
13
 
12
14
  class ToggleEngTitles implements AppAction {}
15
+
13
16
  class ToggleBoldFont implements AppAction {}
17
+
14
18
  class ToggleDarkMode implements AppAction {}
15
19
 
16
20
  class UpdateTextScale implements AppAction {
@@ -24,4 +28,32 @@ class UpdateChapter implements AppAction {
24
28
  final int chapter;
25
29
 
26
30
  const UpdateChapter(this.book, this.chapter);
27
- }
31
+ }
32
+
33
+ class SetPlaying implements AppAction {
34
+ final bool value;
35
+
36
+ const SetPlaying(this.value);
37
+ }
38
+
39
+ class SetSelectedVerses implements AppAction {
40
+ final List<Verse> value;
41
+
42
+ const SetSelectedVerses(this.value);
43
+ }
44
+
45
+ class ClearSelectedVerses implements AppAction {
46
+ const ClearSelectedVerses();
47
+ }
48
+
49
+ class SetActionsShown implements AppAction {
50
+ final bool value;
51
+
52
+ const SetActionsShown(this.value);
53
+ }
54
+
55
+ class SetHighlightsShown implements AppAction {
56
+ final bool value;
57
+
58
+ const SetHighlightsShown(this.value);
59
+ }
lib/store/state.dart CHANGED
@@ -24,7 +24,7 @@ final bibleAtom = AsyncAtom(
24
24
  callback: loadBible,
25
25
  );
26
26
 
27
- final firstOpenAtom = Atom2(
27
+ final firstOpenAtom = Atom(
28
28
  box: box,
29
29
  key: "firstOpen",
30
30
  initialState: true,
@@ -36,7 +36,7 @@ final firstOpenAtom = Atom2(
36
36
  },
37
37
  );
38
38
 
39
- final languageCodeAtom = Atom2(
39
+ final languageCodeAtom = Atom(
40
40
  box: box,
41
41
  key: "languageCode",
42
42
  initialState: "en",
@@ -48,7 +48,7 @@ final languageCodeAtom = Atom2(
48
48
  },
49
49
  );
50
50
 
51
- final bibleNameAtom = Atom2(
51
+ final bibleNameAtom = Atom(
52
52
  box: box,
53
53
  key: "bibleName",
54
54
  initialState: "English",
@@ -60,7 +60,7 @@ final bibleNameAtom = Atom2(
60
60
  },
61
61
  );
62
62
 
63
- final engTitlesAtom = Atom2(
63
+ final engTitlesAtom = Atom(
64
64
  box: box,
65
65
  key: "engTitles",
66
66
  initialState: false,
@@ -72,7 +72,7 @@ final engTitlesAtom = Atom2(
72
72
  },
73
73
  );
74
74
 
75
- final boldFontAtom = Atom2(
75
+ final boldFontAtom = Atom(
76
76
  box: box,
77
77
  key: "boldFont",
78
78
  initialState: false,
@@ -84,7 +84,7 @@ final boldFontAtom = Atom2(
84
84
  },
85
85
  );
86
86
 
87
- final darkModeAtom = Atom2(
87
+ final darkModeAtom = Atom(
88
88
  box: box,
89
89
  key: "darkMode",
90
90
  initialState: false,
@@ -97,7 +97,7 @@ final darkModeAtom = Atom2(
97
97
  },
98
98
  );
99
99
 
100
- final textScaleAtom = Atom2(
100
+ final textScaleAtom = Atom(
101
101
  box: box,
102
102
  key: "textScale",
103
103
  initialState: 0.0,
@@ -109,7 +109,7 @@ final textScaleAtom = Atom2(
109
109
  },
110
110
  );
111
111
 
112
- final savedBookAtom = Atom2(
112
+ final savedBookAtom = Atom(
113
113
  box: box,
114
114
  key: "savedBook",
115
115
  initialState: 0,
@@ -121,7 +121,7 @@ final savedBookAtom = Atom2(
121
121
  },
122
122
  );
123
123
 
124
- final savedChapterAtom = Atom2(
124
+ final savedChapterAtom = Atom(
125
125
  box: box,
126
126
  key: "savedChapter",
127
127
  initialState: 0,
@@ -133,27 +133,31 @@ final savedChapterAtom = Atom2(
133
133
  },
134
134
  );
135
135
 
136
- final Atom<bool> isPlaying = Atom<bool>(
136
+ final isPlaying = Atom(
137
137
  key: "isPlaying",
138
- initialValue: false,
138
+ initialState: false,
139
- update: (bool v) {
139
+ reducer: (state, action) {
140
+ if (action is SetPlaying) {
140
- isPlaying.value = v;
141
+ return action.value;
142
+ }
143
+ return state;
141
144
  },
142
145
  );
143
146
 
144
- final Atom<List<Verse>> selectedVerses = Atom<List<Verse>>(
147
+ final selectedVersesAtom = Atom(
145
148
  key: "selectedVerses",
146
- initialValue: [],
147
- update: (List<Verse> verses) {
149
+ initialState: List<Verse>.from([]),
150
+ reducer: (state, action) {
148
- selectedVerses.value = verses;
151
+ if (action is SetSelectedVerses) {
152
+ return action.value;
153
+ }
149
- // selectedVerses.notifyChanged();
154
+ if (action is ClearSelectedVerses) {
155
+ return [];
156
+ }
157
+ return state;
150
158
  },
151
159
  );
152
160
 
153
- void clearSelections() {
154
- selectedVerses.value.clear();
155
- }
156
-
157
161
  Color? getHighlight(Verse v) {
158
162
  final key = "${v.book}:${v.chapter}:${v.index}:highlight";
159
163
  if (box.hasData(key)) {
@@ -169,7 +173,7 @@ Color? getHighlight(Verse v) {
169
173
  }
170
174
 
171
175
  void setHighlight(BuildContext context, int index) {
172
- for (final v in selectedVerses.value) {
176
+ for (final v in selectedVersesAtom.value) {
173
177
  box.write("${v.book}:${v.chapter}:${v.index}:highlight", index);
174
178
  }
175
179
  box.save();
@@ -177,7 +181,7 @@ void setHighlight(BuildContext context, int index) {
177
181
  }
178
182
 
179
183
  void removeHighlight(BuildContext context) {
180
- for (final v in selectedVerses.value) {
184
+ for (final v in selectedVersesAtom.value) {
181
185
  box.remove("${v.book}:${v.chapter}:${v.index}:highlight");
182
186
  }
183
187
  box.save();
@@ -185,23 +189,25 @@ void removeHighlight(BuildContext context) {
185
189
  }
186
190
 
187
191
  bool isVerseSelected(Verse v) {
188
- return selectedVerses.value.any((el) => el.book == v.book && el.chapter == v.chapter && el.index == v.index);
192
+ return selectedVersesAtom.value.any((el) => el.book == v.book && el.chapter == v.chapter && el.index == v.index);
189
193
  }
190
194
 
191
195
  bool watchVerseSelected(BuildContext context, Verse v) {
196
+ return selectedVersesAtom
197
+ .watch(context)
192
- return selectedVerses.watch(context).any((el) => el.book == v.book && el.chapter == v.chapter && el.index == v.index);
198
+ .any((el) => el.book == v.book && el.chapter == v.chapter && el.index == v.index);
193
199
  }
194
200
 
195
201
  void onVerseSelected(BuildContext context, Bible bible, Verse v) {
196
202
  if (isVerseSelected(v)) {
197
- selectedVerses.update!(selectedVerses.value.removeBy((it) => it.index == v.index).toList());
203
+ dispatch(SetSelectedVerses(selectedVersesAtom.value.removeBy((it) => it.index == v.index).toList()));
198
204
  } else {
199
- selectedVerses.update!(selectedVerses.value.addBy(v).toList());
205
+ dispatch(SetSelectedVerses(selectedVersesAtom.value.addBy(v).toList()));
200
206
  }
201
- if (selectedVerses.value.isNotEmpty) {
207
+ if (selectedVersesAtom.value.isNotEmpty) {
202
208
  showActions(context, bible);
203
209
  }
204
- if (selectedVerses.value.isEmpty) {
210
+ if (selectedVersesAtom.value.isEmpty) {
205
211
  hideActions(context);
206
212
  }
207
213
  }
@@ -235,7 +241,7 @@ clearEvents(BuildContext context) {
235
241
 
236
242
  pause() async {
237
243
  await player.pause();
238
- isPlaying.value = false;
244
+ dispatch(const SetPlaying(false));
239
245
  }
240
246
 
241
247
  class BufferAudioSource extends StreamAudioSource {
@@ -261,11 +267,11 @@ class BufferAudioSource extends StreamAudioSource {
261
267
  }
262
268
 
263
269
  onPlay(BuildContext context, Bible bible) async {
264
- final versesToPlay = List<Verse>.from(selectedVerses.value);
270
+ final versesToPlay = List<Verse>.from(selectedVersesAtom.value);
265
271
  if (isPlaying.value) {
266
272
  pause();
267
273
  } else {
268
- isPlaying.value = true;
274
+ dispatch(const SetPlaying(true));
269
275
  for (final v in versesToPlay) {
270
276
  final pathname = "${bible.name}|${v.book}|${v.chapter}|${v.index}";
271
277
  try {
@@ -304,5 +310,5 @@ deleteNote(BuildContext context, Verse v) {
304
310
  box.save();
305
311
  hideNoteField(context);
306
312
  // TODO: hack to re-render this page
307
- selectedVerses.notifyChanged();
313
+ selectedVersesAtom.notifyChanged();
308
314
  }
lib/widgets/verses_view.dart CHANGED
@@ -89,7 +89,7 @@ class VersesView extends StatelessWidget {
89
89
  ),
90
90
  ),
91
91
  Padding(
92
- padding: EdgeInsets.only(bottom: actionsShown.watch(context) ? 120 : 0),
92
+ padding: EdgeInsets.only(bottom: actionsShownAtom.watch(context) ? 120 : 0),
93
93
  ),
94
94
  ],
95
95
  ),