~repos /only-bible-app
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.
c7ae2a74
—
pyrossh 1 year ago
add goto verse
- app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt +5 -4
- app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt +0 -15
- app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt +4 -5
- app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt +7 -1
- app/src/main/java/dev/pyrossh/onlyBible/composables/ChapterSelector.kt +3 -2
- app/src/main/java/dev/pyrossh/onlyBible/composables/EmbeddedSearchBar.kt +2 -1
- app/src/main/java/dev/pyrossh/onlyBible/composables/VerseHeading.kt +3 -2
- app/src/main/java/dev/pyrossh/onlyBible/composables/VerseText.kt +39 -3
- app/src/main/java/dev/pyrossh/onlyBible/utils/Navigation.kt +6 -0
app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt
CHANGED
|
@@ -4,15 +4,16 @@ import androidx.compose.animation.EnterTransition
|
|
|
4
4
|
import androidx.compose.animation.ExitTransition
|
|
5
5
|
import androidx.compose.animation.core.tween
|
|
6
6
|
import androidx.compose.runtime.Composable
|
|
7
|
-
import androidx.
|
|
7
|
+
import androidx.navigation.NavHostController
|
|
8
8
|
import androidx.navigation.compose.NavHost
|
|
9
9
|
import androidx.navigation.compose.composable
|
|
10
|
-
import androidx.navigation.compose.rememberNavController
|
|
11
10
|
import androidx.navigation.toRoute
|
|
12
11
|
|
|
13
12
|
@Composable
|
|
13
|
+
fun AppHost(
|
|
14
|
-
|
|
14
|
+
model: AppViewModel,
|
|
15
|
-
|
|
15
|
+
navController: NavHostController,
|
|
16
|
+
) {
|
|
16
17
|
val navigateToChapter = { props: ChapterScreenProps ->
|
|
17
18
|
navController.navigate(props)
|
|
18
19
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt
CHANGED
|
@@ -74,7 +74,6 @@ class AppViewModel : ViewModel() {
|
|
|
74
74
|
var lineSpacingDelta by mutableIntStateOf(0)
|
|
75
75
|
var nightMode by mutableIntStateOf(UiModeManager.MODE_NIGHT_AUTO)
|
|
76
76
|
val selectedVerses = MutableStateFlow(listOf<Verse>())
|
|
77
|
-
val isSearching = MutableStateFlow(false)
|
|
78
77
|
val searchText = MutableStateFlow("")
|
|
79
78
|
|
|
80
79
|
@OptIn(FlowPreview::class)
|
|
@@ -99,20 +98,6 @@ class AppViewModel : ViewModel() {
|
|
|
99
98
|
searchText.value = text
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
fun onOpenSearch() {
|
|
103
|
-
isSearching.value = true
|
|
104
|
-
if (!isSearching.value) {
|
|
105
|
-
onSearchTextChange("")
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
fun onCloseSearch() {
|
|
110
|
-
isSearching.value = false
|
|
111
|
-
if (!isSearching.value) {
|
|
112
|
-
onSearchTextChange("")
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
101
|
fun showSheet() {
|
|
117
102
|
showBottomSheet = true
|
|
118
103
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt
CHANGED
|
@@ -86,7 +86,7 @@ fun ChapterScreen(
|
|
|
86
86
|
) {
|
|
87
87
|
val view = LocalView.current
|
|
88
88
|
val context = LocalContext.current
|
|
89
|
-
|
|
89
|
+
var isSearchShown by remember { mutableStateOf(false) }
|
|
90
90
|
var chapterSelectorShown by remember { mutableStateOf(false) }
|
|
91
91
|
var bibleSelectorShown by remember { mutableStateOf(false) }
|
|
92
92
|
val bookNames by model.bookNames.collectAsState()
|
|
@@ -135,12 +135,12 @@ fun ChapterScreen(
|
|
|
135
135
|
bookNames = bookNames,
|
|
136
136
|
startBookIndex = bookIndex,
|
|
137
137
|
onClose = { chapterSelectorShown = false },
|
|
138
|
-
navigateToChapter = navigateToChapter,
|
|
139
138
|
)
|
|
140
139
|
}
|
|
141
|
-
if (
|
|
140
|
+
if (isSearchShown) {
|
|
142
141
|
EmbeddedSearchBar(
|
|
143
142
|
model = model,
|
|
143
|
+
onDismiss = { isSearchShown = false },
|
|
144
144
|
)
|
|
145
145
|
}
|
|
146
146
|
|
|
@@ -181,7 +181,7 @@ fun ChapterScreen(
|
|
|
181
181
|
IconButton(
|
|
182
182
|
onClick = {
|
|
183
183
|
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
184
|
-
|
|
184
|
+
isSearchShown = true
|
|
185
185
|
},
|
|
186
186
|
) {
|
|
187
187
|
Icon(
|
|
@@ -254,7 +254,6 @@ fun ChapterScreen(
|
|
|
254
254
|
text = v.heading,
|
|
255
255
|
fontType = model.fontType,
|
|
256
256
|
fontSizeDelta = model.fontSizeDelta,
|
|
257
|
-
navigateToChapter = navigateToChapter,
|
|
258
257
|
)
|
|
259
258
|
}
|
|
260
259
|
VerseText(
|
app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt
CHANGED
|
@@ -5,8 +5,11 @@ import androidx.activity.ComponentActivity
|
|
|
5
5
|
import androidx.activity.compose.setContent
|
|
6
6
|
import androidx.activity.enableEdgeToEdge
|
|
7
7
|
import androidx.activity.viewModels
|
|
8
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
8
9
|
import androidx.lifecycle.lifecycleScope
|
|
10
|
+
import androidx.navigation.compose.rememberNavController
|
|
9
11
|
import dev.pyrossh.onlyBible.composables.TextSettingsBottomSheet
|
|
12
|
+
import dev.pyrossh.onlyBible.utils.LocalNavController
|
|
10
13
|
import kotlinx.coroutines.launch
|
|
11
14
|
|
|
12
15
|
class MainActivity : ComponentActivity() {
|
|
@@ -25,7 +28,10 @@ class MainActivity : ComponentActivity() {
|
|
|
25
28
|
AppTheme(
|
|
26
29
|
nightMode = model.nightMode
|
|
27
30
|
) {
|
|
31
|
+
val navController = rememberNavController()
|
|
32
|
+
CompositionLocalProvider(LocalNavController provides navController) {
|
|
28
|
-
|
|
33
|
+
AppHost(navController = navController, model = model)
|
|
34
|
+
}
|
|
29
35
|
if (model.showBottomSheet) {
|
|
30
36
|
TextSettingsBottomSheet()
|
|
31
37
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/composables/ChapterSelector.kt
CHANGED
|
@@ -40,6 +40,7 @@ import dev.pyrossh.onlyBible.ChapterScreenProps
|
|
|
40
40
|
import dev.pyrossh.onlyBible.domain.Bible
|
|
41
41
|
import dev.pyrossh.onlyBible.domain.chapterSizes
|
|
42
42
|
import dev.pyrossh.onlyBible.domain.engTitles
|
|
43
|
+
import dev.pyrossh.onlyBible.utils.LocalNavController
|
|
43
44
|
|
|
44
45
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
45
46
|
@Composable
|
|
@@ -48,10 +49,10 @@ fun ChapterSelector(
|
|
|
48
49
|
bookNames: List<String>,
|
|
49
50
|
startBookIndex: Int,
|
|
50
51
|
onClose: () -> Unit,
|
|
51
|
-
navigateToChapter: (ChapterScreenProps) -> Unit
|
|
52
52
|
) {
|
|
53
53
|
val view = LocalView.current
|
|
54
54
|
val context = LocalContext.current
|
|
55
|
+
val navController = LocalNavController.current
|
|
55
56
|
val height = context.resources.configuration.screenHeightDp.dp / 2
|
|
56
57
|
var expanded by remember { mutableStateOf(false) }
|
|
57
58
|
var bookIndex by remember { mutableIntStateOf(startBookIndex) }
|
|
@@ -147,7 +148,7 @@ fun ChapterSelector(
|
|
|
147
148
|
onClick = {
|
|
148
149
|
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
149
150
|
onClose()
|
|
150
|
-
|
|
151
|
+
navController.navigate(
|
|
151
152
|
ChapterScreenProps(
|
|
152
153
|
bookIndex = bookIndex,
|
|
153
154
|
chapterIndex = c,
|
app/src/main/java/dev/pyrossh/onlyBible/composables/EmbeddedSearchBar.kt
CHANGED
|
@@ -34,6 +34,7 @@ import dev.pyrossh.onlyBible.AppViewModel
|
|
|
34
34
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
35
35
|
fun EmbeddedSearchBar(
|
|
36
36
|
model: AppViewModel,
|
|
37
|
+
onDismiss: () -> Unit,
|
|
37
38
|
) {
|
|
38
39
|
val view = LocalView.current
|
|
39
40
|
val searchText by model.searchText.collectAsState()
|
|
@@ -77,7 +78,7 @@ fun EmbeddedSearchBar(
|
|
|
77
78
|
IconButton(
|
|
78
79
|
onClick = {
|
|
79
80
|
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
80
|
-
|
|
81
|
+
onDismiss()
|
|
81
82
|
},
|
|
82
83
|
) {
|
|
83
84
|
Icon(
|
app/src/main/java/dev/pyrossh/onlyBible/composables/VerseHeading.kt
CHANGED
|
@@ -20,15 +20,16 @@ import androidx.compose.ui.unit.dp
|
|
|
20
20
|
import androidx.compose.ui.unit.sp
|
|
21
21
|
import dev.pyrossh.onlyBible.ChapterScreenProps
|
|
22
22
|
import dev.pyrossh.onlyBible.FontType
|
|
23
|
+
import dev.pyrossh.onlyBible.utils.LocalNavController
|
|
23
24
|
|
|
24
25
|
@Composable
|
|
25
26
|
fun VerseHeading(
|
|
26
27
|
text: String,
|
|
27
28
|
fontType: FontType,
|
|
28
29
|
fontSizeDelta: Int,
|
|
29
|
-
navigateToChapter: (ChapterScreenProps) -> Unit
|
|
30
30
|
) {
|
|
31
31
|
val view = LocalView.current
|
|
32
|
+
val navController = LocalNavController.current
|
|
32
33
|
Text(
|
|
33
34
|
modifier = Modifier.padding(bottom = 12.dp),
|
|
34
35
|
style = TextStyle(
|
|
@@ -50,7 +51,7 @@ fun VerseHeading(
|
|
|
50
51
|
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
51
52
|
val url = (it as LinkAnnotation.Url).url
|
|
52
53
|
val parts = url.split(":")
|
|
53
|
-
|
|
54
|
+
navController.navigate(
|
|
54
55
|
ChapterScreenProps(
|
|
55
56
|
bookIndex = parts[0].toInt(),
|
|
56
57
|
chapterIndex = parts[1].toInt(),
|
app/src/main/java/dev/pyrossh/onlyBible/composables/VerseText.kt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package dev.pyrossh.onlyBible.composables
|
|
2
2
|
|
|
3
|
+
import android.view.SoundEffectConstants
|
|
3
4
|
import androidx.compose.foundation.border
|
|
4
5
|
import androidx.compose.foundation.clickable
|
|
5
6
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
@@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.size
|
|
|
13
14
|
import androidx.compose.foundation.layout.width
|
|
14
15
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
15
16
|
import androidx.compose.material.icons.Icons
|
|
17
|
+
import androidx.compose.material.icons.automirrored.outlined.OpenInNew
|
|
16
18
|
import androidx.compose.material.icons.filled.Circle
|
|
17
19
|
import androidx.compose.material.icons.outlined.Cancel
|
|
18
20
|
import androidx.compose.material.icons.outlined.PauseCircle
|
|
@@ -37,6 +39,7 @@ import androidx.compose.ui.graphics.Color
|
|
|
37
39
|
import androidx.compose.ui.layout.onPlaced
|
|
38
40
|
import androidx.compose.ui.layout.positionInRoot
|
|
39
41
|
import androidx.compose.ui.platform.LocalContext
|
|
42
|
+
import androidx.compose.ui.platform.LocalView
|
|
40
43
|
import androidx.compose.ui.text.AnnotatedString
|
|
41
44
|
import androidx.compose.ui.text.LinkAnnotation
|
|
42
45
|
import androidx.compose.ui.text.SpanStyle
|
|
@@ -52,12 +55,14 @@ import androidx.compose.ui.unit.dp
|
|
|
52
55
|
import androidx.compose.ui.unit.sp
|
|
53
56
|
import androidx.compose.ui.window.Popup
|
|
54
57
|
import dev.pyrossh.onlyBible.AppViewModel
|
|
58
|
+
import dev.pyrossh.onlyBible.ChapterScreenProps
|
|
55
59
|
import dev.pyrossh.onlyBible.FontType
|
|
56
60
|
import dev.pyrossh.onlyBible.darkHighlights
|
|
57
61
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
58
62
|
import dev.pyrossh.onlyBible.isLightTheme
|
|
59
63
|
import dev.pyrossh.onlyBible.lightHighlights
|
|
60
64
|
import dev.pyrossh.onlyBible.shareVerses
|
|
65
|
+
import dev.pyrossh.onlyBible.utils.LocalNavController
|
|
61
66
|
import kotlinx.coroutines.Dispatchers
|
|
62
67
|
import kotlinx.coroutines.launch
|
|
63
68
|
|
|
@@ -160,16 +165,25 @@ fun VerseText(
|
|
|
160
165
|
}
|
|
161
166
|
)
|
|
162
167
|
if (isSelected && selectedVerses.last() == verse) {
|
|
168
|
+
Menu(
|
|
169
|
+
model = model,
|
|
163
|
-
|
|
170
|
+
barYPosition = barYPosition,
|
|
171
|
+
verse = verse,
|
|
172
|
+
highlightWord = highlightWord,
|
|
173
|
+
)
|
|
164
174
|
}
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
@Composable
|
|
168
178
|
private fun Menu(
|
|
169
|
-
barYPosition: Int,
|
|
170
179
|
model: AppViewModel,
|
|
180
|
+
barYPosition: Int,
|
|
181
|
+
verse: Verse,
|
|
182
|
+
highlightWord: String?,
|
|
171
183
|
) {
|
|
184
|
+
val view = LocalView.current
|
|
172
185
|
val context = LocalContext.current
|
|
186
|
+
val navController = LocalNavController.current
|
|
173
187
|
val scope = rememberCoroutineScope()
|
|
174
188
|
val selectedVerses by model.selectedVerses.collectAsState()
|
|
175
189
|
Popup(
|
|
@@ -178,7 +192,7 @@ private fun Menu(
|
|
|
178
192
|
) {
|
|
179
193
|
Surface(
|
|
180
194
|
modifier = Modifier
|
|
181
|
-
.width(
|
|
195
|
+
.width(360.dp)
|
|
182
196
|
.height(56.dp)
|
|
183
197
|
.border(
|
|
184
198
|
width = 1.dp,
|
|
@@ -200,6 +214,7 @@ private fun Menu(
|
|
|
200
214
|
verticalAlignment = Alignment.CenterVertically,
|
|
201
215
|
) {
|
|
202
216
|
IconButton(onClick = {
|
|
217
|
+
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
203
218
|
model.removeHighlightedVerses(selectedVerses)
|
|
204
219
|
model.setSelectedVerses(listOf())
|
|
205
220
|
}) {
|
|
@@ -210,6 +225,7 @@ private fun Menu(
|
|
|
210
225
|
}
|
|
211
226
|
lightHighlights.forEachIndexed { i, tint ->
|
|
212
227
|
IconButton(onClick = {
|
|
228
|
+
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
213
229
|
model.addHighlightedVerses(selectedVerses, i)
|
|
214
230
|
model.setSelectedVerses(listOf())
|
|
215
231
|
}) {
|
|
@@ -228,6 +244,7 @@ private fun Menu(
|
|
|
228
244
|
}
|
|
229
245
|
}
|
|
230
246
|
IconButton(onClick = {
|
|
247
|
+
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
231
248
|
if (model.isAudioPlaying) {
|
|
232
249
|
model.speechService.StopSpeakingAsync()
|
|
233
250
|
} else {
|
|
@@ -248,6 +265,7 @@ private fun Menu(
|
|
|
248
265
|
)
|
|
249
266
|
}
|
|
250
267
|
IconButton(onClick = {
|
|
268
|
+
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
251
269
|
shareVerses(
|
|
252
270
|
context,
|
|
253
271
|
selectedVerses.sortedBy { it.verseIndex })
|
|
@@ -258,6 +276,24 @@ private fun Menu(
|
|
|
258
276
|
contentDescription = "Share",
|
|
259
277
|
)
|
|
260
278
|
}
|
|
279
|
+
if (highlightWord != null) {
|
|
280
|
+
IconButton(onClick = {
|
|
281
|
+
view.playSoundEffect(SoundEffectConstants.CLICK)
|
|
282
|
+
navController.navigate(
|
|
283
|
+
ChapterScreenProps(
|
|
284
|
+
bookIndex = verse.bookIndex,
|
|
285
|
+
chapterIndex = verse.chapterIndex,
|
|
286
|
+
verseIndex = verse.verseIndex,
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
}) {
|
|
290
|
+
Icon(
|
|
291
|
+
// modifier = Modifier.size(32.dp),
|
|
292
|
+
imageVector = Icons.AutoMirrored.Outlined.OpenInNew,
|
|
293
|
+
contentDescription = "Goto",
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
261
297
|
}
|
|
262
298
|
}
|
|
263
299
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/utils/Navigation.kt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
package dev.pyrossh.onlyBible.utils
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.compositionLocalOf
|
|
4
|
+
import androidx.navigation.NavController
|
|
5
|
+
|
|
6
|
+
val LocalNavController = compositionLocalOf<NavController> { error("No NavController found!") }
|