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


a23cdd65 pyrossh

2 years ago
improve actions sheet
lib/models.dart CHANGED
@@ -1,16 +1,19 @@
1
1
  class Bible {
2
2
  final int id;
3
3
  final String name;
4
+ final bool hasAudio;
4
5
  List<Book> books = [];
5
6
 
6
7
  Bible({
7
8
  required this.id,
8
9
  required this.name,
10
+ required this.hasAudio,
9
11
  });
10
12
 
11
13
  Bible.withBooks({
12
14
  required this.id,
13
15
  required this.name,
16
+ required this.hasAudio,
14
17
  required this.books,
15
18
  });
16
19
 
@@ -278,17 +281,17 @@ const bookNames = <String, List<String>>{
278
281
  };
279
282
 
280
283
  final bibles = [
281
- Bible(id: 1, name: "KJV"),
284
+ Bible(id: 1, name: "KJV", hasAudio: false),
282
- Bible(id: 2, name: "Kannada"),
285
+ Bible(id: 2, name: "Kannada", hasAudio: true),
283
- Bible(id: 3, name: "Nepali"),
286
+ Bible(id: 3, name: "Nepali", hasAudio: false),
284
- Bible(id: 4, name: "Hindi"),
287
+ Bible(id: 4, name: "Hindi", hasAudio: false),
285
- Bible(id: 5, name: "Gujarati"),
288
+ Bible(id: 5, name: "Gujarati", hasAudio: false),
286
- Bible(id: 6, name: "Malayalam"),
289
+ Bible(id: 6, name: "Malayalam", hasAudio: false),
287
- Bible(id: 7, name: "Oriya"),
290
+ Bible(id: 7, name: "Oriya", hasAudio: false),
288
- Bible(id: 8, name: "Punjabi"),
291
+ Bible(id: 8, name: "Punjabi", hasAudio: false),
289
- Bible(id: 9, name: "Tamil"),
292
+ Bible(id: 9, name: "Tamil", hasAudio: false),
290
- Bible(id: 10, name: "Telugu"),
293
+ Bible(id: 10, name: "Telugu", hasAudio: false),
291
- Bible(id: 11, name: "Bengali"),
294
+ Bible(id: 11, name: "Bengali", hasAudio: false),
292
295
  ];
293
296
 
294
297
  List<Book> getBibleFromText(String languageCode, String text) {
lib/state.dart CHANGED
@@ -12,6 +12,7 @@ import "package:only_bible_app/screens/chapter_view_screen.dart";
12
12
  import "package:only_bible_app/utils/dialog.dart";
13
13
  import "package:only_bible_app/models.dart";
14
14
  import "package:only_bible_app/widgets/actions_sheet.dart";
15
+ import "package:only_bible_app/widgets/settings_sheet.dart";
15
16
  import "package:provider/provider.dart";
16
17
  import "package:shared_preferences/shared_preferences.dart";
17
18
 
@@ -21,6 +22,7 @@ class AppModel extends ChangeNotifier {
21
22
  bool darkMode = false;
22
23
  bool fontBold = false;
23
24
  double textScaleFactor = 0;
25
+ bool actionsShown = false;
24
26
 
25
27
  static AppModel of(BuildContext context) {
26
28
  return Provider.of(context, listen: true);
@@ -66,6 +68,7 @@ class AppModel extends ChangeNotifier {
66
68
  return Bible.withBooks(
67
69
  id: selectedBible.id,
68
70
  name: selectedBible.name,
71
+ hasAudio: selectedBible.hasAudio,
69
72
  books: books,
70
73
  );
71
74
  }
@@ -119,6 +122,32 @@ class AppModel extends ChangeNotifier {
119
122
  notifyListeners();
120
123
  save();
121
124
  }
125
+
126
+ showSettings(BuildContext context) {
127
+ showModalBottomSheet(
128
+ context: context,
129
+ isDismissible: true,
130
+ enableDrag: true,
131
+ showDragHandle: true,
132
+ useSafeArea: true,
133
+ builder: (context) => const SettingsSheet(),
134
+ );
135
+ }
136
+
137
+ showActions(BuildContext context) {
138
+ actionsShown = true;
139
+ Scaffold.of(context).showBottomSheet(
140
+ enableDrag: false,
141
+ (context) => const ActionsSheet(),
142
+ );
143
+ notifyListeners();
144
+ }
145
+
146
+ hideActions(BuildContext context) {
147
+ actionsShown = false;
148
+ Navigator.of(context).pop();
149
+ notifyListeners();
150
+ }
122
151
  }
123
152
 
124
153
  class ChapterViewModel extends ChangeNotifier {
@@ -204,10 +233,7 @@ class ChapterViewModel extends ChangeNotifier {
204
233
  void onVerseSelected(BuildContext context, int i) {
205
234
  if (!isWide(context)) {
206
235
  if (selectedVerses.isEmpty) {
207
- Scaffold.of(context).showBottomSheet(
236
+ AppModel.ofEvent(context).showActions(context);
208
- // clipBehavior: Clip.none,
209
- (context) => const ActionsSheet(),
210
- );
211
237
  }
212
238
  }
213
239
  if (selectedVerses.contains(i)) {
@@ -217,7 +243,7 @@ class ChapterViewModel extends ChangeNotifier {
217
243
  }
218
244
  if (!isWide(context)) {
219
245
  if (selectedVerses.isEmpty) {
220
- Navigator.of(context).pop();
246
+ AppModel.ofEvent(context).hideActions(context);
221
247
  }
222
248
  }
223
249
  notifyListeners();
lib/theme.dart CHANGED
@@ -32,8 +32,12 @@ final lightTheme = ThemeData(
32
32
  dragHandleSize: Size(50, 3),
33
33
  clipBehavior: Clip.antiAliasWithSaveLayer,
34
34
  shape: RoundedRectangleBorder(
35
+ side: BorderSide(
36
+ color: Color(0xFFAFA8A8),
37
+ ),
35
- borderRadius: BorderRadius.vertical(
38
+ borderRadius: BorderRadius.only(
36
- top: Radius.circular(25.0),
39
+ topLeft: Radius.circular(25.0),
40
+ topRight: Radius.circular(25.0),
37
41
  ),
38
42
  ),
39
43
  ),
@@ -68,7 +72,7 @@ final lightTheme = ThemeData(
68
72
  enableFeedback: true,
69
73
  padding: EdgeInsets.zero,
70
74
  shape: const RoundedRectangleBorder(),
71
- elevation: 1,
75
+ elevation: 0,
72
76
  shadowColor: Colors.black,
73
77
  backgroundColor: const Color(0xFFEAE9E9),
74
78
  foregroundColor: const Color(0xFF9A1111),
@@ -87,6 +91,13 @@ final lightTheme = ThemeData(
87
91
  letterSpacing: 0,
88
92
  color: Color(0xFF010101),
89
93
  ),
94
+ bodySmall: TextStyle(
95
+ fontSize: 14,
96
+ fontWeight: FontWeight.w400,
97
+ wordSpacing: 0,
98
+ letterSpacing: 0,
99
+ color: Color(0xFF010101),
100
+ ),
90
101
  headlineLarge: TextStyle(
91
102
  fontSize: 38,
92
103
  fontWeight: FontWeight.w700,
@@ -158,6 +169,9 @@ final darkTheme = ThemeData(
158
169
  bodyMedium: lightTheme.textTheme.bodyMedium!.copyWith(
159
170
  color: const Color(0xFFBCBEC4),
160
171
  ),
172
+ bodySmall: lightTheme.textTheme.bodyMedium!.copyWith(
173
+ color: const Color(0xFFBCBEC4),
174
+ ),
161
175
  headlineLarge: lightTheme.textTheme.headlineLarge!.copyWith(
162
176
  color: const Color(0xFFFFC351),
163
177
  ),
lib/widgets/actions_sheet.dart CHANGED
@@ -1,19 +1,95 @@
1
1
  import "package:flutter/material.dart";
2
2
  import "package:only_bible_app/state.dart";
3
- import "package:only_bible_app/widgets/play_button.dart";
3
+ import "package:only_bible_app/widgets/highlight_button.dart";
4
+ import "package:only_bible_app/widgets/icon_button_text.dart";
4
5
 
5
6
  class ActionsSheet extends StatelessWidget {
6
7
  const ActionsSheet({super.key});
7
8
 
8
9
  @override
9
10
  Widget build(BuildContext context) {
11
+ final iconColor = Colors.black.withOpacity(0.9); //Theme.of(context).secondaryHeaderColor;
12
+ final bodySmall = Theme.of(context).textTheme.bodySmall;
13
+ final model = ChapterViewModel.of(context);
14
+ final audioIcon = model.isPlaying ? Icons.pause_circle_outline : Icons.play_circle_outline;
10
15
  return Container(
16
+ height: 140,
11
17
  color: Theme.of(context).colorScheme.background,
12
- padding: EdgeInsets.only(bottom: isIOS() ? 20 : 0),
18
+ padding: EdgeInsets.only(bottom: isIOS() ? 20 : 0, left: 20, right: 20, top: 10),
13
- child: const Row(
19
+ child: Column(
14
- mainAxisAlignment: MainAxisAlignment.center,
20
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
15
21
  children: [
22
+ Row(
23
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
24
+ children: [
25
+ HighlightButton(
26
+ color: const Color(0xFFDAEFFE),
27
+ onTap: () {},
28
+ ),
29
+ HighlightButton(
30
+ color: const Color(0xFFFFFBB1),
31
+ onTap: () {},
32
+ ),
33
+ HighlightButton(
34
+ color: const Color(0xFFFFDEF3),
35
+ onTap: () {},
36
+ ),
37
+ HighlightButton(
38
+ color: const Color(0xFFE6FCC3),
39
+ onTap: () {},
40
+ ),
41
+ HighlightButton(
42
+ color: const Color(0xFFEADDFF),
43
+ onTap: () {},
44
+ ),
45
+ ],
46
+ ),
47
+ // const Padding(padding: EdgeInsets.only(top: 10)),
48
+ Row(
49
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
50
+ children: [
16
- PlayButton(),
51
+ IconButtonText(
52
+ leading: IconButton(
53
+ padding: EdgeInsets.zero,
54
+ onPressed: () {},
55
+ icon: Icon(Icons.copy, size: 28, color: iconColor),
56
+ ),
57
+ trailing: Text("Copy", style: bodySmall),
58
+ ),
59
+ IconButtonText(
60
+ leading: IconButton(
61
+ padding: EdgeInsets.zero,
62
+ onPressed: () {},
63
+ icon: Icon(Icons.post_add_outlined, size: 32, color: iconColor),
64
+ ),
65
+ trailing: Text("Note", style: bodySmall),
66
+ ),
67
+ IconButtonText(
68
+ leading: IconButton(
69
+ padding: EdgeInsets.zero,
70
+ onPressed: () => model.onPlay(context),
71
+ icon: Icon(audioIcon, size: 40, color: iconColor),
72
+ ),
73
+ trailing: Text("Play", style: bodySmall),
74
+ ),
75
+ IconButtonText(
76
+ leading: IconButton(
77
+ padding: EdgeInsets.zero,
78
+ onPressed: () {},
79
+ icon: Icon(Icons.share_outlined, size: 28, color: iconColor),
80
+ ),
81
+ trailing: Text("Share", style: bodySmall),
82
+ ),
83
+ // IconButtonText(
84
+ // leading: IconButton(
85
+ // padding: EdgeInsets.zero,
86
+ // onPressed: () {},
87
+ // icon: const Text(""),
88
+ // ),
89
+ // trailing: Text("", style: bodySmall),
90
+ // )
91
+ ],
92
+ ),
17
93
  ],
18
94
  ),
19
95
  );
lib/widgets/highlight_button.dart ADDED
@@ -0,0 +1,22 @@
1
+ import "package:flutter/material.dart";
2
+
3
+ class HighlightButton extends StatelessWidget {
4
+ final Color color;
5
+ final VoidCallback onTap;
6
+
7
+ const HighlightButton({super.key, required this.color, required this.onTap});
8
+
9
+ @override
10
+ Widget build(BuildContext context) {
11
+ return InkWell(
12
+ onTap: onTap,
13
+ child: DecoratedBox(
14
+ decoration: BoxDecoration(
15
+ color: color.withOpacity(0.6),
16
+ shape: BoxShape.circle,
17
+ ),
18
+ child: const SizedBox(width: 45, height: 45),
19
+ ),
20
+ );
21
+ }
22
+ }
lib/widgets/icon_button_text.dart ADDED
@@ -0,0 +1,17 @@
1
+ import "package:flutter/material.dart";
2
+
3
+ class IconButtonText extends StatelessWidget {
4
+ final Widget leading, trailing;
5
+
6
+ const IconButtonText({super.key, required this.leading, required this.trailing});
7
+
8
+ @override
9
+ Widget build(BuildContext context) {
10
+ return Column(
11
+ children: [
12
+ leading,
13
+ trailing,
14
+ ],
15
+ );
16
+ }
17
+ }
lib/widgets/more_button.dart CHANGED
@@ -1,28 +1,9 @@
1
1
  import "package:flutter/material.dart";
2
- import "package:only_bible_app/widgets/settings_sheet.dart";
2
+ import "package:only_bible_app/state.dart";
3
3
 
4
- class MoreButton extends StatefulWidget {
4
+ class MoreButton extends StatelessWidget {
5
5
  const MoreButton({super.key});
6
6
 
7
- @override
8
- State<MoreButton> createState() => _MoreButtonState();
9
- }
10
-
11
- class _MoreButtonState extends State<MoreButton> {
12
- var isOpen = false;
13
-
14
- setIsOpen() {
15
- setState(() {
16
- isOpen = true;
17
- });
18
- }
19
-
20
- setIsClosed() {
21
- setState(() {
22
- isOpen = true;
23
- });
24
- }
25
-
26
7
  @override
27
8
  Widget build(BuildContext context) {
28
9
  // showModalBottomSheet(
@@ -53,16 +34,7 @@ class _MoreButtonState extends State<MoreButton> {
53
34
  // );
54
35
  return IconButton(
55
36
  padding: EdgeInsets.zero,
56
- onPressed: () {
57
- showModalBottomSheet(
58
- context: context,
59
- isDismissible: true,
60
- enableDrag: true,
61
- showDragHandle: true,
62
- useSafeArea: true,
63
- builder: (context) => const SettingsSheet(),
37
+ onPressed: () => AppModel.ofEvent(context).showSettings(context),
64
- );
65
- },
66
38
  icon: const Icon(Icons.more_vert),
67
39
  );
68
40
  }
lib/widgets/verses_view.dart CHANGED
@@ -20,51 +20,54 @@ class VersesView extends StatelessWidget {
20
20
  model.onPrevious(context, model.book, model.chapter);
21
21
  },
22
22
  child: Padding(
23
- padding: const EdgeInsets.symmetric(horizontal: 20),
23
+ padding: EdgeInsets.only(left: 20, right: 20, bottom: app.actionsShown ? 120 : 0),
24
- child: SelectableText.rich(
24
+ child: SingleChildScrollView(
25
- scrollPhysics: const BouncingScrollPhysics(),
25
+ physics: const BouncingScrollPhysics(),
26
+ child: Text.rich(
27
+ // scrollPhysics: const BouncingScrollPhysics(),
26
- contextMenuBuilder: null,
28
+ // contextMenuBuilder: null,
27
- textScaleFactor: app.textScaleFactor,
29
+ textScaleFactor: app.textScaleFactor,
28
- // onSelectionChanged: (selection, _) {
30
+ // onSelectionChanged: (selection, _) {
29
- // // Show copy, highlight, note, audio, share
31
+ // // Show copy, highlight, note, audio, share
30
- // //bottom: 55, // TODO: maybe make this 55 only when actions bar is shown else 20
32
+ // //bottom: 55, // TODO: maybe make this 55 only when actions bar is shown else 20
31
- // },
33
+ // },
32
- TextSpan(
34
+ TextSpan(
33
- style: app.fontBold
35
+ style: app.fontBold
34
- ? textStyle.copyWith(
36
+ ? textStyle.copyWith(
35
- fontWeight: FontWeight.w500,
37
+ fontWeight: FontWeight.w500,
36
- )
38
+ )
37
- : textStyle,
39
+ : textStyle,
38
- // recognizer: TapAndPanGestureRecognizer()..onDragEnd = (e) => print("Hello"),
40
+ // recognizer: TapAndPanGestureRecognizer()..onDragEnd = (e) => print("Hello"),
39
- children: chapter.verses
41
+ children: chapter.verses
40
- .asMap()
42
+ .asMap()
41
- .entries
43
+ .entries
42
- .map(
44
+ .map(
43
- (e) => [
45
+ (e) => [
44
- WidgetSpan(
46
+ WidgetSpan(
45
- child: Transform.translate(
47
+ child: Transform.translate(
46
- offset: const Offset(0, -2),
48
+ offset: const Offset(0, -2),
47
- child: Text("${e.key + 1} ", style: Theme.of(context).textTheme.labelMedium),
49
+ child: Text("${e.key + 1} ", style: Theme.of(context).textTheme.labelMedium),
48
- ),
50
+ ),
49
- ),
51
+ ),
50
- TextSpan(
52
+ TextSpan(
51
- text: "${e.value.text}\n",
53
+ text: "${e.value.text}\n",
52
- style: model.isVerseSelected(e.key)
54
+ style: model.isVerseSelected(e.key)
53
- ? TextStyle(
55
+ ? TextStyle(
54
- backgroundColor: Theme.of(context).highlightColor,
56
+ backgroundColor: Theme.of(context).highlightColor,
57
+ )
58
+ : null,
59
+ recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, e.key),
60
+ ),
61
+ const WidgetSpan(
62
+ child: Padding(
63
+ padding: EdgeInsets.only(bottom: 30),
64
+ ),
65
+ ),
66
+ ],
55
67
  )
68
+ .expand((element) => element)
56
- : null,
69
+ .toList(),
57
- recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, e.key),
58
- ),
70
+ ),
59
- const WidgetSpan(
60
- child: Padding(
61
- padding: EdgeInsets.only(bottom: 30),
62
- ),
63
- ),
64
- ],
65
- )
66
- .expand((element) => element)
67
- .toList(),
68
71
  ),
69
72
  ),
70
73
  ),