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


c7ae2a74 pyrossh

1 year ago
add goto verse
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.lifecycle.viewmodel.compose.viewModel
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
- fun AppHost(model: AppViewModel = viewModel()) {
14
+ model: AppViewModel,
15
- val navController = rememberNavController()
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
- val isSearching by model.isSearching.collectAsState()
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 (isSearching) {
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
- model.onOpenSearch()
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
- AppHost()
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
- navigateToChapter(
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
- model.onCloseSearch()
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
- navigateToChapter(
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
- Menu(barYPosition, model)
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(300.dp)
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!") }