~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.
db3ee3f1
—
Peter John 1 year ago
fix scroll restore and add splash
- app/src/main/AndroidManifest.xml +2 -2
- app/src/main/java/dev/pyrossh/onlyBible/AppDrawer.kt +2 -3
- app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt +50 -2
- app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt +13 -0
- app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt +8 -48
- app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt +35 -2
- app/src/main/res/values/themes.xml +5 -1
app/src/main/AndroidManifest.xml
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
android:icon="@mipmap/ic_launcher"
|
|
9
9
|
android:roundIcon="@mipmap/ic_launcher_round"
|
|
10
10
|
android:supportsRtl="true"
|
|
11
|
-
android:theme="@style/Theme.
|
|
11
|
+
android:theme="@style/Theme.BibleAppSplash"
|
|
12
12
|
>
|
|
13
13
|
<activity
|
|
14
14
|
android:name=".MainActivity"
|
|
15
15
|
android:exported="true"
|
|
16
|
-
android:theme="@style/Theme.
|
|
16
|
+
android:theme="@style/Theme.BibleAppSplash">
|
|
17
17
|
<intent-filter>
|
|
18
18
|
<action android:name="android.intent.action.MAIN" />
|
|
19
19
|
|
app/src/main/java/dev/pyrossh/onlyBible/AppDrawer.kt
CHANGED
|
@@ -38,7 +38,6 @@ 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.navigation.NavController
|
|
42
41
|
import dev.pyrossh.onlyBible.domain.Bible
|
|
43
42
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
44
43
|
import kotlinx.coroutines.Job
|
|
@@ -66,7 +65,7 @@ fun LazyGridScope.header(
|
|
|
66
65
|
@Composable
|
|
67
66
|
fun AppDrawer(
|
|
68
67
|
model: AppViewModel,
|
|
69
|
-
|
|
68
|
+
navigateToChapter: (ChapterScreenProps) -> Unit,
|
|
70
69
|
content: @Composable ((MenuType, Int) -> Job) -> Unit
|
|
71
70
|
) {
|
|
72
71
|
val context = LocalContext.current
|
|
@@ -224,7 +223,7 @@ fun AppDrawer(
|
|
|
224
223
|
items(Verse.chapterSizes[bookIndex]) { c ->
|
|
225
224
|
QuickButton("${c + 1}") {
|
|
226
225
|
scope.launch {
|
|
227
|
-
|
|
226
|
+
navigateToChapter(
|
|
228
227
|
ChapterScreenProps(
|
|
229
228
|
bookIndex = bookIndex,
|
|
230
229
|
chapterIndex = c,
|
app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt
CHANGED
|
@@ -17,10 +17,57 @@ import androidx.navigation.compose.NavHost
|
|
|
17
17
|
import androidx.navigation.compose.composable
|
|
18
18
|
import androidx.navigation.compose.rememberNavController
|
|
19
19
|
import androidx.navigation.toRoute
|
|
20
|
+
import dev.pyrossh.onlyBible.domain.Verse
|
|
20
21
|
|
|
21
22
|
@Composable
|
|
22
23
|
fun AppHost(model: AppViewModel = viewModel()) {
|
|
23
24
|
val navController = rememberNavController()
|
|
25
|
+
val navigateToChapter = { props: ChapterScreenProps ->
|
|
26
|
+
model.resetScrollState()
|
|
27
|
+
navController.navigate(props)
|
|
28
|
+
}
|
|
29
|
+
val onSwipeLeft = {
|
|
30
|
+
val pair = Verse.getForwardPair(model.bookIndex, model.chapterIndex)
|
|
31
|
+
navigateToChapter(
|
|
32
|
+
ChapterScreenProps(
|
|
33
|
+
bookIndex = pair.first,
|
|
34
|
+
chapterIndex = pair.second,
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
val onSwipeRight = {
|
|
39
|
+
val pair = Verse.getBackwardPair(model.bookIndex, model.chapterIndex)
|
|
40
|
+
if (navController.previousBackStackEntry != null) {
|
|
41
|
+
val previousBook =
|
|
42
|
+
navController.previousBackStackEntry?.arguments?.getInt("book")
|
|
43
|
+
?: 0
|
|
44
|
+
val previousChapter =
|
|
45
|
+
navController.previousBackStackEntry?.arguments?.getInt("chapter")
|
|
46
|
+
?: 0
|
|
47
|
+
// println("currentBackStackEntry ${previousBook} ${previousChapter} || ${pair.first} ${pair.second}")
|
|
48
|
+
if (previousBook == pair.first && previousChapter == pair.second) {
|
|
49
|
+
println("Popped")
|
|
50
|
+
navController.popBackStack()
|
|
51
|
+
} else {
|
|
52
|
+
navController.navigate(
|
|
53
|
+
ChapterScreenProps(
|
|
54
|
+
bookIndex = pair.first,
|
|
55
|
+
chapterIndex = pair.second,
|
|
56
|
+
dir = Dir.Right.name,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
println("navigated navigate")
|
|
62
|
+
navController.navigate(
|
|
63
|
+
ChapterScreenProps(
|
|
64
|
+
bookIndex = pair.first,
|
|
65
|
+
chapterIndex = pair.second,
|
|
66
|
+
dir = Dir.Right.name
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
24
71
|
Box(
|
|
25
72
|
modifier = Modifier
|
|
26
73
|
.fillMaxSize()
|
|
@@ -29,7 +76,7 @@ fun AppHost(model: AppViewModel = viewModel()) {
|
|
|
29
76
|
}
|
|
30
77
|
) {
|
|
31
78
|
if (model.verses.isNotEmpty()) {
|
|
32
|
-
AppDrawer(model = model,
|
|
79
|
+
AppDrawer(model = model, navigateToChapter = navigateToChapter) { openDrawer ->
|
|
33
80
|
NavHost(
|
|
34
81
|
navController = navController,
|
|
35
82
|
startDestination = ChapterScreenProps(model.bookIndex, model.chapterIndex)
|
|
@@ -70,9 +117,10 @@ fun AppHost(model: AppViewModel = viewModel()) {
|
|
|
70
117
|
}
|
|
71
118
|
ChapterScreen(
|
|
72
119
|
model = model,
|
|
120
|
+
onSwipeLeft = onSwipeLeft,
|
|
121
|
+
onSwipeRight = onSwipeRight,
|
|
73
122
|
bookIndex = props.bookIndex,
|
|
74
123
|
chapterIndex = props.chapterIndex,
|
|
75
|
-
navController = navController,
|
|
76
124
|
openDrawer = openDrawer,
|
|
77
125
|
)
|
|
78
126
|
}
|
app/src/main/java/dev/pyrossh/onlyBible/AppViewModel.kt
CHANGED
|
@@ -3,6 +3,7 @@ package dev.pyrossh.onlyBible
|
|
|
3
3
|
import android.app.Application
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.content.Intent
|
|
6
|
+
import androidx.compose.foundation.lazy.LazyListState
|
|
6
7
|
import androidx.compose.runtime.MutableState
|
|
7
8
|
import androidx.compose.runtime.getValue
|
|
8
9
|
import androidx.compose.runtime.mutableStateOf
|
|
@@ -68,6 +69,10 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
|
68
69
|
defaultValue = 0,
|
|
69
70
|
getPreferencesKey = ::intPreferencesKey,
|
|
70
71
|
)
|
|
72
|
+
var scrollState = LazyListState(
|
|
73
|
+
0,
|
|
74
|
+
0
|
|
75
|
+
)
|
|
71
76
|
var themeType by preferenceMutableState(
|
|
72
77
|
coroutineScope = viewModelScope,
|
|
73
78
|
context = context,
|
|
@@ -121,6 +126,14 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
|
|
|
121
126
|
|
|
122
127
|
fun initData(p: Preferences) {
|
|
123
128
|
bibleName = p[stringPreferencesKey("bibleName")] ?: "English"
|
|
129
|
+
scrollState = LazyListState(
|
|
130
|
+
p[intPreferencesKey("scrollIndex")] ?: 0,
|
|
131
|
+
p[intPreferencesKey("scrollOffset")] ?: 0
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fun resetScrollState() {
|
|
136
|
+
scrollState = LazyListState(0, 0)
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
fun loadBible(context: Context) {
|
app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt
CHANGED
|
@@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.height
|
|
|
23
23
|
import androidx.compose.foundation.layout.padding
|
|
24
24
|
import androidx.compose.foundation.layout.size
|
|
25
25
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
26
|
+
import androidx.compose.foundation.lazy.LazyListState
|
|
26
27
|
import androidx.compose.foundation.lazy.items
|
|
27
28
|
import androidx.compose.material.icons.Icons
|
|
28
29
|
import androidx.compose.material.icons.outlined.Cancel
|
|
@@ -45,7 +46,6 @@ import androidx.compose.runtime.Composable
|
|
|
45
46
|
import androidx.compose.runtime.DisposableEffect
|
|
46
47
|
import androidx.compose.runtime.MutableIntState
|
|
47
48
|
import androidx.compose.runtime.getValue
|
|
48
|
-
import androidx.compose.runtime.mutableFloatStateOf
|
|
49
49
|
import androidx.compose.runtime.mutableIntStateOf
|
|
50
50
|
import androidx.compose.runtime.mutableStateOf
|
|
51
51
|
import androidx.compose.runtime.remember
|
|
@@ -66,7 +66,6 @@ import androidx.compose.ui.text.font.FontWeight
|
|
|
66
66
|
import androidx.compose.ui.text.withStyle
|
|
67
67
|
import androidx.compose.ui.unit.dp
|
|
68
68
|
import androidx.compose.ui.unit.sp
|
|
69
|
-
import androidx.navigation.NavController
|
|
70
69
|
import com.microsoft.cognitiveservices.speech.SpeechSynthesisEventArgs
|
|
71
70
|
import dev.pyrossh.onlyBible.domain.Bible
|
|
72
71
|
import dev.pyrossh.onlyBible.domain.Verse
|
|
@@ -138,9 +137,10 @@ suspend fun PointerInputScope.detectSwipe(
|
|
|
138
137
|
@Composable
|
|
139
138
|
fun ChapterScreen(
|
|
140
139
|
model: AppViewModel,
|
|
140
|
+
onSwipeLeft: () -> Unit,
|
|
141
|
+
onSwipeRight: () -> Any,
|
|
141
142
|
bookIndex: Int,
|
|
142
143
|
chapterIndex: Int,
|
|
143
|
-
navController: NavController,
|
|
144
144
|
openDrawer: (MenuType, Int) -> Job,
|
|
145
145
|
) {
|
|
146
146
|
val context = LocalContext.current
|
|
@@ -155,9 +155,6 @@ fun ChapterScreen(
|
|
|
155
155
|
var isPlaying by rememberSaveable {
|
|
156
156
|
mutableStateOf(false)
|
|
157
157
|
}
|
|
158
|
-
var dragAmount by remember {
|
|
159
|
-
mutableFloatStateOf(0.0f)
|
|
160
|
-
}
|
|
161
158
|
DisposableEffect(Unit) {
|
|
162
159
|
val started = { _: Any, _: SpeechSynthesisEventArgs ->
|
|
163
160
|
isPlaying = true
|
|
@@ -322,6 +319,9 @@ fun ChapterScreen(
|
|
|
322
319
|
},
|
|
323
320
|
) { innerPadding ->
|
|
324
321
|
LazyColumn(
|
|
322
|
+
state = rememberSaveable(saver = LazyListState.Saver) {
|
|
323
|
+
model.scrollState
|
|
324
|
+
},
|
|
325
325
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
326
326
|
modifier = Modifier
|
|
327
327
|
.fillMaxSize()
|
|
@@ -329,48 +329,8 @@ fun ChapterScreen(
|
|
|
329
329
|
.padding(horizontal = 16.dp)
|
|
330
330
|
.pointerInput(Unit) {
|
|
331
331
|
detectSwipe(
|
|
332
|
-
onSwipeLeft =
|
|
332
|
+
onSwipeLeft = onSwipeLeft,
|
|
333
|
-
val pair = Verse.getForwardPair(bookIndex, chapterIndex)
|
|
334
|
-
navController.navigate(
|
|
335
|
-
ChapterScreenProps(
|
|
336
|
-
bookIndex = pair.first,
|
|
337
|
-
chapterIndex = pair.second,
|
|
338
|
-
)
|
|
339
|
-
)
|
|
340
|
-
},
|
|
341
|
-
onSwipeRight = {
|
|
333
|
+
onSwipeRight = { onSwipeRight() },
|
|
342
|
-
val pair = Verse.getBackwardPair(bookIndex, chapterIndex)
|
|
343
|
-
if (navController.previousBackStackEntry != null) {
|
|
344
|
-
val previousBook =
|
|
345
|
-
navController.previousBackStackEntry?.arguments?.getInt("book")
|
|
346
|
-
?: 0
|
|
347
|
-
val previousChapter =
|
|
348
|
-
navController.previousBackStackEntry?.arguments?.getInt("chapter")
|
|
349
|
-
?: 0
|
|
350
|
-
// println("currentBackStackEntry ${previousBook} ${previousChapter} || ${pair.first} ${pair.second}")
|
|
351
|
-
if (previousBook == pair.first && previousChapter == pair.second) {
|
|
352
|
-
println("Popped")
|
|
353
|
-
navController.popBackStack()
|
|
354
|
-
} else {
|
|
355
|
-
navController.navigate(
|
|
356
|
-
ChapterScreenProps(
|
|
357
|
-
bookIndex = pair.first,
|
|
358
|
-
chapterIndex = pair.second,
|
|
359
|
-
dir = Dir.Right.name,
|
|
360
|
-
)
|
|
361
|
-
)
|
|
362
|
-
}
|
|
363
|
-
} else {
|
|
364
|
-
// println("navigated navigate")
|
|
365
|
-
navController.navigate(
|
|
366
|
-
ChapterScreenProps(
|
|
367
|
-
bookIndex = pair.first,
|
|
368
|
-
chapterIndex = pair.second,
|
|
369
|
-
dir = Dir.Right.name
|
|
370
|
-
)
|
|
371
|
-
)
|
|
372
|
-
}
|
|
373
|
-
},
|
|
374
334
|
)
|
|
375
335
|
}) {
|
|
376
336
|
items(chapterVerses) { v ->
|
app/src/main/java/dev/pyrossh/onlyBible/MainActivity.kt
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
package dev.pyrossh.onlyBible
|
|
2
2
|
|
|
3
|
+
import android.animation.ObjectAnimator
|
|
3
4
|
import android.os.Bundle
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.animation.AccelerateInterpolator
|
|
4
7
|
import androidx.activity.ComponentActivity
|
|
5
8
|
import androidx.activity.compose.setContent
|
|
6
9
|
import androidx.activity.enableEdgeToEdge
|
|
7
10
|
import androidx.activity.viewModels
|
|
11
|
+
import androidx.core.animation.doOnEnd
|
|
8
12
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
13
|
+
import androidx.datastore.preferences.core.edit
|
|
14
|
+
import androidx.datastore.preferences.core.intPreferencesKey
|
|
9
15
|
import androidx.lifecycle.lifecycleScope
|
|
10
16
|
import kotlinx.coroutines.flow.first
|
|
11
17
|
import kotlinx.coroutines.launch
|
|
@@ -15,9 +21,25 @@ class MainActivity : ComponentActivity() {
|
|
|
15
21
|
private val model by viewModels<AppViewModel>()
|
|
16
22
|
|
|
17
23
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
18
|
-
val splashScreen = installSplashScreen()
|
|
24
|
+
val splashScreen = installSplashScreen().apply {
|
|
25
|
+
setOnExitAnimationListener { viewProvider ->
|
|
26
|
+
ObjectAnimator.ofFloat(
|
|
27
|
+
viewProvider.view,
|
|
28
|
+
View.TRANSLATION_Y,
|
|
29
|
+
0f,
|
|
30
|
+
-viewProvider.view.height.toFloat()
|
|
31
|
+
).apply {
|
|
32
|
+
interpolator = AccelerateInterpolator()
|
|
33
|
+
duration = 200L
|
|
34
|
+
doOnEnd {
|
|
35
|
+
viewProvider.remove()
|
|
36
|
+
enableEdgeToEdge()
|
|
37
|
+
}
|
|
38
|
+
start()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
19
42
|
super.onCreate(savedInstanceState)
|
|
20
|
-
enableEdgeToEdge()
|
|
21
43
|
lifecycleScope.launch {
|
|
22
44
|
val data = applicationContext.dataStore.data.first()
|
|
23
45
|
model.initData(data)
|
|
@@ -33,5 +55,16 @@ class MainActivity : ComponentActivity() {
|
|
|
33
55
|
}
|
|
34
56
|
}
|
|
35
57
|
}
|
|
58
|
+
|
|
59
|
+
override fun onSaveInstanceState(outState: Bundle) {
|
|
60
|
+
super.onSaveInstanceState(outState)
|
|
61
|
+
lifecycleScope.launch {
|
|
62
|
+
applicationContext.dataStore.edit {
|
|
63
|
+
println("saveData ${model.scrollState.firstVisibleItemIndex}")
|
|
64
|
+
it[intPreferencesKey("scrollIndex")] = model.scrollState.firstVisibleItemIndex
|
|
65
|
+
it[intPreferencesKey("scrollOffset")] = model.scrollState.firstVisibleItemScrollOffset
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
36
69
|
}
|
|
37
70
|
|
app/src/main/res/values/themes.xml
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
2
2
|
<resources>
|
|
3
|
-
|
|
3
|
+
<style name="Theme.BibleAppSplash" parent="Theme.SplashScreen">
|
|
4
|
+
<item name="windowSplashScreenAnimatedIcon">@drawable/cross_2</item>
|
|
5
|
+
<item name="windowSplashScreenBackground">#000000</item>
|
|
6
|
+
<item name="postSplashScreenTheme">@style/Theme.BibleApp</item>
|
|
7
|
+
</style>
|
|
4
8
|
<style name="Theme.BibleApp" parent="android:Theme.Material.Light.NoActionBar" />
|
|
5
9
|
</resources>
|