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


3811a688 pyrossh

2 years ago
improve app
lib/providers/app_model.dart CHANGED
@@ -5,6 +5,7 @@ import "package:only_bible_app/screens/bible_select_screen.dart";
5
5
  import "package:only_bible_app/screens/book_select_screen.dart";
6
6
  import "package:only_bible_app/models.dart";
7
7
  import "package:only_bible_app/widgets/actions_sheet.dart";
8
+ import "package:only_bible_app/widgets/highlight_button.dart";
8
9
  import "package:only_bible_app/widgets/note_sheet.dart";
9
10
  import "package:only_bible_app/widgets/settings_sheet.dart";
10
11
  import "package:provider/provider.dart";
@@ -27,6 +28,7 @@ class AppModel extends ChangeNotifier {
27
28
  bool fontBold = false;
28
29
  double textScaleFactor = 0;
29
30
  bool actionsShown = false;
31
+ bool highlightMenuShown = false;
30
32
  final TextEditingController noteTextController = TextEditingController();
31
33
  List<HistoryFrame> history = [];
32
34
  final box = GetStorage("only-bible-app-backup");
@@ -180,7 +182,8 @@ class AppModel extends ChangeNotifier {
180
182
  actionsShown = true;
181
183
  Scaffold.of(context).showBottomSheet(
182
184
  enableDrag: false,
185
+ clipBehavior: Clip.antiAliasWithSaveLayer,
183
- (context) => const ActionsSheet(),
186
+ (context) => const ActionsSheet(),
184
187
  );
185
188
  notifyListeners();
186
189
  }
@@ -232,4 +235,86 @@ class AppModel extends ChangeNotifier {
232
235
  hideNoteField(BuildContext context) {
233
236
  Navigator.of(context).pop();
234
237
  }
238
+
239
+ static Color fromHexS(String hexString) {
240
+ return Color(int.parse(hexString, radix: 16));
241
+ }
242
+
243
+ String toHexS(Color c) => '${c.alpha.toRadixString(16).padLeft(2, '0')}'
244
+ '${c.red.toRadixString(16).padLeft(2, '0')}'
245
+ '${c.green.toRadixString(16).padLeft(2, '0')}'
246
+ '${c.blue.toRadixString(16).padLeft(2, '0')}';
247
+
248
+ Color? getHighlight(Verse v) {
249
+ final key = "${v.book}:${v.chapter}:${v.index}:highlight";
250
+ if (box.hasData(key)) {
251
+ // box.remove(key);
252
+ // print(box.read(key));
253
+ return fromHexS(box.read(key));
254
+ }
255
+ return null;
256
+ }
257
+
258
+ void setHighlight(BuildContext context, List<Verse> verses, Color c) {
259
+ for (final v in verses) {
260
+ box.write("${v.book}:${v.chapter}:${v.index}:highlight", toHexS(c));
261
+ }
262
+ box.save();
263
+ }
264
+
265
+ void removeHighlight(BuildContext context, List<Verse> verses) {
266
+ for (final v in verses) {
267
+ box.remove("${v.book}:${v.chapter}:${v.index}:highlight");
268
+ }
269
+ box.save();
270
+ }
271
+
272
+ void showHighlightMenu(BuildContext context, List<Verse> verses, Offset position) {
273
+ hideHighlightMenu(context);
274
+ highlightMenuShown = true;
275
+ final overlay = Overlay.of(context).context.findRenderObject();
276
+ onTap(c) => setHighlight(context, verses, c);
277
+
278
+ showMenu(
279
+ context: context,
280
+ position: RelativeRect.fromRect(
281
+ Rect.fromLTWH(position.dx, position.dy + 30, 100, 100),
282
+ Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width, overlay.paintBounds.size.height),
283
+ ),
284
+ items: [
285
+ PopupMenuItem(
286
+ child: Row(
287
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
288
+ children: [
289
+ HighlightButton(
290
+ color: const Color(0xFFDAEFFE),
291
+ onColorSelected: onTap,
292
+ ),
293
+ HighlightButton(
294
+ color: const Color(0xFFFFFBB1),
295
+ onColorSelected: onTap,
296
+ ),
297
+ HighlightButton(
298
+ color: const Color(0xFFFFDEF3),
299
+ onColorSelected: onTap,
300
+ ),
301
+ HighlightButton(
302
+ color: const Color(0xFFE6FCC3),
303
+ onColorSelected: onTap,
304
+ ),
305
+ HighlightButton(
306
+ color: const Color(0xFFEADDFF),
307
+ onColorSelected: onTap,
308
+ ),
309
+ ],
310
+ ),
311
+ ),
312
+ ]);
313
+ }
314
+
315
+ void hideHighlightMenu(BuildContext context) {
316
+ if (highlightMenuShown) {
317
+ Navigator.of(context).pop();
318
+ }
319
+ }
235
320
  }
lib/providers/chapter_view_model.dart CHANGED
@@ -97,6 +97,13 @@ class ChapterViewModel extends ChangeNotifier {
97
97
  }
98
98
 
99
99
  void clearSelections(BuildContext context) {
100
+ AppModel.ofEvent(context).removeHighlight(context, selectedVerses);
101
+ selectedVerses.clear();
102
+ AppModel.ofEvent(context).hideActions(context);
103
+ notifyListeners();
104
+ }
105
+
106
+ void closeActions(BuildContext context) {
100
107
  selectedVerses.clear();
101
108
  AppModel.ofEvent(context).hideActions(context);
102
109
  notifyListeners();
@@ -184,4 +191,4 @@ class ChapterViewModel extends ChangeNotifier {
184
191
  }
185
192
  }
186
193
  }
187
- }
194
+ }
lib/theme.dart CHANGED
@@ -7,6 +7,7 @@ const lightColorScheme = ColorScheme.light(
7
7
  secondary: Color(0xFFFFC351),
8
8
  surfaceTint: Colors.black,
9
9
  shadow: Colors.black,
10
+ outline: Colors.grey,
10
11
  );
11
12
 
12
13
  const darkColorScheme = ColorScheme.dark(
lib/utils.dart CHANGED
@@ -1,10 +1,10 @@
1
1
  import "dart:convert";
2
+ import 'package:flutter/gestures.dart';
2
3
  import "package:flutter/foundation.dart" show defaultTargetPlatform, TargetPlatform;
3
4
  import "package:flutter/material.dart";
4
5
  import "package:flutter/services.dart";
5
6
  import "package:only_bible_app/models.dart";
6
7
 
7
-
8
8
  bool isDesktop() {
9
9
  return defaultTargetPlatform == TargetPlatform.macOS ||
10
10
  defaultTargetPlatform == TargetPlatform.windows ||
@@ -20,7 +20,7 @@ bool isWide(BuildContext context) {
20
20
  return false;
21
21
  }
22
22
  final width = MediaQuery.of(context).size.width;
23
- return width > 600;
23
+ return width > 700;
24
24
  }
25
25
 
26
26
  createNoTransitionPageRoute(Widget page) {
lib/widgets/actions_sheet.dart CHANGED
@@ -18,41 +18,46 @@ class ActionsSheet extends StatelessWidget {
18
18
  final model = ChapterViewModel.of(context);
19
19
  final audioIcon = model.isPlaying ? Icons.pause_circle_outline : Icons.play_circle_outline;
20
20
  final audioText = model.isPlaying ? "Pause" : "Play";
21
- final highlightRowEnabled = !isDesktop && false;
21
+ final highlightRowEnabled = !isDesktop;
22
+ onHighlight(Color c) {
23
+ final verses = ChapterViewModel.ofEvent(context).selectedVerses;
24
+ app.setHighlight(context, verses, c);
25
+ model.closeActions(context);
26
+ }
27
+
28
+ ;
22
29
  return Container(
23
30
  height: highlightRowEnabled
24
- ? 160
31
+ ? 150
25
32
  : isDesktop
26
- ? 80
33
+ ? 95
34
+ : isIOS()
27
- : 100,
35
+ ? 100
36
+ : 70,
28
37
  color: Theme.of(context).colorScheme.background,
29
- padding: EdgeInsets.only(left: 20, right: 20, top: isDesktop ? 10 : 0),
38
+ padding: EdgeInsets.only(left: 20, right: 20, top: isDesktop ? 10 : 10, bottom: 20),
30
39
  child: Column(
31
40
  mainAxisAlignment: highlightRowEnabled ? MainAxisAlignment.spaceAround : MainAxisAlignment.start,
32
41
  children: [
33
42
  if (highlightRowEnabled)
34
43
  Row(
35
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
44
+ mainAxisAlignment: MainAxisAlignment.end,
36
45
  children: [
37
46
  HighlightButton(
38
47
  color: const Color(0xFFDAEFFE),
39
- onTap: () {},
48
+ onColorSelected: onHighlight,
40
49
  ),
41
50
  HighlightButton(
42
51
  color: const Color(0xFFFFFBB1),
43
- onTap: () {},
52
+ onColorSelected: onHighlight,
44
53
  ),
45
54
  HighlightButton(
46
55
  color: const Color(0xFFFFDEF3),
47
- onTap: () {},
56
+ onColorSelected: onHighlight,
48
57
  ),
49
58
  HighlightButton(
50
59
  color: const Color(0xFFE6FCC3),
51
- onTap: () {},
52
- ),
53
- HighlightButton(
54
- color: const Color(0xFFEADDFF),
60
+ onColorSelected: onHighlight,
55
- onTap: () {},
56
61
  ),
57
62
  ],
58
63
  ),
@@ -105,14 +110,6 @@ class ActionsSheet extends StatelessWidget {
105
110
  ),
106
111
  trailing: Text("Share", style: bodySmall),
107
112
  ),
108
- // IconButtonText(
109
- // leading: IconButton(
110
- // padding: EdgeInsets.zero,
111
- // onPressed: () {},
112
- // icon: const Text(""),
113
- // ),
114
- // trailing: Text("", style: bodySmall),
115
- // )
116
113
  ],
117
114
  ),
118
115
  ],
lib/widgets/chapter_app_bar.dart CHANGED
@@ -46,16 +46,51 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget {
46
46
  child: Row(
47
47
  mainAxisAlignment: MainAxisAlignment.end,
48
48
  children: [
49
+ if (isDesktop)
50
+ TextButton.icon(
51
+ onPressed: () => model.onPrevious(context, model.book, model.chapter),
52
+ style: TextButton.styleFrom(
53
+ elevation: 0,
54
+ padding: const EdgeInsets.symmetric(horizontal: 10),
55
+ shadowColor: Theme.of(context).shadowColor,
56
+ backgroundColor: Theme.of(context).colorScheme.background,
57
+ foregroundColor: Theme.of(context).colorScheme.primary,
58
+ ),
59
+ icon: const Icon(Icons.chevron_left),
60
+ label: const Text("Prev"),
61
+ ),
62
+ if (isDesktop) const SizedBox(width: 10),
63
+ if (isDesktop)
64
+ TextButton.icon(
65
+ onPressed: () => model.onNext(context, model.book, model.chapter),
66
+ style: TextButton.styleFrom(
67
+ elevation: 0,
68
+ padding: const EdgeInsets.symmetric(horizontal: 10),
69
+ shadowColor: Theme.of(context).shadowColor,
70
+ backgroundColor: Theme.of(context).colorScheme.background,
71
+ foregroundColor: Theme.of(context).colorScheme.primary,
72
+ ),
73
+ icon: const Icon(Icons.chevron_right),
74
+ label: const Text("Next"),
75
+ ),
76
+ if (isDesktop) const SizedBox(width: 20),
49
77
  if (isDesktop)
50
78
  TextButton.icon(
51
79
  onPressed: () => app.changeBibleFromHeader(context),
52
80
  style: TextButton.styleFrom(
53
81
  padding: const EdgeInsets.symmetric(horizontal: 10),
82
+ shadowColor: Theme.of(context).shadowColor,
83
+ backgroundColor: Theme.of(context).colorScheme.background,
84
+ foregroundColor: Theme.of(context).colorScheme.primary,
85
+ shape: RoundedRectangleBorder(
86
+ side: BorderSide(
87
+ color: Theme.of(context).colorScheme.primary,
88
+ width: 1,
89
+ ),
90
+ ),
54
91
  ),
55
92
  icon: const Icon(Icons.book_outlined),
56
- label: Text(
57
- app.bible.name,
93
+ label: Text(app.bible.name),
58
- ),
59
94
  ),
60
95
  Padding(
61
96
  padding: const EdgeInsets.only(left: 10),
lib/widgets/highlight_button.dart CHANGED
@@ -2,20 +2,21 @@ import "package:flutter/material.dart";
2
2
 
3
3
  class HighlightButton extends StatelessWidget {
4
4
  final Color color;
5
- final VoidCallback onTap;
5
+ final Function(Color c) onColorSelected;
6
6
 
7
- const HighlightButton({super.key, required this.color, required this.onTap});
7
+ const HighlightButton({super.key, required this.color, required this.onColorSelected});
8
8
 
9
9
  @override
10
10
  Widget build(BuildContext context) {
11
11
  return InkWell(
12
- onTap: onTap,
12
+ onTap: () => onColorSelected(color),
13
- child: DecoratedBox(
13
+ child: Container(
14
+ padding: EdgeInsets.symmetric(horizontal: 10),
14
15
  decoration: BoxDecoration(
15
- color: color.withOpacity(0.6),
16
+ color: color.withOpacity(1),
16
17
  shape: BoxShape.circle,
17
18
  ),
18
- child: const SizedBox(width: 45, height: 45),
19
+ child: const SizedBox(width: 30, height: 30),
19
20
  ),
20
21
  );
21
22
  }
lib/widgets/scaffold_menu.dart CHANGED
@@ -9,6 +9,7 @@ class ScaffoldMenu extends StatelessWidget {
9
9
 
10
10
  @override
11
11
  Widget build(BuildContext context) {
12
+ final pageWidth = MediaQuery.of(context).size.width;
12
13
  return Scaffold(
13
14
  backgroundColor: Colors.transparent,
14
15
  body: SafeArea(
@@ -17,7 +18,7 @@ class ScaffoldMenu extends StatelessWidget {
17
18
  margin: EdgeInsets.only(left: isWide(context) ? 250 : 0),
18
19
  child: Container(
19
20
  color: backgroundColor ?? Theme.of(context).colorScheme.background,
20
- margin: EdgeInsets.only(right: isWide(context) ? 650 : 0),
21
+ margin: EdgeInsets.only(right: isWide(context) ? pageWidth - 750 : 0),
21
22
  child: child,
22
23
  ),
23
24
  ),
lib/widgets/verses_view.dart CHANGED
@@ -72,10 +72,16 @@ class VersesView extends StatelessWidget {
72
72
  text: "${v.text}\n",
73
73
  style: context.watch<ChapterViewModel>().isVerseSelected(v)
74
74
  ? TextStyle(
75
- backgroundColor: Theme.of(context).highlightColor,
75
+ backgroundColor: app.darkMode ? Colors.grey.shade800 : Colors.grey.shade200,
76
76
  )
77
- : null,
77
+ : TextStyle(
78
- recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, v),
78
+ backgroundColor: app.getHighlight(v) ?? Theme.of(context).colorScheme.background,
79
+ ),
80
+ recognizer: TapGestureRecognizer()
81
+ ..onTap = () {
82
+ model.onVerseSelected(context, v);
83
+ // AppModel.ofEvent(context).showHighlightMenu(context, v, details.globalPosition);
84
+ },
79
85
  ),
80
86
  const WidgetSpan(
81
87
  child: Padding(