~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.
677f16b3
—
Peter John 1 year ago
fix various issues
- app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt +8 -7
- app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt +101 -161
- app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt +5 -5
- app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt +2 -13
- app/src/main/java/dev/pyrossh/onlyBible/TextSettingsBottomSheet.kt +3 -4
- app/src/main/java/dev/pyrossh/onlyBible/composables/VerseView.kt +4 -5
- app/src/main/java/dev/pyrossh/onlyBible/domain/Verse.kt +2 -23
app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt
CHANGED
|
@@ -20,14 +20,14 @@ import androidx.navigation.toRoute
|
|
|
20
20
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
21
21
|
|
|
22
22
|
@Composable
|
|
23
|
-
fun AppHost(model: AppViewModel
|
|
23
|
+
fun AppHost(model: AppViewModel) {
|
|
24
24
|
val navController = rememberNavController()
|
|
25
25
|
val navigateToChapter = { props: ChapterScreenProps ->
|
|
26
26
|
model.resetScrollState()
|
|
27
27
|
navController.navigate(props)
|
|
28
28
|
}
|
|
29
29
|
val onSwipeLeft = {
|
|
30
|
-
val pair =
|
|
30
|
+
val pair = model.getForwardPair()
|
|
31
31
|
navigateToChapter(
|
|
32
32
|
ChapterScreenProps(
|
|
33
33
|
bookIndex = pair.first,
|
|
@@ -36,19 +36,20 @@ fun AppHost(model: AppViewModel = viewModel()) {
|
|
|
36
36
|
)
|
|
37
37
|
}
|
|
38
38
|
val onSwipeRight = {
|
|
39
|
-
val pair =
|
|
39
|
+
val pair = model.getBackwardPair()
|
|
40
40
|
if (navController.previousBackStackEntry != null) {
|
|
41
41
|
val previousBook =
|
|
42
|
-
navController.previousBackStackEntry?.arguments?.getInt("
|
|
42
|
+
navController.previousBackStackEntry?.arguments?.getInt("bookIndex")
|
|
43
43
|
?: 0
|
|
44
44
|
val previousChapter =
|
|
45
|
-
navController.previousBackStackEntry?.arguments?.getInt("
|
|
45
|
+
navController.previousBackStackEntry?.arguments?.getInt("chapterIndex")
|
|
46
46
|
?: 0
|
|
47
|
-
//
|
|
47
|
+
// println("currentBackStackEntry ${previousBook} ${previousChapter} || ${pair.first} ${pair.second}")
|
|
48
48
|
if (previousBook == pair.first && previousChapter == pair.second) {
|
|
49
49
|
println("Popped")
|
|
50
50
|
navController.popBackStack()
|
|
51
51
|
} else {
|
|
52
|
+
println("navigated with stack")
|
|
52
53
|
navController.navigate(
|
|
53
54
|
ChapterScreenProps(
|
|
54
55
|
bookIndex = pair.first,
|
|
@@ -58,7 +59,7 @@ fun AppHost(model: AppViewModel = viewModel()) {
|
|
|
58
59
|
)
|
|
59
60
|
}
|
|
60
61
|
} else {
|
|
61
|
-
println("navigated
|
|
62
|
+
println("navigated without stack")
|
|
62
63
|
navController.navigate(
|
|
63
64
|
ChapterScreenProps(
|
|
64
65
|
bookIndex = pair.first,
|
app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt
CHANGED
|
@@ -9,44 +9,32 @@ import android.os.Build
|
|
|
9
9
|
import android.os.LocaleList
|
|
10
10
|
import androidx.appcompat.app.AppCompatDelegate
|
|
11
11
|
import androidx.compose.foundation.lazy.LazyListState
|
|
12
|
-
import androidx.compose.runtime.MutableState
|
|
13
12
|
import androidx.compose.runtime.getValue
|
|
14
13
|
import androidx.compose.runtime.mutableIntStateOf
|
|
15
14
|
import androidx.compose.runtime.mutableStateOf
|
|
16
15
|
import androidx.compose.runtime.setValue
|
|
17
16
|
import androidx.core.os.LocaleListCompat
|
|
18
|
-
import androidx.datastore.preferences.core.Preferences
|
|
19
|
-
import androidx.datastore.preferences.core.booleanPreferencesKey
|
|
20
|
-
import androidx.datastore.preferences.core.edit
|
|
21
|
-
import androidx.datastore.preferences.core.intPreferencesKey
|
|
22
|
-
import androidx.datastore.preferences.core.stringPreferencesKey
|
|
23
|
-
import androidx.datastore.preferences.preferencesDataStore
|
|
24
17
|
import androidx.lifecycle.AndroidViewModel
|
|
25
18
|
import androidx.lifecycle.viewModelScope
|
|
26
19
|
import com.microsoft.cognitiveservices.speech.SpeechConfig
|
|
27
20
|
import com.microsoft.cognitiveservices.speech.SpeechSynthesisEventArgs
|
|
28
21
|
import com.microsoft.cognitiveservices.speech.SpeechSynthesizer
|
|
22
|
+
import dev.pyrossh.onlyBible.domain.BOOKS_COUNT
|
|
29
23
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
30
|
-
import
|
|
24
|
+
import dev.pyrossh.onlyBible.domain.Verse.Companion.chapterSizes
|
|
31
25
|
import kotlinx.coroutines.Dispatchers
|
|
32
26
|
import kotlinx.coroutines.FlowPreview
|
|
33
27
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
34
28
|
import kotlinx.coroutines.flow.SharingStarted
|
|
35
29
|
import kotlinx.coroutines.flow.asStateFlow
|
|
36
|
-
import kotlinx.coroutines.flow.collectLatest
|
|
37
30
|
import kotlinx.coroutines.flow.combine
|
|
38
31
|
import kotlinx.coroutines.flow.debounce
|
|
39
|
-
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
40
|
-
import kotlinx.coroutines.flow.map
|
|
41
32
|
import kotlinx.coroutines.flow.stateIn
|
|
42
33
|
import kotlinx.coroutines.launch
|
|
43
|
-
import kotlinx.coroutines.withContext
|
|
44
34
|
import org.json.JSONObject
|
|
45
35
|
import java.io.IOException
|
|
46
36
|
import java.util.Locale
|
|
47
37
|
|
|
48
|
-
internal val Context.dataStore by preferencesDataStore(name = "onlyBible")
|
|
49
|
-
|
|
50
38
|
class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
51
39
|
private val context
|
|
52
40
|
get() = getApplication<Application>()
|
|
@@ -78,51 +66,16 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
|
78
66
|
var showBottomSheet by mutableStateOf(false)
|
|
79
67
|
var highlightedVerses = MutableStateFlow(JSONObject())
|
|
80
68
|
|
|
81
|
-
var bookIndex by
|
|
69
|
+
var bookIndex by mutableIntStateOf(0)
|
|
82
|
-
coroutineScope = viewModelScope,
|
|
83
|
-
context = context,
|
|
84
|
-
keyName = "bookIndex",
|
|
85
|
-
initialValue = 0,
|
|
86
|
-
defaultValue = 0,
|
|
87
|
-
getPreferencesKey = ::intPreferencesKey,
|
|
88
|
-
)
|
|
89
|
-
var chapterIndex by
|
|
70
|
+
var chapterIndex by mutableIntStateOf(0)
|
|
71
|
+
var fontType by mutableStateOf(FontType.Sans)
|
|
90
|
-
|
|
72
|
+
var fontSizeDelta by mutableIntStateOf(0)
|
|
91
|
-
|
|
73
|
+
var fontBoldEnabled by mutableStateOf(false)
|
|
92
|
-
|
|
74
|
+
var uiMode by mutableIntStateOf(0)
|
|
93
|
-
initialValue = 0,
|
|
94
|
-
defaultValue = 0,
|
|
95
|
-
getPreferencesKey = ::intPreferencesKey,
|
|
96
|
-
)
|
|
97
75
|
var scrollState = LazyListState(
|
|
98
76
|
0,
|
|
99
77
|
0
|
|
100
78
|
)
|
|
101
|
-
var uiMode by mutableIntStateOf(0)
|
|
102
|
-
var fontType by preferenceMutableState(
|
|
103
|
-
coroutineScope = viewModelScope,
|
|
104
|
-
context = context,
|
|
105
|
-
keyName = "fontType",
|
|
106
|
-
initialValue = FontType.Sans.name,
|
|
107
|
-
defaultValue = FontType.Sans.name,
|
|
108
|
-
getPreferencesKey = ::stringPreferencesKey,
|
|
109
|
-
)
|
|
110
|
-
var fontSizeDelta by preferenceMutableState(
|
|
111
|
-
coroutineScope = viewModelScope,
|
|
112
|
-
context = context,
|
|
113
|
-
keyName = "fontSizeDelta",
|
|
114
|
-
initialValue = 0,
|
|
115
|
-
defaultValue = 0,
|
|
116
|
-
getPreferencesKey = ::intPreferencesKey,
|
|
117
|
-
)
|
|
118
|
-
var fontBoldEnabled by preferenceMutableState(
|
|
119
|
-
coroutineScope = viewModelScope,
|
|
120
|
-
context = context,
|
|
121
|
-
keyName = "fontBoldEnabled",
|
|
122
|
-
initialValue = false,
|
|
123
|
-
defaultValue = false,
|
|
124
|
-
getPreferencesKey = ::booleanPreferencesKey,
|
|
125
|
-
)
|
|
126
79
|
|
|
127
80
|
private val _isSearching = MutableStateFlow(false)
|
|
128
81
|
val isSearching = _isSearching.asStateFlow()
|
|
@@ -175,18 +128,69 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
|
175
128
|
showBottomSheet = false
|
|
176
129
|
}
|
|
177
130
|
|
|
178
|
-
fun loadData(
|
|
131
|
+
fun loadData() {
|
|
132
|
+
viewModelScope.launch(Dispatchers.IO) {
|
|
179
|
-
|
|
133
|
+
uiMode = context.applicationContext.resources.configuration.uiMode
|
|
180
|
-
|
|
134
|
+
bookIndex = prefs.getInt("bookIndex", 0)
|
|
181
|
-
|
|
135
|
+
chapterIndex = prefs.getInt("chapterIndex", 0)
|
|
136
|
+
fontType =
|
|
137
|
+
FontType.valueOf(
|
|
182
|
-
|
|
138
|
+
prefs.getString("fontType", FontType.Sans.name) ?: FontType.Sans.name
|
|
139
|
+
)
|
|
183
|
-
|
|
140
|
+
fontSizeDelta = prefs.getInt("fontSizeDelta", 0)
|
|
184
|
-
|
|
141
|
+
fontBoldEnabled = prefs.getBoolean("fontBoldEnabled", false)
|
|
185
|
-
|
|
142
|
+
highlightedVerses.value = JSONObject(prefs.getString("highlightedVerses", "{}") ?: "{}")
|
|
186
|
-
|
|
143
|
+
scrollState = LazyListState(
|
|
187
|
-
|
|
144
|
+
prefs.getInt("scrollIndex", 0),
|
|
188
|
-
|
|
145
|
+
prefs.getInt("scrollOffset", 0)
|
|
189
|
-
|
|
146
|
+
)
|
|
147
|
+
loadBible()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fun loadBible() {
|
|
152
|
+
viewModelScope.launch(Dispatchers.Main) {
|
|
153
|
+
isLoading = true
|
|
154
|
+
isOnError = false
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
val buffer =
|
|
158
|
+
context.assets.open(
|
|
159
|
+
"bibles/${
|
|
160
|
+
context.getCurrentLocale().getDisplayLanguage(Locale.ENGLISH)
|
|
161
|
+
}.txt"
|
|
162
|
+
)
|
|
163
|
+
.bufferedReader()
|
|
164
|
+
val localVerses = buffer.readLines().filter { it.isNotEmpty() }.map {
|
|
165
|
+
val arr = it.split("|")
|
|
166
|
+
val bookName = arr[0]
|
|
167
|
+
val book = arr[1].toInt()
|
|
168
|
+
val chapter = arr[2].toInt()
|
|
169
|
+
val verseNo = arr[3].toInt()
|
|
170
|
+
val heading = arr[4]
|
|
171
|
+
val verseText = arr.subList(5, arr.size).joinToString("|")
|
|
172
|
+
Verse(
|
|
173
|
+
bookIndex = book,
|
|
174
|
+
bookName = bookName,
|
|
175
|
+
chapterIndex = chapter,
|
|
176
|
+
verseIndex = verseNo,
|
|
177
|
+
heading = heading,
|
|
178
|
+
text = verseText,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
viewModelScope.launch(Dispatchers.Main) {
|
|
182
|
+
verses.value = localVerses
|
|
183
|
+
bookNames.value = localVerses.distinctBy { it.bookName }.map { it.bookName }
|
|
184
|
+
isLoading = false
|
|
185
|
+
isOnError = false
|
|
186
|
+
}
|
|
187
|
+
} catch (e: IOException) {
|
|
188
|
+
e.printStackTrace()
|
|
189
|
+
viewModelScope.launch(Dispatchers.Main) {
|
|
190
|
+
isLoading = false
|
|
191
|
+
isOnError = true
|
|
192
|
+
}
|
|
193
|
+
}
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
fun saveData() {
|
|
@@ -194,79 +198,61 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
|
194
198
|
with(prefs.edit()) {
|
|
195
199
|
putInt("bookIndex", bookIndex)
|
|
196
200
|
putInt("chapterIndex", chapterIndex)
|
|
197
|
-
putString("fontType", fontType)
|
|
201
|
+
putString("fontType", fontType.name)
|
|
198
202
|
putInt("fontSizeDelta", fontSizeDelta)
|
|
199
203
|
putBoolean("fontBoldEnabled", fontBoldEnabled)
|
|
200
204
|
putString("highlightedVerses", highlightedVerses.value.toString())
|
|
205
|
+
putInt("scrollIndex", scrollState.firstVisibleItemIndex)
|
|
206
|
+
putInt("scrollOffset", scrollState.firstVisibleItemScrollOffset)
|
|
201
207
|
apply()
|
|
202
208
|
commit()
|
|
203
209
|
}
|
|
204
210
|
}
|
|
205
211
|
}
|
|
206
212
|
|
|
213
|
+
fun getForwardPair(): Pair<Int, Int> {
|
|
214
|
+
val sizes = chapterSizes[bookIndex];
|
|
207
|
-
|
|
215
|
+
if (sizes > chapterIndex + 1) {
|
|
216
|
+
return Pair(bookIndex, chapterIndex + 1)
|
|
217
|
+
}
|
|
218
|
+
if (bookIndex + 1 < BOOKS_COUNT) {
|
|
208
|
-
|
|
219
|
+
return Pair(bookIndex + 1, 0)
|
|
220
|
+
}
|
|
221
|
+
return Pair(0, 0)
|
|
209
222
|
}
|
|
210
223
|
|
|
211
|
-
fun
|
|
224
|
+
fun getBackwardPair(): Pair<Int, Int> {
|
|
212
|
-
viewModelScope.launch(Dispatchers.IO) {
|
|
213
|
-
launch(Dispatchers.Main) {
|
|
214
|
-
isLoading = true
|
|
215
|
-
isOnError = false
|
|
216
|
-
}
|
|
217
|
-
try {
|
|
218
|
-
val buffer =
|
|
219
|
-
context.assets.open("bibles/${loc.getDisplayLanguage(Locale.ENGLISH)}.txt")
|
|
220
|
-
.bufferedReader()
|
|
221
|
-
val localVerses = buffer.readLines().filter { it.isNotEmpty() }.map {
|
|
222
|
-
val arr = it.split("|")
|
|
223
|
-
val bookName = arr[0]
|
|
224
|
-
val book = arr[1].toInt()
|
|
225
|
-
val chapter = arr[2].toInt()
|
|
226
|
-
val verseNo = arr[3].toInt()
|
|
227
|
-
val heading = arr[4]
|
|
228
|
-
val verseText = arr.subList(5, arr.size).joinToString("|")
|
|
229
|
-
Verse(
|
|
230
|
-
bookIndex = book,
|
|
231
|
-
bookName = bookName,
|
|
232
|
-
|
|
225
|
+
if (chapterIndex - 1 >= 0) {
|
|
233
|
-
|
|
226
|
+
return Pair(bookIndex, chapterIndex - 1)
|
|
234
|
-
heading = heading,
|
|
235
|
-
text = verseText,
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
launch(Dispatchers.Main) {
|
|
239
|
-
isLoading = false
|
|
240
|
-
isOnError = false
|
|
241
|
-
verses.value = localVerses
|
|
242
|
-
bookNames.value = localVerses.distinctBy { it.bookName }.map { it.bookName }
|
|
243
|
-
}
|
|
244
|
-
} catch (e: IOException) {
|
|
245
|
-
e.printStackTrace()
|
|
246
|
-
launch(Dispatchers.Main) {
|
|
247
|
-
isLoading = false
|
|
248
|
-
isOnError = true
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
227
|
}
|
|
228
|
+
if (bookIndex - 1 >= 0) {
|
|
229
|
+
return Pair(bookIndex - 1, chapterSizes[bookIndex - 1] - 1)
|
|
230
|
+
}
|
|
231
|
+
return Pair(BOOKS_COUNT - 1, chapterSizes[BOOKS_COUNT - 1] - 1)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
fun resetScrollState() {
|
|
235
|
+
scrollState = LazyListState(0, 0)
|
|
252
236
|
}
|
|
253
237
|
|
|
254
238
|
fun getHighlightForVerse(v: Verse): Int? {
|
|
255
|
-
val k = "${v.bookIndex}:${v.chapterIndex}:${v.verseIndex}"
|
|
256
|
-
if (highlightedVerses.value.has(
|
|
239
|
+
if (highlightedVerses.value.has(v.key()))
|
|
257
|
-
return highlightedVerses.value.getInt(
|
|
240
|
+
return highlightedVerses.value.getInt(v.key())
|
|
258
241
|
return null
|
|
259
242
|
}
|
|
260
243
|
|
|
261
244
|
fun addHighlightedVerses(verses: List<Verse>, colorIndex: Int) {
|
|
262
245
|
verses.forEach { v ->
|
|
263
|
-
highlightedVerses.value.put(
|
|
246
|
+
highlightedVerses.value.put(
|
|
247
|
+
v.key(),
|
|
248
|
+
colorIndex
|
|
249
|
+
)
|
|
264
250
|
}
|
|
265
251
|
}
|
|
266
252
|
|
|
267
253
|
fun removeHighlightedVerses(verses: List<Verse>) {
|
|
268
254
|
verses.forEach { v ->
|
|
269
|
-
highlightedVerses.value.remove(
|
|
255
|
+
highlightedVerses.value.remove(v.key())
|
|
270
256
|
}
|
|
271
257
|
}
|
|
272
258
|
}
|
|
@@ -301,50 +287,4 @@ fun setLocale(context: Context, loc: Locale) {
|
|
|
301
287
|
LocaleListCompat.forLanguageTags(loc.language)
|
|
302
288
|
)
|
|
303
289
|
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private inline fun <reified T, reified NNT : T> preferenceMutableState(
|
|
307
|
-
coroutineScope: CoroutineScope,
|
|
308
|
-
context: Context,
|
|
309
|
-
keyName: String,
|
|
310
|
-
initialValue: T,
|
|
311
|
-
defaultValue: T,
|
|
312
|
-
getPreferencesKey: (keyName: String) -> Preferences.Key<NNT>,
|
|
313
|
-
): MutableState<T> {
|
|
314
|
-
val snapshotMutableState: MutableState<T> = mutableStateOf(initialValue)
|
|
315
|
-
val key: Preferences.Key<NNT> = getPreferencesKey(keyName)
|
|
316
|
-
coroutineScope.launch {
|
|
317
|
-
context.dataStore.data
|
|
318
|
-
.map { if (it[key] == null) defaultValue else it[key] }
|
|
319
|
-
.distinctUntilChanged()
|
|
320
|
-
.collectLatest {
|
|
321
|
-
withContext(Dispatchers.Main) {
|
|
322
|
-
snapshotMutableState.value = it as T
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
return object : MutableState<T> {
|
|
327
|
-
override var value: T
|
|
328
|
-
get() = snapshotMutableState.value
|
|
329
|
-
set(value) {
|
|
330
|
-
val rollbackValue = snapshotMutableState.value
|
|
331
|
-
snapshotMutableState.value = value
|
|
332
|
-
coroutineScope.launch {
|
|
333
|
-
try {
|
|
334
|
-
context.dataStore.edit {
|
|
335
|
-
if (value != null) {
|
|
336
|
-
it[key] = value as NNT
|
|
337
|
-
} else {
|
|
338
|
-
it.remove(key)
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
} catch (e: Exception) {
|
|
342
|
-
snapshotMutableState.value = rollbackValue
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
override fun component1() = value
|
|
348
|
-
override fun component2(): (T) -> Unit = { value = it }
|
|
349
|
-
}
|
|
350
290
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt
CHANGED
|
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|
|
8
8
|
import androidx.compose.foundation.layout.Row
|
|
9
9
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
10
10
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
11
|
+
import androidx.compose.foundation.layout.height
|
|
11
12
|
import androidx.compose.foundation.layout.padding
|
|
12
13
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
13
14
|
import androidx.compose.foundation.lazy.LazyListState
|
|
@@ -194,7 +195,6 @@ fun ChapterScreen(
|
|
|
194
195
|
val searchText by model.searchText.collectAsState()
|
|
195
196
|
val isSearching by model.isSearching.collectAsState()
|
|
196
197
|
val versesList by model.versesList.collectAsState()
|
|
197
|
-
val fontType = FontType.valueOf(model.fontType)
|
|
198
198
|
val fontSizeDelta = model.fontSizeDelta
|
|
199
199
|
val headingColor = MaterialTheme.colorScheme.onSurface // MaterialTheme.colorScheme.primary,
|
|
200
200
|
val chapterVerses =
|
|
@@ -224,7 +224,7 @@ fun ChapterScreen(
|
|
|
224
224
|
vertical = 12.dp,
|
|
225
225
|
),
|
|
226
226
|
style = TextStyle(
|
|
227
|
-
fontFamily = fontType.family(),
|
|
227
|
+
fontFamily = model.fontType.family(),
|
|
228
228
|
fontSize = (16 + fontSizeDelta).sp,
|
|
229
229
|
fontWeight = FontWeight.W700,
|
|
230
230
|
color = headingColor,
|
|
@@ -245,8 +245,8 @@ fun ChapterScreen(
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
TopAppBar(
|
|
248
|
-
|
|
248
|
+
modifier = Modifier
|
|
249
|
-
|
|
249
|
+
.height(72.dp),
|
|
250
250
|
title = {
|
|
251
251
|
|
|
252
252
|
Row(
|
|
@@ -340,7 +340,7 @@ fun ChapterScreen(
|
|
|
340
340
|
top = if (v.verseIndex != 0) 12.dp else 0.dp, bottom = 12.dp
|
|
341
341
|
),
|
|
342
342
|
style = TextStyle(
|
|
343
|
-
fontFamily = fontType.family(),
|
|
343
|
+
fontFamily = model.fontType.family(),
|
|
344
344
|
fontSize = (16 + fontSizeDelta).sp,
|
|
345
345
|
fontWeight = FontWeight.W700,
|
|
346
346
|
color = headingColor,
|
app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt
CHANGED
|
@@ -11,10 +11,7 @@ import androidx.activity.enableEdgeToEdge
|
|
|
11
11
|
import androidx.activity.viewModels
|
|
12
12
|
import androidx.core.animation.doOnEnd
|
|
13
13
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
14
|
-
import androidx.datastore.preferences.core.edit
|
|
15
|
-
import androidx.datastore.preferences.core.intPreferencesKey
|
|
16
14
|
import androidx.lifecycle.lifecycleScope
|
|
17
|
-
import kotlinx.coroutines.flow.first
|
|
18
15
|
import kotlinx.coroutines.launch
|
|
19
16
|
import java.util.Locale
|
|
20
17
|
|
|
@@ -31,9 +28,7 @@ class MainActivity : ComponentActivity() {
|
|
|
31
28
|
super.onCreate(savedInstanceState)
|
|
32
29
|
enableEdgeToEdge()
|
|
33
30
|
lifecycleScope.launch {
|
|
34
|
-
val data = applicationContext.dataStore.data.first()
|
|
35
|
-
model.loadData(
|
|
31
|
+
model.loadData()
|
|
36
|
-
model.loadBible(applicationContext.getCurrentLocale(), applicationContext)
|
|
37
32
|
}
|
|
38
33
|
splashScreen.setKeepOnScreenCondition { model.isLoading }
|
|
39
34
|
splashScreen.setOnExitAnimationListener { viewProvider ->
|
|
@@ -59,7 +54,7 @@ class MainActivity : ComponentActivity() {
|
|
|
59
54
|
}
|
|
60
55
|
setContent {
|
|
61
56
|
AppTheme {
|
|
62
|
-
AppHost()
|
|
57
|
+
AppHost(model = model)
|
|
63
58
|
if (model.showBottomSheet) {
|
|
64
59
|
TextSettingsBottomSheet(model = model)
|
|
65
60
|
}
|
|
@@ -71,12 +66,6 @@ class MainActivity : ComponentActivity() {
|
|
|
71
66
|
super.onSaveInstanceState(outState)
|
|
72
67
|
lifecycleScope.launch {
|
|
73
68
|
model.saveData()
|
|
74
|
-
applicationContext.dataStore.edit {
|
|
75
|
-
println("saveData ${model.scrollState.firstVisibleItemIndex}")
|
|
76
|
-
it[intPreferencesKey("scrollIndex")] = model.scrollState.firstVisibleItemIndex
|
|
77
|
-
it[intPreferencesKey("scrollOffset")] =
|
|
78
|
-
model.scrollState.firstVisibleItemScrollOffset
|
|
79
|
-
}
|
|
80
69
|
}
|
|
81
70
|
}
|
|
82
71
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/TextSettingsBottomSheet.kt
CHANGED
|
@@ -51,7 +51,6 @@ fun TextSettingsBottomSheet(model: AppViewModel) {
|
|
|
51
51
|
val uiMode = model.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
52
52
|
val scope = rememberCoroutineScope()
|
|
53
53
|
val sheetState = rememberModalBottomSheetState()
|
|
54
|
-
val fontType = FontType.valueOf(model.fontType)
|
|
55
54
|
return ModalBottomSheet(
|
|
56
55
|
tonalElevation = 2.dp,
|
|
57
56
|
sheetState = sheetState,
|
|
@@ -192,7 +191,7 @@ fun TextSettingsBottomSheet(model: AppViewModel) {
|
|
|
192
191
|
FontType.entries.map {
|
|
193
192
|
Surface(
|
|
194
193
|
shape = RoundedCornerShape(8.dp),
|
|
195
|
-
border = if (fontType == it) BorderStroke(
|
|
194
|
+
border = if (model.fontType == it) BorderStroke(
|
|
196
195
|
2.dp, MaterialTheme.colorScheme.primary
|
|
197
196
|
) else null,
|
|
198
197
|
modifier = Modifier
|
|
@@ -201,7 +200,7 @@ fun TextSettingsBottomSheet(model: AppViewModel) {
|
|
|
201
200
|
.padding(end = 16.dp)
|
|
202
201
|
.weight(1f),
|
|
203
202
|
onClick = {
|
|
204
|
-
model.fontType = it
|
|
203
|
+
model.fontType = it
|
|
205
204
|
}) {
|
|
206
205
|
Column(
|
|
207
206
|
modifier = Modifier.background(
|
|
@@ -216,7 +215,7 @@ fun TextSettingsBottomSheet(model: AppViewModel) {
|
|
|
216
215
|
fontFamily = it.family(),
|
|
217
216
|
fontSize = 18.sp,
|
|
218
217
|
fontWeight = FontWeight.W600,
|
|
219
|
-
color = if (fontType == it)
|
|
218
|
+
color = if (model.fontType == it)
|
|
220
219
|
MaterialTheme.colorScheme.primary
|
|
221
220
|
else
|
|
222
221
|
MaterialTheme.colorScheme.onSurface,
|
app/src/main/java/dev/pyrossh/onlyBible/composables/VerseView.kt
CHANGED
|
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|
|
13
13
|
import androidx.compose.foundation.layout.Row
|
|
14
14
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
15
|
import androidx.compose.foundation.layout.height
|
|
16
|
+
import androidx.compose.foundation.layout.padding
|
|
16
17
|
import androidx.compose.foundation.layout.size
|
|
17
18
|
import androidx.compose.foundation.layout.width
|
|
18
19
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
@@ -28,7 +29,6 @@ import androidx.compose.material3.MaterialTheme
|
|
|
28
29
|
import androidx.compose.material3.Surface
|
|
29
30
|
import androidx.compose.material3.Text
|
|
30
31
|
import androidx.compose.runtime.Composable
|
|
31
|
-
import androidx.compose.runtime.collectAsState
|
|
32
32
|
import androidx.compose.runtime.getValue
|
|
33
33
|
import androidx.compose.runtime.mutableIntStateOf
|
|
34
34
|
import androidx.compose.runtime.remember
|
|
@@ -52,7 +52,6 @@ import androidx.compose.ui.unit.dp
|
|
|
52
52
|
import androidx.compose.ui.unit.sp
|
|
53
53
|
import androidx.compose.ui.window.Popup
|
|
54
54
|
import dev.pyrossh.onlyBible.AppViewModel
|
|
55
|
-
import dev.pyrossh.onlyBible.FontType
|
|
56
55
|
import dev.pyrossh.onlyBible.R
|
|
57
56
|
import dev.pyrossh.onlyBible.darkHighlights
|
|
58
57
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
@@ -75,7 +74,6 @@ fun VerseView(
|
|
|
75
74
|
val scope = rememberCoroutineScope()
|
|
76
75
|
val context = LocalContext.current
|
|
77
76
|
val isLight = isLightTheme(model.uiMode, isSystemInDarkTheme())
|
|
78
|
-
val fontType = FontType.valueOf(model.fontType)
|
|
79
77
|
val fontSizeDelta = model.fontSizeDelta
|
|
80
78
|
val boldWeight = if (model.fontBoldEnabled) FontWeight.W700 else FontWeight.W400
|
|
81
79
|
val buttonInteractionSource = remember { MutableInteractionSource() }
|
|
@@ -107,7 +105,7 @@ fun VerseView(
|
|
|
107
105
|
currentHighlightColors[highlightedColorIndex]
|
|
108
106
|
else
|
|
109
107
|
Color.Unspecified,
|
|
110
|
-
fontFamily = fontType.family(),
|
|
108
|
+
fontFamily = model.fontType.family(),
|
|
111
109
|
color = if (isLight)
|
|
112
110
|
Color(0xFF000104)
|
|
113
111
|
else
|
|
@@ -194,7 +192,8 @@ fun VerseView(
|
|
|
194
192
|
) {
|
|
195
193
|
Row(
|
|
196
194
|
modifier = Modifier
|
|
197
|
-
.fillMaxSize()
|
|
195
|
+
.fillMaxSize()
|
|
196
|
+
.padding(horizontal = 4.dp),
|
|
198
197
|
horizontalArrangement = Arrangement.SpaceAround,
|
|
199
198
|
verticalAlignment = Alignment.CenterVertically,
|
|
200
199
|
) {
|
app/src/main/java/dev/pyrossh/onlyBible/domain/Verse.kt
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package dev.pyrossh.onlyBible.domain
|
|
2
2
|
|
|
3
3
|
import android.os.Parcelable
|
|
4
|
-
import androidx.appsearch.annotation.Document
|
|
5
|
-
import androidx.appsearch.app.AppSearchSchema
|
|
6
4
|
import kotlinx.parcelize.Parcelize
|
|
7
5
|
import kotlinx.serialization.Serializable
|
|
8
6
|
|
|
@@ -88,6 +86,8 @@ data class Verse(
|
|
|
88
86
|
val text: String,
|
|
89
87
|
) : Parcelable {
|
|
90
88
|
|
|
89
|
+
fun key() = "${bookIndex}:${chapterIndex}:${verseIndex}"
|
|
90
|
+
|
|
91
91
|
fun toSSML(voice: String): String {
|
|
92
92
|
return """
|
|
93
93
|
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
|
|
@@ -167,26 +167,5 @@ data class Verse(
|
|
|
167
167
|
1,
|
|
168
168
|
22
|
|
169
169
|
)
|
|
170
|
-
|
|
171
|
-
fun getForwardPair(book: Int, chapter: Int): Pair<Int, Int> {
|
|
172
|
-
val sizes = chapterSizes[book];
|
|
173
|
-
if (sizes > chapter + 1) {
|
|
174
|
-
return Pair(book, chapter + 1)
|
|
175
|
-
}
|
|
176
|
-
if (book + 1 < BOOKS_COUNT) {
|
|
177
|
-
return Pair(book + 1, 0)
|
|
178
|
-
}
|
|
179
|
-
return Pair(0, 0)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
fun getBackwardPair(book: Int, chapter: Int): Pair<Int, Int> {
|
|
183
|
-
if (chapter - 1 >= 0) {
|
|
184
|
-
return Pair(book, chapter - 1)
|
|
185
|
-
}
|
|
186
|
-
if (book - 1 >= 0) {
|
|
187
|
-
return Pair(book - 1, chapterSizes[book - 1] - 1)
|
|
188
|
-
}
|
|
189
|
-
return Pair(BOOKS_COUNT - 1, chapterSizes[BOOKS_COUNT - 1] - 1)
|
|
190
|
-
}
|
|
191
170
|
}
|
|
192
171
|
}
|