~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.
f635a25b
—
Peter John 1 year ago
improve viewModel
- app/build.gradle.kts +1 -0
- app/src/main/java/dev/pyrossh/onlyBible/AppDrawer.kt +6 -6
- app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt +6 -7
- app/src/main/java/dev/pyrossh/onlyBible/AppTheme.kt +4 -2
- app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt +115 -45
- app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt +16 -12
- app/src/main/java/dev/pyrossh/onlyBible/Hooks.kt +0 -25
- app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt +6 -9
- app/src/main/java/dev/pyrossh/onlyBible/TextSettingsBottomSheet.kt +12 -13
- gradle/libs.versions.toml +7 -5
app/build.gradle.kts
CHANGED
|
@@ -87,4 +87,5 @@ dependencies {
|
|
|
87
87
|
implementation(libs.androidx.datastore.preferences)
|
|
88
88
|
implementation(libs.androidx.core.splashscreen)
|
|
89
89
|
implementation(libs.compose.remember.preference)
|
|
90
|
+
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
|
90
91
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/AppDrawer.kt
CHANGED
|
@@ -38,6 +38,7 @@ import androidx.compose.ui.text.TextStyle
|
|
|
38
38
|
import androidx.compose.ui.text.font.FontWeight
|
|
39
39
|
import androidx.compose.ui.unit.dp
|
|
40
40
|
import androidx.compose.ui.unit.sp
|
|
41
|
+
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
41
42
|
import androidx.navigation.NavController
|
|
42
43
|
import kotlinx.coroutines.Job
|
|
43
44
|
import kotlinx.coroutines.launch
|
|
@@ -77,12 +78,11 @@ val bibles = listOf(
|
|
|
77
78
|
|
|
78
79
|
@Composable
|
|
79
80
|
fun AppDrawer(
|
|
80
|
-
|
|
81
|
+
model: AppViewModel = viewModel(),
|
|
81
82
|
navController: NavController,
|
|
82
83
|
content: @Composable ((MenuType, Int) -> Job) -> Unit
|
|
83
84
|
) {
|
|
84
85
|
val context = LocalContext.current
|
|
85
|
-
val state = LocalSettings.current!!
|
|
86
86
|
val scope = rememberCoroutineScope()
|
|
87
87
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
|
88
88
|
var bookIndex by rememberSaveable {
|
|
@@ -141,7 +141,7 @@ fun AppDrawer(
|
|
|
141
141
|
}
|
|
142
142
|
items(bibles) { b ->
|
|
143
143
|
QuickButton(b) {
|
|
144
|
-
|
|
144
|
+
model.setBibleName(context, b)
|
|
145
145
|
scope.launch {
|
|
146
146
|
drawerState.close()
|
|
147
147
|
}
|
|
@@ -177,7 +177,7 @@ fun AppDrawer(
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
items(39) { b ->
|
|
180
|
-
QuickButton(shortName(bookNames[b])) {
|
|
180
|
+
QuickButton(shortName(model.bookNames[b])) {
|
|
181
181
|
bookIndex = b
|
|
182
182
|
menuType = MenuType.Chapter
|
|
183
183
|
}
|
|
@@ -197,7 +197,7 @@ fun AppDrawer(
|
|
|
197
197
|
}
|
|
198
198
|
items(27) { i ->
|
|
199
199
|
val b = 39 + i
|
|
200
|
-
QuickButton(shortName(bookNames[b])) {
|
|
200
|
+
QuickButton(shortName(model.bookNames[b])) {
|
|
201
201
|
bookIndex = b
|
|
202
202
|
menuType = MenuType.Chapter
|
|
203
203
|
}
|
|
@@ -219,7 +219,7 @@ fun AppDrawer(
|
|
|
219
219
|
verticalAlignment = Alignment.CenterVertically,
|
|
220
220
|
) {
|
|
221
221
|
Text(
|
|
222
|
-
text = bookNames[bookIndex],
|
|
222
|
+
text = model.bookNames[bookIndex],
|
|
223
223
|
fontSize = 20.sp,
|
|
224
224
|
fontWeight = FontWeight.W500
|
|
225
225
|
)
|
app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt
CHANGED
|
@@ -15,6 +15,7 @@ import androidx.compose.runtime.getValue
|
|
|
15
15
|
import androidx.compose.runtime.setValue
|
|
16
16
|
import androidx.compose.ui.Alignment
|
|
17
17
|
import androidx.compose.ui.Modifier
|
|
18
|
+
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
18
19
|
import androidx.navigation.compose.NavHost
|
|
19
20
|
import androidx.navigation.compose.composable
|
|
20
21
|
import androidx.navigation.compose.rememberNavController
|
|
@@ -22,12 +23,11 @@ import androidx.navigation.toRoute
|
|
|
22
23
|
import dev.burnoo.compose.rememberpreference.rememberIntPreference
|
|
23
24
|
|
|
24
25
|
@Composable
|
|
25
|
-
fun AppHost() {
|
|
26
|
+
fun AppHost(model: AppViewModel = viewModel()) {
|
|
26
27
|
val navController = rememberNavController()
|
|
27
28
|
var bookIndex by rememberIntPreference(keyName = "bookIndex", initialValue = 0, defaultValue = 0)
|
|
28
29
|
var chapterIndex by rememberIntPreference(keyName = "chapterIndex", initialValue = 0, defaultValue = 0)
|
|
29
|
-
val model = LocalSettings.current!!
|
|
30
|
-
if (model.
|
|
30
|
+
if (model.isLoading) {
|
|
31
31
|
Box(
|
|
32
32
|
modifier = Modifier
|
|
33
33
|
.fillMaxWidth()
|
|
@@ -42,8 +42,8 @@ fun AppHost() {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
} else {
|
|
45
|
-
val bookNames = model.
|
|
45
|
+
val bookNames = model.verses.distinctBy { it.bookName }.map { it.bookName }
|
|
46
|
-
AppDrawer(
|
|
46
|
+
AppDrawer(navController = navController) { openDrawer ->
|
|
47
47
|
NavHost(
|
|
48
48
|
navController = navController,
|
|
49
49
|
startDestination = ChapterScreenProps(bookIndex, chapterIndex)
|
|
@@ -82,8 +82,7 @@ fun AppHost() {
|
|
|
82
82
|
chapterIndex = props.chapterIndex
|
|
83
83
|
}
|
|
84
84
|
ChapterScreen(
|
|
85
|
-
|
|
85
|
+
model = model,
|
|
86
|
-
verses = model.uiState.value.verses,
|
|
87
86
|
bookIndex = props.bookIndex,
|
|
88
87
|
chapterIndex = props.chapterIndex,
|
|
89
88
|
navController = navController,
|
app/src/main/java/dev/pyrossh/onlyBible/AppTheme.kt
CHANGED
|
@@ -12,6 +12,7 @@ import androidx.compose.ui.graphics.Color
|
|
|
12
12
|
import androidx.compose.ui.platform.LocalContext
|
|
13
13
|
import androidx.compose.ui.text.font.FontFamily
|
|
14
14
|
import androidx.compose.ui.text.font.GenericFontFamily
|
|
15
|
+
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
15
16
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
|
16
17
|
|
|
17
18
|
enum class FontType {
|
|
@@ -53,14 +54,15 @@ fun getColorScheme(context: Context, themeType: ThemeType, darkTheme: Boolean):
|
|
|
53
54
|
|
|
54
55
|
@Composable
|
|
55
56
|
fun AppTheme(
|
|
57
|
+
model: AppViewModel = viewModel(),
|
|
56
58
|
content: @Composable() () -> Unit
|
|
57
59
|
) {
|
|
58
60
|
val context = LocalContext.current
|
|
59
61
|
val darkTheme = isSystemInDarkTheme()
|
|
60
62
|
val systemUiController = rememberSystemUiController()
|
|
61
|
-
val
|
|
63
|
+
val themeType = ThemeType.valueOf(model.themeType)
|
|
62
64
|
val colorScheme = getColorScheme(context, themeType, darkTheme)
|
|
63
|
-
LaunchedEffect(key1 = themeType) {
|
|
65
|
+
LaunchedEffect(key1 = model.themeType) {
|
|
64
66
|
systemUiController.setSystemBarsColor(
|
|
65
67
|
color = colorScheme.background
|
|
66
68
|
)
|
app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt
CHANGED
|
@@ -1,51 +1,83 @@
|
|
|
1
1
|
package dev.pyrossh.onlyBible
|
|
2
2
|
|
|
3
|
+
import android.app.Application
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import android.content.Intent
|
|
5
|
-
import android.content.SharedPreferences
|
|
6
|
-
import androidx.compose.runtime.
|
|
6
|
+
import androidx.compose.runtime.MutableState
|
|
7
7
|
import androidx.compose.runtime.getValue
|
|
8
8
|
import androidx.compose.runtime.mutableStateOf
|
|
9
9
|
import androidx.compose.runtime.setValue
|
|
10
|
-
import androidx.
|
|
10
|
+
import androidx.datastore.preferences.core.Preferences
|
|
11
|
+
import androidx.datastore.preferences.core.booleanPreferencesKey
|
|
12
|
+
import androidx.datastore.preferences.core.edit
|
|
13
|
+
import androidx.datastore.preferences.core.intPreferencesKey
|
|
14
|
+
import androidx.datastore.preferences.core.stringPreferencesKey
|
|
15
|
+
import androidx.datastore.preferences.preferencesDataStore
|
|
11
|
-
import androidx.lifecycle.
|
|
16
|
+
import androidx.lifecycle.AndroidViewModel
|
|
12
17
|
import androidx.lifecycle.viewModelScope
|
|
13
18
|
import com.microsoft.cognitiveservices.speech.SpeechConfig
|
|
14
19
|
import com.microsoft.cognitiveservices.speech.SpeechSynthesizer
|
|
15
20
|
import kotlinx.coroutines.CoroutineScope
|
|
16
21
|
import kotlinx.coroutines.Dispatchers
|
|
17
22
|
import kotlinx.coroutines.delay
|
|
23
|
+
import kotlinx.coroutines.flow.collectLatest
|
|
24
|
+
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
25
|
+
import kotlinx.coroutines.flow.map
|
|
18
26
|
import kotlinx.coroutines.launch
|
|
19
27
|
import kotlinx.coroutines.withContext
|
|
20
28
|
import java.io.IOException
|
|
21
29
|
import java.util.concurrent.Future
|
|
22
30
|
|
|
23
|
-
val
|
|
31
|
+
internal val Context.dataStore by preferencesDataStore(name = "onlyBible")
|
|
24
32
|
|
|
33
|
+
class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
25
|
-
|
|
34
|
+
private val context
|
|
35
|
+
get() = getApplication<Application>()
|
|
26
|
-
|
|
36
|
+
var isLoading by mutableStateOf(true)
|
|
27
|
-
|
|
37
|
+
var isOnError by mutableStateOf(false)
|
|
28
|
-
|
|
38
|
+
var bibleName by mutableStateOf("English")
|
|
29
|
-
|
|
39
|
+
var verses by mutableStateOf(listOf<Verse>())
|
|
40
|
+
var bookNames by mutableStateOf(listOf<String>())
|
|
41
|
+
var showBottomSheet by mutableStateOf(false)
|
|
42
|
+
var themeType by preferenceMutableState(
|
|
43
|
+
coroutineScope = viewModelScope,
|
|
44
|
+
context = context,
|
|
45
|
+
keyName = "themeType",
|
|
46
|
+
initialValue = ThemeType.Auto.name,
|
|
47
|
+
defaultValue = ThemeType.Auto.name,
|
|
48
|
+
getPreferencesKey = ::stringPreferencesKey,
|
|
30
|
-
)
|
|
49
|
+
)
|
|
50
|
+
var fontType by preferenceMutableState(
|
|
51
|
+
coroutineScope = viewModelScope,
|
|
52
|
+
context = context,
|
|
53
|
+
keyName = "fontType",
|
|
54
|
+
initialValue = FontType.Sans.name,
|
|
55
|
+
defaultValue = FontType.Sans.name,
|
|
56
|
+
getPreferencesKey = ::stringPreferencesKey,
|
|
57
|
+
)
|
|
58
|
+
var fontSizeDelta by preferenceMutableState(
|
|
59
|
+
coroutineScope = viewModelScope,
|
|
60
|
+
context = context,
|
|
61
|
+
keyName = "fontSizeDelta",
|
|
62
|
+
initialValue = 0,
|
|
63
|
+
defaultValue = 0,
|
|
64
|
+
getPreferencesKey = ::intPreferencesKey,
|
|
65
|
+
)
|
|
66
|
+
var fontBoldEnabled by preferenceMutableState(
|
|
67
|
+
coroutineScope = viewModelScope,
|
|
68
|
+
context = context,
|
|
69
|
+
keyName = "fontBoldEnabled",
|
|
70
|
+
initialValue = false,
|
|
71
|
+
defaultValue = false,
|
|
72
|
+
getPreferencesKey = ::booleanPreferencesKey,
|
|
73
|
+
)
|
|
31
74
|
|
|
32
|
-
class AppViewModel() : ViewModel() {
|
|
33
75
|
|
|
34
|
-
|
|
76
|
+
fun isDarkTheme(isSystemDark: Boolean): Boolean {
|
|
77
|
+
val themeType = ThemeType.valueOf(themeType)
|
|
35
|
-
return
|
|
78
|
+
return themeType == ThemeType.Dark || (themeType == ThemeType.Auto && isSystemDark)
|
|
36
79
|
}
|
|
37
80
|
|
|
38
|
-
private val _uiState = mutableStateOf(
|
|
39
|
-
UiState(
|
|
40
|
-
isLoading = true,
|
|
41
|
-
isOnError = false,
|
|
42
|
-
bibleName = "English",
|
|
43
|
-
verses = listOf(),
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
val uiState: State<UiState> = _uiState
|
|
47
|
-
var showBottomSheet by mutableStateOf(false)
|
|
48
|
-
|
|
49
81
|
fun showSheet() {
|
|
50
82
|
showBottomSheet = true
|
|
51
83
|
}
|
|
@@ -55,26 +87,21 @@ class AppViewModel() : ViewModel() {
|
|
|
55
87
|
}
|
|
56
88
|
|
|
57
89
|
fun setBibleName(context: Context, b: String) {
|
|
58
|
-
_uiState.value = uiState.value.copy(
|
|
59
|
-
|
|
90
|
+
bibleName = b
|
|
60
|
-
)
|
|
61
|
-
|
|
91
|
+
context.getSharedPreferences("settings", Context.MODE_PRIVATE).edit().putString("bibleName", b).apply()
|
|
62
92
|
loadBible(context)
|
|
63
93
|
}
|
|
64
94
|
|
|
65
|
-
|
|
66
95
|
fun loadBible(context: Context) {
|
|
67
96
|
viewModelScope.launch(Dispatchers.IO) {
|
|
68
97
|
launch(Dispatchers.Main) {
|
|
69
|
-
_uiState.value = uiState.value.copy(
|
|
70
|
-
|
|
98
|
+
isLoading = true
|
|
71
|
-
|
|
99
|
+
isOnError = false
|
|
72
|
-
)
|
|
73
100
|
}
|
|
74
101
|
try {
|
|
75
102
|
val buffer =
|
|
76
|
-
context.assets.open("bibles/${
|
|
103
|
+
context.assets.open("bibles/${bibleName}.txt").bufferedReader()
|
|
77
|
-
val
|
|
104
|
+
val localVerses = buffer.readLines().filter { it.isNotEmpty() }.map {
|
|
78
105
|
val arr = it.split("|")
|
|
79
106
|
val bookName = arr[0]
|
|
80
107
|
val book = arr[1].toInt()
|
|
@@ -92,19 +119,16 @@ class AppViewModel() : ViewModel() {
|
|
|
92
119
|
)
|
|
93
120
|
}
|
|
94
121
|
launch(Dispatchers.Main) {
|
|
95
|
-
_uiState.value = uiState.value.copy(
|
|
96
|
-
|
|
122
|
+
isLoading = false
|
|
97
|
-
|
|
123
|
+
isOnError = false
|
|
98
|
-
|
|
124
|
+
verses = localVerses
|
|
99
|
-
|
|
125
|
+
bookNames = localVerses.distinctBy { it.bookName }.map { it.bookName }
|
|
100
126
|
}
|
|
101
127
|
} catch (e: IOException) {
|
|
102
128
|
e.printStackTrace()
|
|
103
129
|
launch(Dispatchers.Main) {
|
|
104
|
-
_uiState.value = uiState.value.copy(
|
|
105
|
-
|
|
130
|
+
isLoading = false
|
|
106
|
-
|
|
131
|
+
isOnError = true
|
|
107
|
-
)
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
}
|
|
@@ -169,4 +193,50 @@ fun shareVerses(context: Context, verses: List<Verse>) {
|
|
|
169
193
|
}
|
|
170
194
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
|
171
195
|
context.startActivity(shareIntent)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private inline fun <reified T, reified NNT : T> preferenceMutableState(
|
|
199
|
+
coroutineScope: CoroutineScope,
|
|
200
|
+
context: Context,
|
|
201
|
+
keyName: String,
|
|
202
|
+
initialValue: T,
|
|
203
|
+
defaultValue: T,
|
|
204
|
+
getPreferencesKey: (keyName: String) -> Preferences.Key<NNT>,
|
|
205
|
+
): MutableState<T> {
|
|
206
|
+
val snapshotMutableState: MutableState<T> = mutableStateOf(initialValue)
|
|
207
|
+
val key: Preferences.Key<NNT> = getPreferencesKey(keyName)
|
|
208
|
+
coroutineScope.launch {
|
|
209
|
+
context.dataStore.data
|
|
210
|
+
.map { if (it[key] == null) defaultValue else it[key] }
|
|
211
|
+
.distinctUntilChanged()
|
|
212
|
+
.collectLatest {
|
|
213
|
+
withContext(Dispatchers.Main) {
|
|
214
|
+
snapshotMutableState.value = it as T
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return object : MutableState<T> {
|
|
219
|
+
override var value: T
|
|
220
|
+
get() = snapshotMutableState.value
|
|
221
|
+
set(value) {
|
|
222
|
+
val rollbackValue = snapshotMutableState.value
|
|
223
|
+
snapshotMutableState.value = value
|
|
224
|
+
coroutineScope.launch {
|
|
225
|
+
try {
|
|
226
|
+
context.dataStore.edit {
|
|
227
|
+
if (value != null) {
|
|
228
|
+
it[key] = value as NNT
|
|
229
|
+
} else {
|
|
230
|
+
it.remove(key)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (e: Exception) {
|
|
234
|
+
snapshotMutableState.value = rollbackValue
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
override fun component1() = value
|
|
240
|
+
override fun component2(): (T) -> Unit = { value = it }
|
|
241
|
+
}
|
|
172
242
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt
CHANGED
|
@@ -11,6 +11,7 @@ import androidx.compose.animation.AnimatedContentTransitionScope
|
|
|
11
11
|
import androidx.compose.foundation.clickable
|
|
12
12
|
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
|
13
13
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
14
|
+
import androidx.compose.foundation.isSystemInDarkTheme
|
|
14
15
|
import androidx.compose.foundation.layout.Arrangement
|
|
15
16
|
import androidx.compose.foundation.layout.Row
|
|
16
17
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
@@ -86,19 +87,17 @@ enum class Dir : Parcelable {
|
|
|
86
87
|
@SuppressLint("MutableCollectionMutableState")
|
|
87
88
|
@Composable
|
|
88
89
|
fun ChapterScreen(
|
|
89
|
-
bookNames: List<String>,
|
|
90
|
-
|
|
90
|
+
model: AppViewModel,
|
|
91
91
|
bookIndex: Int,
|
|
92
92
|
chapterIndex: Int,
|
|
93
93
|
navController: NavController,
|
|
94
94
|
openDrawer: (MenuType, Int) -> Job,
|
|
95
95
|
) {
|
|
96
96
|
val context = LocalContext.current
|
|
97
|
-
val state = LocalSettings.current!!
|
|
98
|
-
val darkTheme =
|
|
97
|
+
val darkTheme = model.isDarkTheme(isSystemInDarkTheme())
|
|
99
|
-
val
|
|
98
|
+
val fontType = FontType.valueOf(model.fontType)
|
|
100
|
-
val fontSizeDelta =
|
|
99
|
+
val fontSizeDelta = model.fontSizeDelta
|
|
101
|
-
val boldWeight =
|
|
100
|
+
val boldWeight = if (model.fontBoldEnabled) FontWeight.W700 else FontWeight.W400
|
|
102
101
|
val scope = rememberCoroutineScope()
|
|
103
102
|
var selectedVerses by rememberSaveable {
|
|
104
103
|
mutableStateOf(listOf<Verse>())
|
|
@@ -107,7 +106,7 @@ fun ChapterScreen(
|
|
|
107
106
|
mutableFloatStateOf(0.0f)
|
|
108
107
|
}
|
|
109
108
|
val chapterVerses =
|
|
110
|
-
verses.filter { it.bookIndex == bookIndex && it.chapterIndex == chapterIndex }
|
|
109
|
+
model.verses.filter { it.bookIndex == bookIndex && it.chapterIndex == chapterIndex }
|
|
111
110
|
val headingColor = MaterialTheme.colorScheme.onSurface // MaterialTheme.colorScheme.primary,
|
|
112
111
|
Scaffold(
|
|
113
112
|
modifier = Modifier
|
|
@@ -127,7 +126,7 @@ fun ChapterScreen(
|
|
|
127
126
|
modifier = Modifier.clickable {
|
|
128
127
|
openDrawer(MenuType.Book, bookIndex)
|
|
129
128
|
},
|
|
130
|
-
text = bookNames[bookIndex],
|
|
129
|
+
text = model.bookNames[bookIndex],
|
|
131
130
|
style = TextStyle(
|
|
132
131
|
fontSize = 22.sp,
|
|
133
132
|
fontWeight = FontWeight.W500,
|
|
@@ -175,18 +174,23 @@ fun ChapterScreen(
|
|
|
175
174
|
}
|
|
176
175
|
TextButton(onClick = { openDrawer(MenuType.Bible, bookIndex) }) {
|
|
177
176
|
Text(
|
|
178
|
-
text =
|
|
177
|
+
text = model.bibleName.substring(0, 2).uppercase(),
|
|
179
178
|
style = TextStyle(
|
|
180
179
|
fontSize = 18.sp,
|
|
181
180
|
fontWeight = FontWeight.W500,
|
|
181
|
+
color = headingColor,
|
|
182
182
|
),
|
|
183
183
|
)
|
|
184
184
|
}
|
|
185
185
|
TextButton(
|
|
186
186
|
onClick = {
|
|
187
|
-
|
|
187
|
+
model.showSheet()
|
|
188
188
|
}) {
|
|
189
|
+
Icon(
|
|
190
|
+
imageVector = Icons.Outlined.MoreVert,
|
|
189
|
-
|
|
191
|
+
contentDescription = "More",
|
|
192
|
+
tint = headingColor,
|
|
193
|
+
)
|
|
190
194
|
}
|
|
191
195
|
},
|
|
192
196
|
)
|
app/src/main/java/dev/pyrossh/onlyBible/Hooks.kt
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
package dev.pyrossh.onlyBible
|
|
2
|
-
|
|
3
|
-
import androidx.compose.foundation.isSystemInDarkTheme
|
|
4
|
-
import androidx.compose.runtime.Composable
|
|
5
|
-
import androidx.compose.runtime.getValue
|
|
6
|
-
import androidx.compose.runtime.setValue
|
|
7
|
-
import dev.burnoo.compose.rememberpreference.rememberStringPreference
|
|
8
|
-
|
|
9
|
-
@Composable
|
|
10
|
-
fun isDarkMode(): Boolean {
|
|
11
|
-
val (themeType) = rememberThemeType()
|
|
12
|
-
return themeType == ThemeType.Dark || (themeType == ThemeType.Auto && isSystemInDarkTheme())
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@Composable
|
|
16
|
-
fun rememberThemeType(): Pair<ThemeType, (ThemeType) -> Unit> {
|
|
17
|
-
var data by rememberStringPreference(keyName = "themeType", initialValue = ThemeType.Auto.name, defaultValue = ThemeType.Auto.name)
|
|
18
|
-
return Pair(ThemeType.valueOf(data)) { data = it.name }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@Composable
|
|
22
|
-
fun rememberFontType(): Pair<FontType, (FontType) -> Unit> {
|
|
23
|
-
var data by rememberStringPreference(keyName = "fontType", initialValue = FontType.Sans.name, defaultValue = FontType.Sans.name)
|
|
24
|
-
return Pair(FontType.valueOf(data)) { data = it.name }
|
|
25
|
-
}
|
app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt
CHANGED
|
@@ -5,26 +5,23 @@ 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
|
|
9
8
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
10
9
|
|
|
11
10
|
class MainActivity : ComponentActivity() {
|
|
12
11
|
|
|
13
|
-
private val model
|
|
12
|
+
private val model by viewModels<AppViewModel>()
|
|
14
13
|
|
|
15
14
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
16
15
|
val splashScreen = installSplashScreen()
|
|
17
16
|
super.onCreate(savedInstanceState)
|
|
18
17
|
enableEdgeToEdge()
|
|
19
18
|
model.loadBible(applicationContext)
|
|
20
|
-
splashScreen.setKeepOnScreenCondition{model.
|
|
19
|
+
splashScreen.setKeepOnScreenCondition { model.isLoading }
|
|
21
20
|
setContent {
|
|
22
|
-
CompositionLocalProvider(LocalSettings provides model) {
|
|
23
|
-
|
|
21
|
+
AppTheme {
|
|
24
|
-
|
|
22
|
+
AppHost()
|
|
25
|
-
|
|
23
|
+
if (model.showBottomSheet) {
|
|
26
|
-
|
|
24
|
+
TextSettingsBottomSheet()
|
|
27
|
-
}
|
|
28
25
|
}
|
|
29
26
|
}
|
|
30
27
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/TextSettingsBottomSheet.kt
CHANGED
|
@@ -35,6 +35,7 @@ import androidx.compose.ui.text.TextStyle
|
|
|
35
35
|
import androidx.compose.ui.text.font.FontWeight
|
|
36
36
|
import androidx.compose.ui.unit.dp
|
|
37
37
|
import androidx.compose.ui.unit.sp
|
|
38
|
+
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
38
39
|
import dev.pyrossh.onlyBible.ThemeType.Auto
|
|
39
40
|
import dev.pyrossh.onlyBible.ThemeType.Dark
|
|
40
41
|
import dev.pyrossh.onlyBible.ThemeType.Light
|
|
@@ -42,13 +43,11 @@ import kotlinx.coroutines.launch
|
|
|
42
43
|
|
|
43
44
|
@Composable
|
|
44
45
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
45
|
-
fun TextSettingsBottomSheet() {
|
|
46
|
+
fun TextSettingsBottomSheet(model: AppViewModel = viewModel()) {
|
|
46
47
|
val scope = rememberCoroutineScope()
|
|
47
48
|
val sheetState = rememberModalBottomSheetState()
|
|
48
|
-
val settings = LocalSettings.current!!
|
|
49
|
-
val fontSizeDelta = 0
|
|
50
|
-
val (fontType, setFontType) = rememberFontType()
|
|
51
|
-
val
|
|
49
|
+
val themeType = ThemeType.valueOf(model.themeType)
|
|
50
|
+
val fontType = FontType.valueOf(model.fontType)
|
|
52
51
|
return ModalBottomSheet(
|
|
53
52
|
tonalElevation = 2.dp,
|
|
54
53
|
sheetState = sheetState,
|
|
@@ -56,7 +55,7 @@ fun TextSettingsBottomSheet() {
|
|
|
56
55
|
scope.launch {
|
|
57
56
|
sheetState.hide()
|
|
58
57
|
}.invokeOnCompletion {
|
|
59
|
-
|
|
58
|
+
model.closeSheet()
|
|
60
59
|
}
|
|
61
60
|
},
|
|
62
61
|
) {
|
|
@@ -83,7 +82,7 @@ fun TextSettingsBottomSheet() {
|
|
|
83
82
|
scope.launch {
|
|
84
83
|
sheetState.hide()
|
|
85
84
|
}.invokeOnCompletion {
|
|
86
|
-
|
|
85
|
+
model.closeSheet()
|
|
87
86
|
}
|
|
88
87
|
}) {
|
|
89
88
|
Icon(Icons.Filled.Close, "Close")
|
|
@@ -105,7 +104,7 @@ fun TextSettingsBottomSheet() {
|
|
|
105
104
|
.padding(end = 16.dp)
|
|
106
105
|
.weight(1f),
|
|
107
106
|
onClick = {
|
|
108
|
-
|
|
107
|
+
model.fontSizeDelta -= 1
|
|
109
108
|
}) {
|
|
110
109
|
Column(
|
|
111
110
|
modifier = Modifier.background(MaterialTheme.colorScheme.background),
|
|
@@ -126,7 +125,7 @@ fun TextSettingsBottomSheet() {
|
|
|
126
125
|
.padding(end = 16.dp)
|
|
127
126
|
.weight(1f),
|
|
128
127
|
onClick = {
|
|
129
|
-
|
|
128
|
+
model.fontSizeDelta += 1
|
|
130
129
|
}) {
|
|
131
130
|
Column(
|
|
132
131
|
modifier = Modifier.background(MaterialTheme.colorScheme.background),
|
|
@@ -146,7 +145,7 @@ fun TextSettingsBottomSheet() {
|
|
|
146
145
|
.padding(end = 16.dp)
|
|
147
146
|
.weight(1f),
|
|
148
147
|
onClick = {
|
|
149
|
-
|
|
148
|
+
model.fontBoldEnabled = !model.fontBoldEnabled
|
|
150
149
|
}) {
|
|
151
150
|
Column(
|
|
152
151
|
modifier = Modifier.background(MaterialTheme.colorScheme.background),
|
|
@@ -198,7 +197,7 @@ fun TextSettingsBottomSheet() {
|
|
|
198
197
|
.padding(end = 16.dp)
|
|
199
198
|
.weight(1f),
|
|
200
199
|
onClick = {
|
|
201
|
-
|
|
200
|
+
model.fontType = it.name
|
|
202
201
|
}) {
|
|
203
202
|
Column(
|
|
204
203
|
modifier = Modifier.background(
|
|
@@ -252,8 +251,8 @@ fun TextSettingsBottomSheet() {
|
|
|
252
251
|
onClick = {
|
|
253
252
|
scope.launch {
|
|
254
253
|
sheetState.hide()
|
|
255
|
-
|
|
254
|
+
model.closeSheet()
|
|
256
|
-
|
|
255
|
+
model.themeType = it.name
|
|
257
256
|
}
|
|
258
257
|
}
|
|
259
258
|
) {
|
gradle/libs.versions.toml
CHANGED
|
@@ -3,7 +3,7 @@ accompanistSystemuicontroller = "0.27.0"
|
|
|
3
3
|
agp = "8.4.2"
|
|
4
4
|
clientSdk = "1.34.0"
|
|
5
5
|
composeRememberPreference = "1.1.0"
|
|
6
|
-
coreSplashscreen = "1.0.
|
|
6
|
+
coreSplashscreen = "1.0.1"
|
|
7
7
|
datastorePreferences = "1.1.1"
|
|
8
8
|
foundation = "1.6.8"
|
|
9
9
|
kotlin = "2.0.0"
|
|
@@ -11,13 +11,14 @@ kotlinxCoroutinesCore = "1.9.0-RC"
|
|
|
11
11
|
kotlinxSerialization = "1.7.0"
|
|
12
12
|
coreKtx = "1.13.1"
|
|
13
13
|
junit = "4.13.2"
|
|
14
|
-
junitVersion = "1.2.
|
|
14
|
+
junitVersion = "1.2.1"
|
|
15
|
-
espressoCore = "3.6.
|
|
15
|
+
espressoCore = "3.6.1"
|
|
16
|
-
lifecycleRuntimeKtx = "2.8.
|
|
16
|
+
lifecycleRuntimeKtx = "2.8.3"
|
|
17
17
|
activityCompose = "1.9.0"
|
|
18
18
|
composeBom = "2024.06.00"
|
|
19
|
+
lifecycleViewmodelCompose = "2.8.3"
|
|
19
20
|
materialIconsExtended = "1.6.8"
|
|
20
|
-
navigationFragmentKtx = "2.8.0-
|
|
21
|
+
navigationFragmentKtx = "2.8.0-beta05"
|
|
21
22
|
secretsGradlePlugin = "2.0.1"
|
|
22
23
|
uiTextGoogleFonts = "1.6.8"
|
|
23
24
|
uiUtilAndroid = "1.6.8"
|
|
@@ -28,6 +29,7 @@ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref =
|
|
|
28
29
|
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
|
|
29
30
|
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
|
30
31
|
androidx-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "foundation" }
|
|
32
|
+
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
|
|
31
33
|
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
|
|
32
34
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationFragmentKtx" }
|
|
33
35
|
androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
|