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


3d6c0484 Peter John

1 year ago
improve stuff
app/src/main/java/dev/pyros/bibleapp/AppHost.kt CHANGED
@@ -1,12 +1,9 @@
1
1
  package dev.pyros.bibleapp
2
2
 
3
+ import Verse
3
4
  import androidx.compose.animation.AnimatedContentTransitionScope
4
5
  import androidx.compose.animation.core.tween
5
6
  import androidx.compose.runtime.Composable
6
- import androidx.compose.runtime.getValue
7
- import androidx.compose.runtime.mutableIntStateOf
8
- import androidx.compose.runtime.saveable.rememberSaveable
9
- import androidx.compose.runtime.setValue
10
7
  import androidx.navigation.NavType
11
8
  import androidx.navigation.compose.NavHost
12
9
  import androidx.navigation.compose.composable
@@ -16,38 +13,32 @@ import androidx.navigation.navArgument
16
13
  @Composable
17
14
  fun AppHost(verses: List<Verse>) {
18
15
  val navController = rememberNavController()
19
- var bookIndex by rememberSaveable {
20
- mutableIntStateOf(0)
21
- }
22
- val setBookIndex = { v: Int ->
23
- bookIndex = v
24
- }
25
- Drawer(navController, bookIndex, setBookIndex) { openDrawer ->
16
+ Drawer(navController) { openDrawer ->
26
17
  NavHost(
27
18
  navController = navController,
28
19
  startDestination = "/books/{book}/chapters/{chapter}",
29
20
  enterTransition = {
30
21
  slideIntoContainer(
31
22
  AnimatedContentTransitionScope.SlideDirection.Left,
32
- tween(500),
23
+ tween(400),
33
24
  )
34
25
  },
35
26
  // exitTransition = {
36
27
  // slideOutOfContainer(
37
28
  // AnimatedContentTransitionScope.SlideDirection.Left,
38
- // tween(500),
29
+ // tween(300),
39
30
  // )
40
31
  // },
41
32
  popEnterTransition = {
42
33
  slideIntoContainer(
43
34
  AnimatedContentTransitionScope.SlideDirection.Right,
44
- tween(500),
35
+ tween(400),
45
36
  )
46
37
  },
47
38
  popExitTransition = {
48
39
  slideOutOfContainer(
49
40
  AnimatedContentTransitionScope.SlideDirection.Right,
50
- tween(500),
41
+ tween(400),
51
42
  )
52
43
  }
53
44
  ) {
app/src/main/java/dev/pyros/bibleapp/ChapterScreen.kt CHANGED
@@ -1,68 +1,72 @@
1
1
  package dev.pyros.bibleapp
2
2
 
3
+ import Verse
4
+ import android.annotation.SuppressLint
3
5
  import androidx.compose.animation.core.tween
4
6
  import androidx.compose.foundation.ExperimentalFoundationApi
7
+ import androidx.compose.foundation.background
5
8
  import androidx.compose.foundation.border
6
9
  import androidx.compose.foundation.gestures.AnchoredDraggableState
7
10
  import androidx.compose.foundation.gestures.DraggableAnchors
8
11
  import androidx.compose.foundation.gestures.detectHorizontalDragGestures
12
+ import androidx.compose.foundation.gestures.detectTapGestures
9
13
  import androidx.compose.foundation.interaction.MutableInteractionSource
10
14
  import androidx.compose.foundation.layout.Arrangement
15
+ import androidx.compose.foundation.layout.Box
11
16
  import androidx.compose.foundation.layout.Column
17
+ import androidx.compose.foundation.layout.PaddingValues
12
18
  import androidx.compose.foundation.layout.Row
13
- import androidx.compose.foundation.layout.WindowInsets
14
- import androidx.compose.foundation.layout.absolutePadding
15
19
  import androidx.compose.foundation.layout.fillMaxSize
16
20
  import androidx.compose.foundation.layout.fillMaxWidth
21
+ import androidx.compose.foundation.layout.height
22
+ import androidx.compose.foundation.layout.offset
17
23
  import androidx.compose.foundation.layout.padding
18
- import androidx.compose.foundation.lazy.grid.GridCells
24
+ import androidx.compose.foundation.layout.width
19
- import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
20
25
  import androidx.compose.foundation.rememberScrollState
26
+ import androidx.compose.foundation.shape.RoundedCornerShape
21
27
  import androidx.compose.foundation.verticalScroll
22
28
  import androidx.compose.material.icons.Icons
23
- import androidx.compose.material.icons.filled.Close
24
- import androidx.compose.material.icons.filled.Menu
25
29
  import androidx.compose.material.icons.outlined.MoreVert
26
- import androidx.compose.material3.Button
30
+ import androidx.compose.material3.BottomAppBar
27
- import androidx.compose.material3.Divider
31
+ import androidx.compose.material3.DropdownMenu
28
- import androidx.compose.material3.DrawerValue
32
+ import androidx.compose.material3.DropdownMenuItem
29
33
  import androidx.compose.material3.ExperimentalMaterial3Api
30
34
  import androidx.compose.material3.Icon
31
35
  import androidx.compose.material3.IconButton
32
36
  import androidx.compose.material3.MaterialTheme
33
- import androidx.compose.material3.ModalBottomSheet
34
- import androidx.compose.material3.ModalDrawerSheet
35
- import androidx.compose.material3.ModalNavigationDrawer
36
37
  import androidx.compose.material3.Scaffold
37
38
  import androidx.compose.material3.Surface
38
39
  import androidx.compose.material3.Text
39
- import androidx.compose.material3.TopAppBar
40
- import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
41
- import androidx.compose.material3.rememberDrawerState
42
- import androidx.compose.material3.rememberModalBottomSheetState
43
40
  import androidx.compose.runtime.Composable
44
41
  import androidx.compose.runtime.getValue
42
+ import androidx.compose.runtime.mutableFloatStateOf
45
43
  import androidx.compose.runtime.mutableStateOf
46
44
  import androidx.compose.runtime.remember
47
- import androidx.compose.runtime.rememberCoroutineScope
48
45
  import androidx.compose.runtime.saveable.rememberSaveable
49
46
  import androidx.compose.runtime.setValue
50
47
  import androidx.compose.ui.Alignment
51
48
  import androidx.compose.ui.Modifier
49
+ import androidx.compose.ui.geometry.Offset
50
+ import androidx.compose.ui.geometry.Rect
52
51
  import androidx.compose.ui.graphics.Color
52
+ import androidx.compose.ui.graphics.RectangleShape
53
53
  import androidx.compose.ui.input.pointer.pointerInput
54
+ import androidx.compose.ui.layout.boundsInWindow
55
+ import androidx.compose.ui.layout.onGloballyPositioned
54
56
  import androidx.compose.ui.platform.LocalDensity
55
57
  import androidx.compose.ui.text.SpanStyle
56
58
  import androidx.compose.ui.text.TextStyle
57
59
  import androidx.compose.ui.text.buildAnnotatedString
58
- import androidx.compose.ui.text.font.FontFamily
59
- import androidx.compose.ui.text.font.FontSynthesis
60
60
  import androidx.compose.ui.text.font.FontWeight
61
+ import androidx.compose.ui.text.style.TextAlign
61
62
  import androidx.compose.ui.text.withStyle
63
+ import androidx.compose.ui.unit.DpOffset
64
+ import androidx.compose.ui.unit.IntOffset
62
65
  import androidx.compose.ui.unit.dp
63
66
  import androidx.compose.ui.unit.sp
67
+ import androidx.compose.ui.window.Popup
68
+ import androidx.compose.ui.zIndex
64
69
  import androidx.navigation.NavController
65
- import bookNames
66
70
  import fontFamily
67
71
  import kotlinx.coroutines.Job
68
72
  import kotlinx.serialization.Serializable
@@ -81,6 +85,7 @@ data class ChapterScreenProps(
81
85
  val chapterIndex: Int,
82
86
  )
83
87
 
88
+ @SuppressLint("MutableCollectionMutableState")
84
89
  @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
85
90
  @Composable
86
91
  fun ChapterScreen(
@@ -88,15 +93,16 @@ fun ChapterScreen(
88
93
  bookIndex: Int,
89
94
  chapterIndex: Int,
90
95
  navController: NavController,
91
- openDrawer: (MenuType) -> Job,
96
+ openDrawer: (MenuType, Int) -> Job,
92
97
  ) {
93
- val chapters =
94
- verses.filter { it.bookIndex == bookIndex }.map { it.chapterIndex }.distinct();
95
-
96
- val changeChapter = { c: Int ->
97
- navController.navigate(route = "/books/${bookIndex}/chapters/${c}")
98
- }
99
98
  val density = LocalDensity.current
99
+ var selectedVerseBounds: Rect by remember { mutableStateOf(Rect.Zero) }
100
+ var selectedVerses by rememberSaveable {
101
+ mutableStateOf(listOf<Int>())
102
+ }
103
+ var dragAmount by remember {
104
+ mutableFloatStateOf(0.0f)
105
+ }
100
106
  val state = remember {
101
107
  AnchoredDraggableState(
102
108
  initialValue = DragAnchors.Start,
@@ -109,7 +115,6 @@ fun ChapterScreen(
109
115
  animationSpec = tween(),
110
116
  confirmValueChange = {
111
117
  if (it == DragAnchors.End) {
112
- changeChapter(chapterIndex + 1)
113
118
  true
114
119
  } else {
115
120
  false
@@ -122,6 +127,36 @@ fun ChapterScreen(
122
127
  Scaffold(
123
128
  modifier = Modifier.fillMaxSize(),
124
129
  ) { innerPadding ->
130
+ if (selectedVerses.isNotEmpty()) {
131
+ Box(
132
+ Modifier
133
+ .zIndex(99f)
134
+ .offset {
135
+ IntOffset(
136
+ selectedVerseBounds.centerLeft.x.toInt() + 400,
137
+ selectedVerseBounds.centerLeft.y.toInt() + 300,
138
+ )
139
+ }
140
+ ) {
141
+ Surface(
142
+ modifier = Modifier
143
+ .width(200.dp)
144
+ .height(60.dp)
145
+ .border(
146
+ 1.dp,
147
+ Color.Black,
148
+ RoundedCornerShape(0, 0, 0, 0),
149
+ ),
150
+ ) {
151
+ Text(
152
+ modifier = Modifier
153
+ .fillMaxWidth(),
154
+ textAlign = TextAlign.Center,
155
+ text = "Bottom app bar",
156
+ )
157
+ }
158
+ }
159
+ }
125
160
  Column(
126
161
  modifier = Modifier
127
162
  .fillMaxSize()
@@ -130,15 +165,35 @@ fun ChapterScreen(
130
165
  .verticalScroll(rememberScrollState())
131
166
  // .anchoredDraggable(state, Orientation.Horizontal, reverseDirection = true)
132
167
  .pointerInput(Unit) {
168
+ detectHorizontalDragGestures(
169
+ onDragEnd = {
170
+ // println("END " + dragAmount);
171
+ if (dragAmount < 0) {
172
+ val pair = Verse.getForwardPair(bookIndex, chapterIndex)
173
+ navController.navigate(route = "/books/${pair.first}/chapters/${pair.second}")
174
+ } else if (dragAmount > 0) {
175
+ val pair = Verse.getBackwardPair(bookIndex, chapterIndex)
176
+ val previousBook =
177
+ navController.currentBackStackEntry?.arguments?.getInt("book")
178
+ ?: 0
179
+ val previousChapter =
180
+ navController.currentBackStackEntry?.arguments?.getInt("chapter")
181
+ ?: 0
182
+ if (previousBook == pair.first && previousChapter == pair.second) {
183
+ navController.popBackStack(
184
+ route = "/books/${pair.first}/chapters/${pair.second}",
185
+ inclusive = false
186
+ )
187
+ } else {
188
+ navController.popBackStack()
189
+ }
190
+ }
191
+ },
133
- detectHorizontalDragGestures { change, dragAmount ->
192
+ onHorizontalDrag = { change, da ->
193
+ dragAmount = da
134
- change.consume()
194
+ change.consume()
135
- if (dragAmount < -5) {
136
- changeChapter(chapterIndex - 1)
137
- }
138
- if (dragAmount < 5) {
139
- changeChapter(chapterIndex + 1)
140
195
  }
141
- }
196
+ )
142
197
  }
143
198
  ) {
144
199
  Row(
@@ -149,15 +204,17 @@ fun ChapterScreen(
149
204
  Row(
150
205
  horizontalArrangement = Arrangement.Start,
151
206
  ) {
152
- Surface(onClick = { openDrawer(MenuType.Book) }) {
207
+ Surface(onClick = { openDrawer(MenuType.Book, bookIndex) }) {
208
+ Text(
153
- Text(bookNames[bookIndex], style = TextStyle(
209
+ Verse.bookNames[bookIndex], style = TextStyle(
154
- fontSize = 22.sp,
210
+ fontSize = 22.sp,
155
- fontWeight = FontWeight.W500,
211
+ fontWeight = FontWeight.W500,
156
- color = Color.Black,
212
+ color = Color.Black,
157
- ))
213
+ )
214
+ )
158
215
 
159
216
  }
160
- Surface(onClick = { openDrawer(MenuType.Chapter) }) {
217
+ Surface(onClick = { openDrawer(MenuType.Chapter, bookIndex) }) {
161
218
  Text(
162
219
  "${chapterIndex + 1}", style = TextStyle(
163
220
  fontSize = 22.sp,
@@ -171,49 +228,81 @@ fun ChapterScreen(
171
228
  modifier = Modifier.fillMaxWidth(),
172
229
  horizontalArrangement = Arrangement.End,
173
230
  ) {
174
- IconButton(onClick = { }) {
231
+ IconButton(onClick = { }) {
175
232
  Icon(Icons.Outlined.MoreVert, "Close")
176
233
  }
177
234
  }
178
235
  }
179
- chapterVerses.map {
236
+ chapterVerses.map { v ->
180
- var isSelected by rememberSaveable {
237
+ val isSelected = selectedVerses.contains(v.verseIndex);
181
- mutableStateOf(false)
238
+ val background =
182
- }
183
- val background = if (isSelected) Color(0xFFEEEEEE) else MaterialTheme.colorScheme.background
239
+ if (isSelected) Color(0xFFEEEEEE) else MaterialTheme.colorScheme.background
184
- Surface(onClick = { isSelected = !isSelected }, interactionSource = MutableInteractionSource()) {
240
+ if (v.heading.isNotEmpty()) {
185
241
  Text(
186
- modifier = Modifier.padding(bottom = 12.dp),
242
+ modifier = Modifier.padding(
243
+ top = if (v.verseIndex != 0) 12.dp else 0.dp,
244
+ bottom = 12.dp
245
+ ),
246
+ style = TextStyle(
247
+ fontFamily = fontFamily,
248
+ fontSize = 16.sp,
249
+ fontWeight = FontWeight.W700,
250
+ color = Color.Black,
251
+ ),
252
+ text = v.heading.replace("<br>", "\n\n"),
253
+ )
254
+ }
255
+ Text(
256
+ modifier = Modifier
257
+ .padding(bottom = 10.dp)
258
+ .onGloballyPositioned { coordinates ->
259
+ val boundsInWindow = coordinates.boundsInWindow()
260
+ selectedVerseBounds = coordinates.boundsInWindow()
261
+ println("boundsInWindow blx:" + boundsInWindow.bottomLeft.x.dp)
262
+ println("boundsInWindow bly:" + boundsInWindow.bottomLeft.y.dp)
263
+ // println("boundsInWindow brx:"+boundsInWindow.bottomRight.x)
264
+ // println("boundsInWindow bry:"+boundsInWindow.bottomRight.y)
265
+ }
266
+ .pointerInput(Unit) {
267
+ detectTapGestures(
268
+ onTap = {
269
+ selectedVerses = if (selectedVerses.contains(v.verseIndex)) {
270
+ selectedVerses - v.verseIndex
271
+ } else {
272
+ selectedVerses + v.verseIndex
273
+ }
274
+ }
275
+ )
276
+ },
187
- text = buildAnnotatedString {
277
+ text = buildAnnotatedString {
188
- withStyle(
278
+ withStyle(
189
- style = SpanStyle(
279
+ style = SpanStyle(
190
- background = background,
280
+ background = background,
191
- fontFamily = fontFamily,
281
+ fontFamily = fontFamily,
192
- fontSize = 14.sp,
282
+ fontSize = 14.sp,
193
- color = Color(0xFF9A1111),
283
+ color = Color(0xFF9A1111),
194
284
  // fontSize = if (it.verseIndex == 0) 24.sp else 14.sp,
195
- fontWeight = FontWeight.W600,
285
+ fontWeight = FontWeight.W600,
196
286
  // color = if (it.verseIndex == 0) Color.Black else Color(0xFF9A1111),
197
- )
287
+ )
198
- ) {
288
+ ) {
199
- append("${it.verseIndex + 1} ")
289
+ append("${v.verseIndex + 1} ")
200
290
  // append(if (it.verseIndex == 0) "${chapterIndex + 1} " else "${it.verseIndex + 1} ")
201
- }
202
- withStyle(
203
- style = SpanStyle(
204
- background = background,
205
- // fontFamily = fontFamily,
206
- fontFamily = FontFamily.Serif,
207
- fontSize = 15.sp,
208
- fontWeight = FontWeight.W400,
209
- color = Color.Black,
210
- )
211
- ) {
212
- append(it.text)
213
- }
214
291
  }
292
+ withStyle(
293
+ style = SpanStyle(
294
+ background = background,
295
+ fontFamily = fontFamily,
296
+ // fontFamily = FontFamily.Serif,
297
+ fontSize = 16.sp,
298
+ fontWeight = FontWeight.Normal,
299
+ color = Color.Black,
215
- )
300
+ )
301
+ ) {
302
+ append(v.text)
216
- }
303
+ }
304
+ }
305
+ )
217
306
  }
218
307
  }
219
308
  }
app/src/main/java/dev/pyros/bibleapp/Consts.kt DELETED
@@ -1,137 +0,0 @@
1
- val bookNames = listOf(
2
- "Genesis",
3
- "Exodus",
4
- "Leviticus",
5
- "Numbers",
6
- "Deuteronomy",
7
- "Joshua",
8
- "Judges",
9
- "Ruth",
10
- "1 Samuel",
11
- "2 Samuel",
12
- "1 Kings",
13
- "2 Kings",
14
- "1 Chronicles",
15
- "2 Chronicles",
16
- "Ezra",
17
- "Nehemiah",
18
- "Esther",
19
- "Job",
20
- "Psalms",
21
- "Proverbs",
22
- "Ecclesiastes",
23
- "Song of Solomon",
24
- "Isaiah",
25
- "Jeremiah",
26
- "Lamentations",
27
- "Ezekiel",
28
- "Daniel",
29
- "Hosea",
30
- "Joel",
31
- "Amos",
32
- "Obadiah",
33
- "Jonah",
34
- "Micah",
35
- "Nahum",
36
- "Habakkuk",
37
- "Zephaniah",
38
- "Haggai",
39
- "Zechariah",
40
- "Malachi",
41
- "Matthew",
42
- "Mark",
43
- "Luke",
44
- "John",
45
- "Acts",
46
- "Romans",
47
- "1 Corinthians",
48
- "2 Corinthians",
49
- "Galatians",
50
- "Ephesians",
51
- "Philippians",
52
- "Colossians",
53
- "1 Thessalonians",
54
- "2 Thessalonians",
55
- "1 Timothy",
56
- "2 Timothy",
57
- "Titus",
58
- "Philemon",
59
- "Hebrews",
60
- "James",
61
- "1 Peter",
62
- "2 Peter",
63
- "1 John",
64
- "2 John",
65
- "3 John",
66
- "Jude",
67
- "Revelation",
68
- )
69
-
70
- val chapterSizes = listOf(
71
- 50,
72
- 40,
73
- 27,
74
- 36,
75
- 34,
76
- 24,
77
- 21,
78
- 4,
79
- 31,
80
- 24,
81
- 22,
82
- 25,
83
- 29,
84
- 36,
85
- 10,
86
- 13,
87
- 10,
88
- 42,
89
- 150,
90
- 31,
91
- 12,
92
- 8,
93
- 66,
94
- 52,
95
- 5,
96
- 48,
97
- 12,
98
- 14,
99
- 3,
100
- 9,
101
- 1,
102
- 4,
103
- 7,
104
- 3,
105
- 3,
106
- 3,
107
- 2,
108
- 14,
109
- 4,
110
- 28,
111
- 16,
112
- 24,
113
- 21,
114
- 28,
115
- 16,
116
- 16,
117
- 13,
118
- 6,
119
- 6,
120
- 4,
121
- 4,
122
- 5,
123
- 3,
124
- 6,
125
- 4,
126
- 3,
127
- 1,
128
- 13,
129
- 5,
130
- 5,
131
- 3,
132
- 5,
133
- 1,
134
- 1,
135
- 1,
136
- 22
137
- )
app/src/main/java/dev/pyros/bibleapp/Drawer.kt CHANGED
@@ -1,7 +1,13 @@
1
1
  package dev.pyros.bibleapp
2
2
 
3
+ import android.annotation.SuppressLint
4
+ import android.util.Log
5
+ import androidx.compose.foundation.background
6
+ import androidx.compose.foundation.gestures.detectTapGestures
7
+ import androidx.compose.foundation.interaction.MutableInteractionSource
3
8
  import androidx.compose.foundation.layout.Arrangement
4
9
  import androidx.compose.foundation.layout.Box
10
+ import androidx.compose.foundation.layout.BoxWithConstraints
5
11
  import androidx.compose.foundation.layout.Column
6
12
  import androidx.compose.foundation.layout.PaddingValues
7
13
  import androidx.compose.foundation.layout.Row
@@ -18,6 +24,8 @@ import androidx.compose.material3.Button
18
24
  import androidx.compose.material3.ButtonDefaults
19
25
  import androidx.compose.material3.DrawerDefaults
20
26
  import androidx.compose.material3.DrawerValue
27
+ import androidx.compose.material3.DropdownMenu
28
+ import androidx.compose.material3.DropdownMenuItem
21
29
  import androidx.compose.material3.Icon
22
30
  import androidx.compose.material3.IconButton
23
31
  import androidx.compose.material3.ModalDrawerSheet
@@ -26,22 +34,27 @@ import androidx.compose.material3.Text
26
34
  import androidx.compose.material3.rememberDrawerState
27
35
  import androidx.compose.runtime.Composable
28
36
  import androidx.compose.runtime.getValue
37
+ import androidx.compose.runtime.mutableIntStateOf
29
38
  import androidx.compose.runtime.mutableStateOf
39
+ import androidx.compose.runtime.remember
30
40
  import androidx.compose.runtime.rememberCoroutineScope
31
41
  import androidx.compose.runtime.saveable.rememberSaveable
32
42
  import androidx.compose.runtime.setValue
33
43
  import androidx.compose.ui.Alignment
34
44
  import androidx.compose.ui.Modifier
45
+ import androidx.compose.ui.geometry.Offset
35
46
  import androidx.compose.ui.graphics.Color
36
47
  import androidx.compose.ui.graphics.RectangleShape
48
+ import androidx.compose.ui.input.pointer.pointerInput
49
+ import androidx.compose.ui.platform.LocalDensity
37
50
  import androidx.compose.ui.text.TextStyle
38
51
  import androidx.compose.ui.text.font.FontFamily
39
52
  import androidx.compose.ui.text.font.FontWeight
53
+ import androidx.compose.ui.unit.DpOffset
40
54
  import androidx.compose.ui.unit.dp
41
55
  import androidx.compose.ui.unit.sp
42
56
  import androidx.navigation.NavController
43
- import bookNames
44
- import chapterSizes
57
+ import androidx.navigation.NavOptions
45
58
  import kotlinx.coroutines.Job
46
59
  import kotlinx.coroutines.launch
47
60
 
@@ -92,77 +105,77 @@ fun NonlazyGrid(
92
105
  }
93
106
  }
94
107
 
95
- //@Composable
96
- //private fun DropDownSample() {
97
- // var expanded by remember { mutableStateOf(false) }
98
- // var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
99
- // val density = LocalDensity.current
100
- //
101
- // BoxWithConstraints(
102
- // Modifier
103
- // .fillMaxSize()
104
- // .background(Color.Cyan)
105
- // .pointerInput(Unit) {
106
- // detectTapGestures {
107
- // Log.d("TAG", "onCreate: ${it}")
108
- // touchPoint = it
109
- // expanded = true
110
- //
111
- // }
112
- //
113
- // }
114
- // ) {
115
- // val (xDp, yDp) = with(density) {
116
- // (touchPoint.x.toDp()) to (touchPoint.y.toDp())
117
- // }
118
- // DropdownMenu(
119
- // expanded = expanded,
120
- // offset = DpOffset(xDp, -maxHeight + yDp),
121
- // onDismissRequest = {
122
- // expanded = false
123
- // }
124
- // ) {
125
- //
126
- // DropdownMenuItem(
127
- // onClick = {
128
- // expanded = false
129
- // },
130
- // interactionSource = MutableInteractionSource(),
131
- // text = {
132
- // Text("Copy")
133
- // }
134
- // )
135
- //
136
- // DropdownMenuItem(
137
- // onClick = {
138
- // expanded = false
139
- // },
140
- // interactionSource = MutableInteractionSource(),
141
- // text = {
142
- // Text("Get Balance")
143
- // }
144
- // )
145
- // }
146
- // }
147
- //}
108
+ @SuppressLint("UnrememberedMutableInteractionSource")
109
+ @Composable
110
+ fun DropDownSample() {
111
+ var expanded by remember { mutableStateOf(false) }
112
+ var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
113
+ val density = LocalDensity.current
114
+
115
+ BoxWithConstraints(
116
+ Modifier
117
+ .fillMaxSize()
118
+ .background(Color.Cyan)
119
+ .pointerInput(Unit) {
120
+ detectTapGestures {
121
+ Log.d("TAG", "onCreate: ${it}")
122
+ touchPoint = it
123
+ expanded = true
124
+
125
+ }
126
+
127
+ }
128
+ ) {
129
+ val (xDp, yDp) = with(density) {
130
+ (touchPoint.x.toDp()) to (touchPoint.y.toDp())
131
+ }
132
+ DropdownMenu(
133
+ expanded = expanded,
134
+ offset = DpOffset(xDp, -maxHeight + yDp),
135
+ onDismissRequest = {
136
+ expanded = false
137
+ }
138
+ ) {
139
+
140
+ DropdownMenuItem(
141
+ onClick = {
142
+ expanded = false
143
+ },
144
+ interactionSource = MutableInteractionSource(),
145
+ text = {
146
+ Text("Copy")
147
+ }
148
+ )
149
+
150
+ DropdownMenuItem(
151
+ onClick = {
152
+ expanded = false
153
+ },
154
+ interactionSource = MutableInteractionSource(),
155
+ text = {
156
+ Text("Get Balance")
157
+ }
158
+ )
159
+ }
160
+ }
161
+ }
148
162
 
149
163
  @Composable
150
164
  fun Drawer(
151
165
  navController: NavController,
152
- bookIndex: Int,
153
- setBookIndex: (Int) -> Unit,
154
- content: @Composable ((MenuType) -> Job) -> Unit
166
+ content: @Composable ((MenuType, Int) -> Job) -> Unit
155
167
  ) {
156
168
  val scope = rememberCoroutineScope()
157
169
  val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
158
- var localBookIndex by rememberSaveable {
170
+ var bookIndex by rememberSaveable {
159
- mutableStateOf(bookIndex)
171
+ mutableIntStateOf(0)
160
172
  }
161
173
  var menuType by rememberSaveable {
162
174
  mutableStateOf(MenuType.Chapter)
163
175
  }
164
- val openDrawer = { m: MenuType ->
176
+ val openDrawer = { m: MenuType, b: Int ->
165
177
  menuType = m
178
+ bookIndex = b
166
179
  scope.launch {
167
180
  drawerState.apply {
168
181
  if (isClosed) open() else close()
@@ -216,8 +229,8 @@ fun Drawer(
216
229
  items(
217
230
  when (menuType) {
218
231
  MenuType.Bible -> 1
219
- MenuType.Book -> bookNames.size
232
+ MenuType.Book -> Verse.bookNames.size
220
- MenuType.Chapter -> chapterSizes[bookIndex]
233
+ MenuType.Chapter -> Verse.chapterSizes[bookIndex]
221
234
  }
222
235
  ) { c ->
223
236
  Button(
@@ -233,12 +246,11 @@ fun Drawer(
233
246
  when (menuType) {
234
247
  MenuType.Bible -> ""
235
248
  MenuType.Book -> {
236
- localBookIndex = c
249
+ bookIndex = c
237
250
  menuType = MenuType.Chapter
238
- // navController.navigate(route = "/books/${c}/chapters/0")
239
251
  }
240
252
  MenuType.Chapter -> {
241
- navController.navigate(route = "/books/${localBookIndex}/chapters/${c}")
253
+ navController.navigate(route = "/books/${bookIndex}/chapters/${c}")
242
254
  drawerState.close();
243
255
  }
244
256
  }
@@ -254,7 +266,7 @@ fun Drawer(
254
266
  ),
255
267
  text = when (menuType) {
256
268
  MenuType.Bible -> ""
257
- MenuType.Book -> shortName(bookNames[c])
269
+ MenuType.Book -> shortName(Verse.bookNames[c])
258
270
  MenuType.Chapter -> "${c + 1}"
259
271
  }
260
272
  )
app/src/main/java/dev/pyros/bibleapp/MainActivity.kt CHANGED
@@ -1,48 +1,18 @@
1
1
  package dev.pyros.bibleapp
2
2
 
3
+ import Verse
3
4
  import android.os.Bundle
4
5
  import android.util.Log
5
6
  import androidx.activity.ComponentActivity
6
7
  import androidx.activity.compose.setContent
7
8
  import androidx.activity.enableEdgeToEdge
8
- import bookNames
9
9
  import dev.pyros.bibleapp.ui.theme.BibleAppTheme
10
- import java.io.BufferedReader
11
-
12
- data class Verse(
13
- val bookIndex: Int,
14
- val bookName: String,
15
- val chapterIndex: Int,
16
- val verseIndex: Int,
17
- val heading: String,
18
- val text: String
19
- )
20
-
21
- fun parseBibleTxt(name: String, buffer: BufferedReader): List<Verse> {
22
- Log.i("loading", "parsing bible $name")
23
- return buffer.readLines().filter { it.isNotEmpty() }.map {
24
- val arr = it.split("|")
25
- val book = arr[0].toInt()
26
- val chapter = arr[1].toInt()
27
- val verseNo = arr[2].toInt()
28
- val heading = arr[3]
29
- val verseText = arr.subList(4, arr.size).joinToString("|")
30
- Verse(
31
- bookIndex = book,
32
- bookName = bookNames[book],
33
- chapterIndex = chapter,
34
- verseIndex = verseNo,
35
- heading = heading,
36
- text = verseText,
37
- )
38
- }
39
- }
40
10
 
41
11
  class MainActivity : ComponentActivity() {
42
12
  override fun onCreate(savedInstanceState: Bundle?) {
43
13
  super.onCreate(savedInstanceState)
44
14
  enableEdgeToEdge()
45
- val verses = parseBibleTxt("English", assets.open("English.txt").bufferedReader())
15
+ val verses = Verse.parseFromBibleTxt("English", assets.open("English.txt").bufferedReader())
46
16
  setContent {
47
17
  BibleAppTheme {
48
18
  AppHost(verses = verses)
app/src/main/java/dev/pyros/bibleapp/Model.kt ADDED
@@ -0,0 +1,195 @@
1
+ import android.util.Log
2
+ import java.io.BufferedReader
3
+
4
+ data class Verse(
5
+ val bookIndex: Int,
6
+ val bookName: String,
7
+ val chapterIndex: Int,
8
+ val verseIndex: Int,
9
+ val heading: String,
10
+ val text: String,
11
+ ) {
12
+ fun isOldTestament() = bookIndex < 39;
13
+ fun isNewTestament() = bookIndex >= 39;
14
+
15
+ companion object {
16
+
17
+ val bookNames = listOf(
18
+ "Genesis",
19
+ "Exodus",
20
+ "Leviticus",
21
+ "Numbers",
22
+ "Deuteronomy",
23
+ "Joshua",
24
+ "Judges",
25
+ "Ruth",
26
+ "1 Samuel",
27
+ "2 Samuel",
28
+ "1 Kings",
29
+ "2 Kings",
30
+ "1 Chronicles",
31
+ "2 Chronicles",
32
+ "Ezra",
33
+ "Nehemiah",
34
+ "Esther",
35
+ "Job",
36
+ "Psalms",
37
+ "Proverbs",
38
+ "Ecclesiastes",
39
+ "Song of Solomon",
40
+ "Isaiah",
41
+ "Jeremiah",
42
+ "Lamentations",
43
+ "Ezekiel",
44
+ "Daniel",
45
+ "Hosea",
46
+ "Joel",
47
+ "Amos",
48
+ "Obadiah",
49
+ "Jonah",
50
+ "Micah",
51
+ "Nahum",
52
+ "Habakkuk",
53
+ "Zephaniah",
54
+ "Haggai",
55
+ "Zechariah",
56
+ "Malachi",
57
+ "Matthew",
58
+ "Mark",
59
+ "Luke",
60
+ "John",
61
+ "Acts",
62
+ "Romans",
63
+ "1 Corinthians",
64
+ "2 Corinthians",
65
+ "Galatians",
66
+ "Ephesians",
67
+ "Philippians",
68
+ "Colossians",
69
+ "1 Thessalonians",
70
+ "2 Thessalonians",
71
+ "1 Timothy",
72
+ "2 Timothy",
73
+ "Titus",
74
+ "Philemon",
75
+ "Hebrews",
76
+ "James",
77
+ "1 Peter",
78
+ "2 Peter",
79
+ "1 John",
80
+ "2 John",
81
+ "3 John",
82
+ "Jude",
83
+ "Revelation",
84
+ )
85
+
86
+ val chapterSizes = listOf(
87
+ 50,
88
+ 40,
89
+ 27,
90
+ 36,
91
+ 34,
92
+ 24,
93
+ 21,
94
+ 4,
95
+ 31,
96
+ 24,
97
+ 22,
98
+ 25,
99
+ 29,
100
+ 36,
101
+ 10,
102
+ 13,
103
+ 10,
104
+ 42,
105
+ 150,
106
+ 31,
107
+ 12,
108
+ 8,
109
+ 66,
110
+ 52,
111
+ 5,
112
+ 48,
113
+ 12,
114
+ 14,
115
+ 3,
116
+ 9,
117
+ 1,
118
+ 4,
119
+ 7,
120
+ 3,
121
+ 3,
122
+ 3,
123
+ 2,
124
+ 14,
125
+ 4,
126
+ 28,
127
+ 16,
128
+ 24,
129
+ 21,
130
+ 28,
131
+ 16,
132
+ 16,
133
+ 13,
134
+ 6,
135
+ 6,
136
+ 4,
137
+ 4,
138
+ 5,
139
+ 3,
140
+ 6,
141
+ 4,
142
+ 3,
143
+ 1,
144
+ 13,
145
+ 5,
146
+ 5,
147
+ 3,
148
+ 5,
149
+ 1,
150
+ 1,
151
+ 1,
152
+ 22
153
+ )
154
+ fun parseFromBibleTxt(name: String, buffer: BufferedReader): List<Verse> {
155
+ Log.i("loading", "parsing bible $name")
156
+ return buffer.readLines().filter { it.isNotEmpty() }.map {
157
+ val arr = it.split("|")
158
+ val book = arr[0].toInt()
159
+ val chapter = arr[1].toInt()
160
+ val verseNo = arr[2].toInt()
161
+ val heading = arr[3]
162
+ val verseText = arr.subList(4, arr.size).joinToString("|")
163
+ Verse(
164
+ bookIndex = book,
165
+ bookName = bookNames[book],
166
+ chapterIndex = chapter,
167
+ verseIndex = verseNo,
168
+ heading = heading,
169
+ text = verseText,
170
+ )
171
+ }
172
+ }
173
+
174
+ fun getForwardPair(book: Int, chapter: Int): Pair<Int, Int> {
175
+ val sizes = chapterSizes[book];
176
+ if (sizes > chapter + 1) {
177
+ return Pair(book, chapter + 1)
178
+ }
179
+ if (book + 1 < bookNames.size) {
180
+ return Pair(book + 1, 0)
181
+ }
182
+ return Pair(0, 0)
183
+ }
184
+
185
+ fun getBackwardPair(book: Int, chapter: Int): Pair<Int, Int> {
186
+ if (chapter - 1 >= 0) {
187
+ return Pair(book, chapter - 1)
188
+ }
189
+ if (book - 1 >= 0) {
190
+ return Pair(book-1, chapterSizes[book-1]-1)
191
+ }
192
+ return Pair(bookNames.size-1, chapterSizes[bookNames.size-1]-1)
193
+ }
194
+ }
195
+ }
app/src/main/java/dev/pyros/bibleapp/Utils.kt ADDED
File without changes