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


84197944 pyrossh

2 years ago
add actions
assets/bibles/{KJV.txt → English.txt} RENAMED
File without changes
ios/Podfile.lock CHANGED
@@ -115,6 +115,8 @@ PODS:
115
115
  - PromisesObjC (2.3.1)
116
116
  - PromisesSwift (2.3.1):
117
117
  - PromisesObjC (= 2.3.1)
118
+ - share_plus (0.0.1):
119
+ - Flutter
118
120
  - shared_preferences_foundation (0.0.1):
119
121
  - Flutter
120
122
  - FlutterMacOS
@@ -130,6 +132,7 @@ DEPENDENCIES:
130
132
  - integration_test (from `.symlinks/plugins/integration_test/ios`)
131
133
  - just_audio (from `.symlinks/plugins/just_audio/ios`)
132
134
  - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
135
+ - share_plus (from `.symlinks/plugins/share_plus/ios`)
133
136
  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
134
137
 
135
138
  SPEC REPOS:
@@ -175,6 +178,8 @@ EXTERNAL SOURCES:
175
178
  :path: ".symlinks/plugins/just_audio/ios"
176
179
  path_provider_foundation:
177
180
  :path: ".symlinks/plugins/path_provider_foundation/darwin"
181
+ share_plus:
182
+ :path: ".symlinks/plugins/share_plus/ios"
178
183
  shared_preferences_foundation:
179
184
  :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
180
185
 
@@ -208,6 +213,7 @@ SPEC CHECKSUMS:
208
213
  path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
209
214
  PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
210
215
  PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
216
+ share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
211
217
  shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
212
218
 
213
219
  PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189
lib/models.dart CHANGED
@@ -60,17 +60,12 @@ class Chapter {
60
60
  }
61
61
 
62
62
  class Verse {
63
+ final int index;
64
+ final int book;
65
+ final int chapter;
63
66
  final String text;
64
- final TimeRange audioRange;
65
-
66
- const Verse({required this.text, required this.audioRange});
67
- }
68
-
69
- class TimeRange {
70
- final double start;
71
- final double end;
72
67
 
73
- const TimeRange({required this.start, required this.end});
68
+ const Verse({required this.index, required this.text, required this.chapter, required this.book});
74
69
  }
75
70
 
76
71
  const bookNames = <String, List<String>>{
@@ -281,7 +276,7 @@ const bookNames = <String, List<String>>{
281
276
  };
282
277
 
283
278
  final bibles = [
284
- Bible(id: 1, name: "KJV", hasAudio: false),
279
+ Bible(id: 1, name: "English", hasAudio: false),
285
280
  Bible(id: 2, name: "Kannada", hasAudio: true),
286
281
  Bible(id: 3, name: "Nepali", hasAudio: false),
287
282
  Bible(id: 4, name: "Hindi", hasAudio: false),
@@ -304,14 +299,8 @@ List<Book> getBibleFromText(String languageCode, String text) {
304
299
  }
305
300
  var book = int.parse(line.substring(0, 2));
306
301
  var chapter = int.parse(line.substring(3, 6));
307
- // var verseNo = line.substring(7, 10);
302
+ var verseNo = int.parse(line.substring(7, 10));
308
303
  var verseText = line.substring(11);
309
- double start = 0;
310
- double end = 0;
311
- // if (item.length > 4) {
312
- // start = double.parse(item[4]);
313
- // end = double.parse(item[5]);
314
- // }
315
304
  if (books.length < book) {
316
305
  books.add(
317
306
  Book(
@@ -327,8 +316,10 @@ List<Book> getBibleFromText(String languageCode, String text) {
327
316
  }
328
317
  books[book - 1].chapters[chapter - 1].verses.add(
329
318
  Verse(
319
+ index: verseNo - 1,
330
320
  text: verseText,
331
- audioRange: TimeRange(start: start, end: end),
321
+ chapter: chapter - 1,
322
+ book: book - 1,
332
323
  ),
333
324
  );
334
325
  }
lib/screens/chapter_select_screen.dart CHANGED
@@ -12,6 +12,7 @@ class ChapterSelectScreen extends StatelessWidget {
12
12
 
13
13
  const ChapterSelectScreen({super.key, required this.selectedBookIndex, required this.book});
14
14
 
15
+ // TODO: move this to app and allow to pause
15
16
  onChapterSelected(BuildContext context, int index) {
16
17
  Navigator.of(context).pushReplacement(
17
18
  createNoTransitionPageRoute(
lib/state.dart CHANGED
@@ -17,7 +17,9 @@ import "package:only_bible_app/widgets/actions_sheet.dart";
17
17
  import "package:only_bible_app/widgets/scaffold_menu.dart";
18
18
  import "package:only_bible_app/widgets/settings_sheet.dart";
19
19
  import "package:provider/provider.dart";
20
+ import "package:share_plus/share_plus.dart";
20
21
  import "package:shared_preferences/shared_preferences.dart";
22
+ import "package:get_storage/get_storage.dart";
21
23
 
22
24
  class HistoryFrame {
23
25
  final int book;
@@ -35,6 +37,7 @@ class AppModel extends ChangeNotifier {
35
37
  double textScaleFactor = 0;
36
38
  bool actionsShown = false;
37
39
  List<HistoryFrame> history = [];
40
+ final box = GetStorage("only-bible-app-backup");
38
41
 
39
42
  static AppModel of(BuildContext context) {
40
43
  return Provider.of(context, listen: true);
@@ -202,7 +205,7 @@ class AppModel extends ChangeNotifier {
202
205
  class ChapterViewModel extends ChangeNotifier {
203
206
  final int book;
204
207
  final int chapter;
205
- final List<int> selectedVerses;
208
+ final List<Verse> selectedVerses;
206
209
  final player = AudioPlayer();
207
210
  bool isPlaying = false;
208
211
 
@@ -235,6 +238,9 @@ class ChapterViewModel extends ChangeNotifier {
235
238
  }
236
239
 
237
240
  navigateBookChapter(BuildContext context, int book, int chapter, TextDirection? dir) {
241
+ if (isPlaying) {
242
+ pause();
243
+ }
238
244
  AppModel.ofEvent(context).hideActions(context);
239
245
  Navigator.of(context).push(
240
246
  createSlideRoute(
@@ -279,18 +285,29 @@ class ChapterViewModel extends ChangeNotifier {
279
285
  return selectedVerses.isNotEmpty;
280
286
  }
281
287
 
288
+ void clearSelections(BuildContext context) {
289
+ selectedVerses.clear();
290
+ AppModel.ofEvent(context).hideActions(context);
291
+ notifyListeners();
292
+ }
293
+
282
- bool isVerseSelected(int i) {
294
+ bool isVerseSelected(Verse v) {
283
- return selectedVerses.contains(i);
295
+ return selectedVerses.any((el) => el.index == v.index);
284
296
  }
285
297
 
298
+ bool isVerseHighlighted(BuildContext context) {
299
+ // box.read("${book}:${chapter}:${verse}", "color");
300
+ return false;
301
+ }
302
+
286
- void onVerseSelected(BuildContext context, int i) {
303
+ void onVerseSelected(BuildContext context, Verse v) {
287
304
  if (selectedVerses.isEmpty) {
288
305
  AppModel.ofEvent(context).showActions(context);
289
306
  }
290
- if (selectedVerses.contains(i)) {
307
+ if (isVerseSelected(v)) {
291
- selectedVerses.remove(i);
308
+ selectedVerses.removeWhere((it) => it.index == v.index);
292
309
  } else {
293
- selectedVerses.add(i);
310
+ selectedVerses.add(v);
294
311
  }
295
312
  if (selectedVerses.isEmpty) {
296
313
  AppModel.ofEvent(context).hideActions(context);
@@ -298,26 +315,44 @@ class ChapterViewModel extends ChangeNotifier {
298
315
  notifyListeners();
299
316
  }
300
317
 
318
+ void copyVerses() {
319
+ final text = selectedVerses.map((e) => e.text).join("\n");
320
+ Clipboard.setData(ClipboardData(text: text));
321
+ // maybe close the action menu or show a snackbar
322
+ // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Email address copied to clipboard")));
323
+ }
324
+
325
+ void shareVerses() {
326
+ final text = selectedVerses.map((e) => e.text).join("\n");
327
+ Share.share(text);
328
+ }
329
+
330
+ pause() async {
331
+ await player.pause();
332
+ isPlaying = false;
333
+ notifyListeners();
334
+ }
335
+
301
336
  onPlay(BuildContext context) async {
302
337
  final bible = AppModel.ofEvent(context).bible;
303
- final model = ChapterViewModel.ofEvent(context);
304
- // if (!bible.hasAudio) {
338
+ if (!bible.hasAudio) {
339
+ showError(
340
+ context,
305
- // showError(context, "This bible version doesn't support ");
341
+ "This Bible doesn't support audio. Currently audio is only available for the Kannada Bible.",
342
+ );
306
- // return;
343
+ return;
307
- // }
344
+ }
308
345
  if (isPlaying) {
309
- await player.pause();
346
+ pause();
310
- isPlaying = false;
311
- notifyListeners();
312
347
  } else {
313
348
  isPlaying = true;
314
349
  notifyListeners();
315
350
  for (final v in selectedVerses) {
316
351
  final bibleName = bible.name;
317
- final book = (model.book + 1).toString().padLeft(2, "0");
352
+ final book = (v.book + 1).toString().padLeft(2, "0");
318
- final chapter = (model.chapter + 1).toString().padLeft(3, "0");
353
+ final chapter = (v.chapter + 1).toString().padLeft(3, "0");
319
- final verse = (v + 1).toString().padLeft(3, "0");
354
+ final verseNo = (v.index + 1).toString().padLeft(3, "0");
320
- final pathname = "$bibleName/$book-$chapter-$verse.mp3";
355
+ final pathname = "$bibleName/$book-$chapter-$verseNo.mp3";
321
356
  try {
322
357
  final url = await FirebaseStorage.instance.ref(pathname).getDownloadURL();
323
358
  await player.setUrl(url);
@@ -329,9 +364,7 @@ class ChapterViewModel extends ChangeNotifier {
329
364
  showError(context, "Could not play audio");
330
365
  return;
331
366
  } finally {
332
- await player.pause();
367
+ pause();
333
- isPlaying = false;
334
- notifyListeners();
335
368
  }
336
369
  }
337
370
  }
lib/widgets/actions_sheet.dart CHANGED
@@ -61,7 +61,9 @@ class ActionsSheet extends StatelessWidget {
61
61
  IconButtonText(
62
62
  leading: IconButton(
63
63
  padding: EdgeInsets.zero,
64
- onPressed: () {},
64
+ onPressed: () {
65
+ model.clearSelections(context);
66
+ },
65
67
  icon: Icon(Icons.cancel_outlined, size: 24 + iconSize, color: iconColor),
66
68
  ),
67
69
  trailing: Text("Clear", style: bodySmall),
@@ -69,7 +71,7 @@ class ActionsSheet extends StatelessWidget {
69
71
  IconButtonText(
70
72
  leading: IconButton(
71
73
  padding: EdgeInsets.zero,
72
- onPressed: () {},
74
+ onPressed: model.copyVerses,
73
75
  icon: Icon(Icons.copy, size: 24 + iconSize, color: iconColor),
74
76
  ),
75
77
  trailing: Text("Copy", style: bodySmall),
@@ -78,13 +80,16 @@ class ActionsSheet extends StatelessWidget {
78
80
  leading: IconButton(
79
81
  padding: EdgeInsets.zero,
80
82
  onPressed: () {
81
- if (app.bible.hasAudio) {
82
- model.onPlay(context);
83
+ model.onPlay(context);
83
- }
84
84
  },
85
85
  icon: Icon(audioIcon, size: 34 + iconSize, color: app.bible.hasAudio ? iconColor : Colors.grey),
86
86
  ),
87
+ trailing: Text(
88
+ audioText,
89
+ style: bodySmall!.copyWith(
87
- trailing: Text(audioText, style: bodySmall),
90
+ color: app.bible.hasAudio ? bodySmall!.color : Colors.grey,
91
+ ),
92
+ ),
88
93
  ),
89
94
  IconButtonText(
90
95
  leading: IconButton(
@@ -97,7 +102,7 @@ class ActionsSheet extends StatelessWidget {
97
102
  IconButtonText(
98
103
  leading: IconButton(
99
104
  padding: EdgeInsets.zero,
100
- onPressed: () {},
105
+ onPressed: model.shareVerses,
101
106
  icon: Icon(Icons.share_outlined, size: 28 + iconSize, color: iconColor),
102
107
  ),
103
108
  trailing: Text("Share", style: bodySmall),
lib/widgets/chapter_app_bar.dart CHANGED
@@ -7,6 +7,8 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
7
7
  @override
8
8
  Size get preferredSize => const Size.fromHeight(40);
9
9
 
10
+ // TODO: add next/prev buttons for desktop mode
11
+
10
12
  @override
11
13
  Widget build(BuildContext context) {
12
14
  final app = AppModel.of(context);
lib/widgets/settings_sheet.dart CHANGED
@@ -37,7 +37,7 @@ class SettingsSheet extends StatelessWidget {
37
37
  tiles: [
38
38
  SettingsTile.navigation(
39
39
  leading: const Icon(Icons.language, color: Colors.green),
40
- title: const Text("Language"),
40
+ title: const Text("App Language"),
41
41
  value: const Text("English"),
42
42
  ),
43
43
  SettingsTile.navigation(
lib/widgets/verses_view.dart CHANGED
@@ -42,24 +42,22 @@ class VersesView extends StatelessWidget {
42
42
  : textStyle,
43
43
  // recognizer: TapAndPanGestureRecognizer()..onDragEnd = (e) => print("Hello"),
44
44
  children: chapter.verses
45
- .asMap()
46
- .entries
47
45
  .map(
48
- (e) => [
46
+ (v) => [
49
47
  WidgetSpan(
50
48
  child: Transform.translate(
51
49
  offset: const Offset(0, -2),
52
- child: Text("${e.key + 1} ", style: Theme.of(context).textTheme.labelMedium),
50
+ child: Text("${v.index + 1} ", style: Theme.of(context).textTheme.labelMedium),
53
51
  ),
54
52
  ),
55
53
  TextSpan(
56
- text: "${e.value.text}\n",
54
+ text: "${v.text}\n",
57
- style: model.isVerseSelected(e.key)
55
+ style: model.isVerseSelected(v)
58
56
  ? TextStyle(
59
57
  backgroundColor: Theme.of(context).highlightColor,
60
58
  )
61
59
  : null,
62
- recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, e.key),
60
+ recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, v),
63
61
  ),
64
62
  const WidgetSpan(
65
63
  child: Padding(
macos/Podfile.lock CHANGED
@@ -85,6 +85,8 @@ PODS:
85
85
  - PromisesObjC (2.3.1)
86
86
  - PromisesSwift (2.3.1):
87
87
  - PromisesObjC (= 2.3.1)
88
+ - share_plus (0.0.1):
89
+ - FlutterMacOS
88
90
  - shared_preferences_foundation (0.0.1):
89
91
  - Flutter
90
92
  - FlutterMacOS
@@ -97,6 +99,7 @@ DEPENDENCIES:
97
99
  - FlutterMacOS (from `Flutter/ephemeral`)
98
100
  - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
99
101
  - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
102
+ - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
100
103
  - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
101
104
 
102
105
  SPEC REPOS:
@@ -133,6 +136,8 @@ EXTERNAL SOURCES:
133
136
  :path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos
134
137
  path_provider_foundation:
135
138
  :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
139
+ share_plus:
140
+ :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
136
141
  shared_preferences_foundation:
137
142
  :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
138
143
 
@@ -160,6 +165,7 @@ SPEC CHECKSUMS:
160
165
  path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
161
166
  PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
162
167
  PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
168
+ share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7
163
169
  shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
164
170
 
165
171
  PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
pubspec.lock CHANGED
@@ -185,6 +185,14 @@ packages:
185
185
  url: "https://pub.dev"
186
186
  source: hosted
187
187
  version: "3.1.1"
188
+ cross_file:
189
+ dependency: transitive
190
+ description:
191
+ name: cross_file
192
+ sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9"
193
+ url: "https://pub.dev"
194
+ source: hosted
195
+ version: "0.3.3+4"
188
196
  crypto:
189
197
  dependency: transitive
190
198
  description:
@@ -423,6 +431,22 @@ packages:
423
431
  description: flutter
424
432
  source: sdk
425
433
  version: "0.0.0"
434
+ get:
435
+ dependency: transitive
436
+ description:
437
+ name: get
438
+ sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a"
439
+ url: "https://pub.dev"
440
+ source: hosted
441
+ version: "4.6.5"
442
+ get_storage:
443
+ dependency: "direct main"
444
+ description:
445
+ name: get_storage
446
+ sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2"
447
+ url: "https://pub.dev"
448
+ source: hosted
449
+ version: "2.1.1"
426
450
  glob:
427
451
  dependency: transitive
428
452
  description:
@@ -748,6 +772,22 @@ packages:
748
772
  url: "https://pub.dev"
749
773
  source: hosted
750
774
  version: "2.0.2"
775
+ share_plus:
776
+ dependency: "direct main"
777
+ description:
778
+ name: share_plus
779
+ sha256: "6cec740fa0943a826951223e76218df002804adb588235a8910dc3d6b0654e11"
780
+ url: "https://pub.dev"
781
+ source: hosted
782
+ version: "7.1.0"
783
+ share_plus_platform_interface:
784
+ dependency: transitive
785
+ description:
786
+ name: share_plus_platform_interface
787
+ sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7"
788
+ url: "https://pub.dev"
789
+ source: hosted
790
+ version: "3.3.0"
751
791
  shared_preferences:
752
792
  dependency: "direct main"
753
793
  description:
@@ -913,6 +953,38 @@ packages:
913
953
  url: "https://pub.dev"
914
954
  source: hosted
915
955
  version: "2.2.2"
956
+ url_launcher_linux:
957
+ dependency: transitive
958
+ description:
959
+ name: url_launcher_linux
960
+ sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5"
961
+ url: "https://pub.dev"
962
+ source: hosted
963
+ version: "3.0.5"
964
+ url_launcher_platform_interface:
965
+ dependency: transitive
966
+ description:
967
+ name: url_launcher_platform_interface
968
+ sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
969
+ url: "https://pub.dev"
970
+ source: hosted
971
+ version: "2.1.3"
972
+ url_launcher_web:
973
+ dependency: transitive
974
+ description:
975
+ name: url_launcher_web
976
+ sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
977
+ url: "https://pub.dev"
978
+ source: hosted
979
+ version: "2.0.18"
980
+ url_launcher_windows:
981
+ dependency: transitive
982
+ description:
983
+ name: url_launcher_windows
984
+ sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
985
+ url: "https://pub.dev"
986
+ source: hosted
987
+ version: "3.0.7"
916
988
  uuid:
917
989
  dependency: transitive
918
990
  description:
pubspec.yaml CHANGED
@@ -24,6 +24,8 @@ dependencies:
24
24
  firebase_performance: ^0.9.2+4
25
25
  firebase_storage: ^11.2.5
26
26
  settings_ui: ^2.0.2
27
+ get_storage: ^2.1.1
28
+ share_plus: ^7.1.0
27
29
 
28
30
  dev_dependencies:
29
31
  flutter_test:
@@ -53,7 +55,8 @@ flutter:
53
55
  flutter_launcher_icons:
54
56
  android: false
55
57
  ios: true
56
- image_path: "assets/icon.png"
58
+ image_path: "assets/test2.png"
59
+ remove_alpha_ios: true
57
60
  web:
58
61
  generate: true
59
62
  background_color: "#FFFFFF"