~repos /only-bible-app
GIT_CONFIG_PARAMETERS="'http.version=HTTP/1.1'" git clone
https://git.pyrossh.dev/only-bible-app.git
Discussions:
https://groups.google.com/g/rust-embed-devs
The only bible app you will ever need. No ads. No in-app purchases. No distractions.
541d4777
—
pyrossh 1 month ago
Remove verses_view
- lib/home.dart +107 -2
- lib/widgets/verses_view.dart +0 -120
lib/home.dart
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import "package:flutter/gestures.dart";
|
|
1
2
|
import "package:flutter/material.dart";
|
|
3
|
+
import "package:only_bible_app/gen/bible.gen.dart";
|
|
2
4
|
import "package:only_bible_app/store/app_state.dart";
|
|
3
5
|
import "package:only_bible_app/widgets/home_app_bar.dart";
|
|
6
|
+
import "package:flutter_swipe_detector/flutter_swipe_detector.dart";
|
|
7
|
+
import "package:only_bible_app/store/actions_navigation.dart";
|
|
8
|
+
import "package:only_bible_app/store/app_navigator.dart";
|
|
4
|
-
import "package:only_bible_app/widgets/
|
|
9
|
+
import "package:only_bible_app/widgets/menu_overlay.dart";
|
|
10
|
+
import "package:only_bible_app/store/actions_state.dart";
|
|
5
11
|
|
|
6
12
|
class Home extends StatelessWidget {
|
|
7
13
|
final int bookIndex;
|
|
@@ -9,16 +15,115 @@ class Home extends StatelessWidget {
|
|
|
9
15
|
|
|
10
16
|
const Home({super.key, required this.bookIndex, required this.chapterIndex});
|
|
11
17
|
|
|
18
|
+
static final _linkPattern = RegExp(r"RF:(\d+):(\d+):(\d+)");
|
|
19
|
+
|
|
20
|
+
List<InlineSpan> _buildHeadingSpans(BuildContext context, Bible bible, String heading, TextStyle style) {
|
|
21
|
+
final text = heading.replaceAll("<br>", "\n");
|
|
22
|
+
final spans = <InlineSpan>[];
|
|
23
|
+
var lastEnd = 0;
|
|
24
|
+
|
|
25
|
+
for (final match in _linkPattern.allMatches(text)) {
|
|
26
|
+
if (match.start > lastEnd) {
|
|
27
|
+
spans.add(TextSpan(text: text.substring(lastEnd, match.start), style: style));
|
|
28
|
+
}
|
|
29
|
+
final bookIndex = int.parse(match.group(1)!);
|
|
30
|
+
final chapterIndex = int.parse(match.group(2)!);
|
|
31
|
+
final verseIndex = int.parse(match.group(3)!);
|
|
32
|
+
final bookName = bible.books![bookIndex].name ?? "";
|
|
33
|
+
final label = "$bookName ${chapterIndex + 1}:${verseIndex + 1}";
|
|
34
|
+
spans.add(
|
|
35
|
+
TextSpan(
|
|
36
|
+
text: label,
|
|
37
|
+
style: style.copyWith(
|
|
38
|
+
color: Theme.of(context).colorScheme.primary,
|
|
39
|
+
decoration: TextDecoration.underline,
|
|
40
|
+
),
|
|
41
|
+
recognizer: TapGestureRecognizer()
|
|
42
|
+
..onTap = () => context.dispatch(GoToChapterAction(context.router, bookIndex, chapterIndex)),
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
lastEnd = match.end;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (lastEnd < text.length) {
|
|
49
|
+
spans.add(TextSpan(text: text.substring(lastEnd), style: style));
|
|
50
|
+
}
|
|
51
|
+
spans.add(TextSpan(text: "\n", style: style));
|
|
52
|
+
return spans;
|
|
53
|
+
}
|
|
54
|
+
|
|
12
55
|
@override
|
|
13
56
|
Widget build(BuildContext context) {
|
|
57
|
+
final theme = Theme.of(context).textTheme;
|
|
14
58
|
final bible = context.select((s) => s.bible);
|
|
15
59
|
final book = bible.books![bookIndex];
|
|
16
60
|
final chapter = book.chapters![chapterIndex];
|
|
61
|
+
final (boldFont, fontSize, selectedVerses, _, _) =
|
|
62
|
+
context.select((s) => (s.boldFont, s.fontSize, s.selectedVerses, s.highlights, s.darkMode));
|
|
63
|
+
final appState = context.read();
|
|
64
|
+
final baseStyle = theme.bodyMedium!.copyWith(
|
|
65
|
+
fontWeight: boldFont ? FontWeight.w500 : FontWeight.w400,
|
|
66
|
+
fontSize: fontSize,
|
|
67
|
+
);
|
|
17
68
|
return Scaffold(
|
|
18
69
|
appBar: HomeAppBar(bible: bible, book: book, chapter: chapter),
|
|
19
70
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
|
20
71
|
body: SafeArea(
|
|
72
|
+
child: Stack(
|
|
73
|
+
children: [
|
|
74
|
+
SwipeDetector(
|
|
75
|
+
onSwipeLeft: (offset) =>
|
|
76
|
+
context.dispatch(NextChapterAction(context.router, bible, chapter.book, chapter.index)),
|
|
77
|
+
onSwipeRight: (offset) =>
|
|
78
|
+
context.dispatch(PreviousChapterAction(context.router, bible, chapter.book, chapter.index)),
|
|
79
|
+
child: SingleChildScrollView(
|
|
80
|
+
key: ValueKey("${chapter.book}-${chapter.index}"),
|
|
81
|
+
physics: const BouncingScrollPhysics(),
|
|
82
|
+
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
83
|
+
child: Column(
|
|
84
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
85
|
+
children: [
|
|
86
|
+
for (final v in chapter.verses!)
|
|
87
|
+
Padding(
|
|
88
|
+
padding: const EdgeInsets.only(bottom: 8),
|
|
89
|
+
child: GestureDetector(
|
|
90
|
+
onTap: () => context.dispatch(SelectVerseAction(v)),
|
|
91
|
+
behavior: HitTestBehavior.opaque,
|
|
92
|
+
child: Text.rich(
|
|
93
|
+
TextSpan(
|
|
94
|
+
style: baseStyle,
|
|
95
|
+
children: [
|
|
96
|
+
if (v.heading != null && v.heading!.isNotEmpty)
|
|
97
|
+
..._buildHeadingSpans(context, bible, v.heading!, theme.labelLarge!),
|
|
98
|
+
TextSpan(
|
|
99
|
+
text: "${v.index + 1} ",
|
|
100
|
+
style: theme.labelMedium!.copyWith(
|
|
101
|
+
color: const Color(0xFF9A1111),
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
TextSpan(
|
|
105
|
+
text: v.text ?? "",
|
|
106
|
+
style: appState.getHighlightStyle(context, v, false),
|
|
107
|
+
),
|
|
108
|
+
],
|
|
109
|
+
),
|
|
110
|
+
),
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
if (selectedVerses.isNotEmpty) const SizedBox(height: 120),
|
|
114
|
+
],
|
|
115
|
+
),
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
if (selectedVerses.isNotEmpty)
|
|
119
|
+
Positioned(
|
|
120
|
+
left: 20,
|
|
121
|
+
right: 20,
|
|
122
|
+
bottom: MediaQuery.of(context).padding.bottom + 40,
|
|
21
|
-
|
|
123
|
+
child: Center(child: MenuOverlay(bible: bible)),
|
|
124
|
+
),
|
|
125
|
+
],
|
|
126
|
+
),
|
|
22
127
|
),
|
|
23
128
|
);
|
|
24
129
|
}
|
lib/widgets/verses_view.dart
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import "package:flutter/gestures.dart";
|
|
2
|
-
import "package:flutter/material.dart";
|
|
3
|
-
import "package:flutter_swipe_detector/flutter_swipe_detector.dart";
|
|
4
|
-
import "package:only_bible_app/gen/bible.gen.dart";
|
|
5
|
-
import "package:only_bible_app/store/actions_navigation.dart";
|
|
6
|
-
import "package:only_bible_app/store/app_navigator.dart";
|
|
7
|
-
import "package:only_bible_app/widgets/menu_overlay.dart";
|
|
8
|
-
import "package:only_bible_app/store/actions_state.dart";
|
|
9
|
-
import "package:only_bible_app/store/app_state.dart";
|
|
10
|
-
|
|
11
|
-
class VersesView extends StatelessWidget {
|
|
12
|
-
final Bible bible;
|
|
13
|
-
final Chapter chapter;
|
|
14
|
-
|
|
15
|
-
const VersesView({super.key, required this.bible, required this.chapter});
|
|
16
|
-
|
|
17
|
-
@override
|
|
18
|
-
Widget build(BuildContext context) {
|
|
19
|
-
final (boldFont, fontSize, selectedVerses, _, _) =
|
|
20
|
-
context.select((s) => (s.boldFont, s.fontSize, s.selectedVerses, s.highlights, s.darkMode));
|
|
21
|
-
final appState = context.read();
|
|
22
|
-
final theme = Theme.of(context).textTheme;
|
|
23
|
-
final baseStyle = theme.bodyMedium!.copyWith(
|
|
24
|
-
fontWeight: boldFont ? FontWeight.w500 : FontWeight.w400,
|
|
25
|
-
fontSize: fontSize,
|
|
26
|
-
);
|
|
27
|
-
return Stack(
|
|
28
|
-
children: [
|
|
29
|
-
SwipeDetector(
|
|
30
|
-
onSwipeLeft: (offset) =>
|
|
31
|
-
context.dispatch(NextChapterAction(context.router, bible, chapter.book, chapter.index)),
|
|
32
|
-
onSwipeRight: (offset) =>
|
|
33
|
-
context.dispatch(PreviousChapterAction(context.router, bible, chapter.book, chapter.index)),
|
|
34
|
-
child: SingleChildScrollView(
|
|
35
|
-
key: ValueKey("${chapter.book}-${chapter.index}"),
|
|
36
|
-
physics: const BouncingScrollPhysics(),
|
|
37
|
-
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
38
|
-
child: Column(
|
|
39
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
40
|
-
children: [
|
|
41
|
-
for (final v in chapter.verses!)
|
|
42
|
-
Padding(
|
|
43
|
-
padding: const EdgeInsets.only(bottom: 8),
|
|
44
|
-
child: GestureDetector(
|
|
45
|
-
onTap: () => context.dispatch(SelectVerseAction(v)),
|
|
46
|
-
behavior: HitTestBehavior.opaque,
|
|
47
|
-
child: Text.rich(
|
|
48
|
-
TextSpan(
|
|
49
|
-
style: baseStyle,
|
|
50
|
-
children: [
|
|
51
|
-
if (v.heading != null && v.heading!.isNotEmpty)
|
|
52
|
-
..._buildHeadingSpans(context, v.heading!, theme.labelLarge!),
|
|
53
|
-
TextSpan(
|
|
54
|
-
text: "${v.index + 1} ",
|
|
55
|
-
style: theme.labelMedium!.copyWith(
|
|
56
|
-
color: const Color(0xFF9A1111),
|
|
57
|
-
),
|
|
58
|
-
),
|
|
59
|
-
TextSpan(
|
|
60
|
-
text: v.text ?? "",
|
|
61
|
-
style: appState.getHighlightStyle(context, v, false),
|
|
62
|
-
),
|
|
63
|
-
],
|
|
64
|
-
),
|
|
65
|
-
),
|
|
66
|
-
),
|
|
67
|
-
),
|
|
68
|
-
if (selectedVerses.isNotEmpty) const SizedBox(height: 120),
|
|
69
|
-
],
|
|
70
|
-
),
|
|
71
|
-
),
|
|
72
|
-
),
|
|
73
|
-
if (selectedVerses.isNotEmpty)
|
|
74
|
-
Positioned(
|
|
75
|
-
left: 20,
|
|
76
|
-
right: 20,
|
|
77
|
-
bottom: MediaQuery.of(context).padding.bottom + 40,
|
|
78
|
-
child: Center(child: MenuOverlay(bible: bible)),
|
|
79
|
-
),
|
|
80
|
-
],
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static final _linkPattern = RegExp(r"RF:(\d+):(\d+):(\d+)");
|
|
85
|
-
|
|
86
|
-
List<InlineSpan> _buildHeadingSpans(BuildContext context, String heading, TextStyle style) {
|
|
87
|
-
final text = heading.replaceAll("<br>", "\n");
|
|
88
|
-
final spans = <InlineSpan>[];
|
|
89
|
-
var lastEnd = 0;
|
|
90
|
-
|
|
91
|
-
for (final match in _linkPattern.allMatches(text)) {
|
|
92
|
-
if (match.start > lastEnd) {
|
|
93
|
-
spans.add(TextSpan(text: text.substring(lastEnd, match.start), style: style));
|
|
94
|
-
}
|
|
95
|
-
final bookIndex = int.parse(match.group(1)!);
|
|
96
|
-
final chapterIndex = int.parse(match.group(2)!);
|
|
97
|
-
final verseIndex = int.parse(match.group(3)!);
|
|
98
|
-
final bookName = bible.books![bookIndex].name ?? "";
|
|
99
|
-
final label = "$bookName ${chapterIndex + 1}:${verseIndex + 1}";
|
|
100
|
-
spans.add(
|
|
101
|
-
TextSpan(
|
|
102
|
-
text: label,
|
|
103
|
-
style: style.copyWith(
|
|
104
|
-
color: Theme.of(context).colorScheme.primary,
|
|
105
|
-
decoration: TextDecoration.underline,
|
|
106
|
-
),
|
|
107
|
-
recognizer: TapGestureRecognizer()
|
|
108
|
-
..onTap = () => context.dispatch(GoToChapterAction(context.router, bookIndex, chapterIndex)),
|
|
109
|
-
),
|
|
110
|
-
);
|
|
111
|
-
lastEnd = match.end;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (lastEnd < text.length) {
|
|
115
|
-
spans.add(TextSpan(text: text.substring(lastEnd), style: style));
|
|
116
|
-
}
|
|
117
|
-
spans.add(TextSpan(text: "\n", style: style));
|
|
118
|
-
return spans;
|
|
119
|
-
}
|
|
120
|
-
}
|