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


f6d79907 pyrossh

1 year ago
improve selector
app/src/main/java/dev/pyrossh/onlyBible/AppDrawer.kt DELETED
@@ -1,300 +0,0 @@
1
- package dev.pyrossh.onlyBible
2
-
3
- import androidx.compose.foundation.layout.Arrangement
4
- import androidx.compose.foundation.layout.Column
5
- import androidx.compose.foundation.layout.PaddingValues
6
- import androidx.compose.foundation.layout.Row
7
- import androidx.compose.foundation.layout.fillMaxSize
8
- import androidx.compose.foundation.layout.fillMaxWidth
9
- import androidx.compose.foundation.layout.padding
10
- import androidx.compose.foundation.lazy.grid.GridCells
11
- import androidx.compose.foundation.lazy.grid.GridItemSpan
12
- import androidx.compose.foundation.lazy.grid.LazyGridItemScope
13
- import androidx.compose.foundation.lazy.grid.LazyGridScope
14
- import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
15
- import androidx.compose.foundation.lazy.grid.items
16
- import androidx.compose.foundation.shape.RoundedCornerShape
17
- import androidx.compose.material.icons.Icons
18
- import androidx.compose.material.icons.filled.Close
19
- import androidx.compose.material3.Button
20
- import androidx.compose.material3.DrawerValue
21
- import androidx.compose.material3.Icon
22
- import androidx.compose.material3.IconButton
23
- import androidx.compose.material3.ModalDrawerSheet
24
- import androidx.compose.material3.ModalNavigationDrawer
25
- import androidx.compose.material3.Text
26
- import androidx.compose.material3.rememberDrawerState
27
- import androidx.compose.runtime.Composable
28
- import androidx.compose.runtime.collectAsState
29
- import androidx.compose.runtime.getValue
30
- import androidx.compose.runtime.mutableIntStateOf
31
- import androidx.compose.runtime.mutableStateOf
32
- import androidx.compose.runtime.rememberCoroutineScope
33
- import androidx.compose.runtime.saveable.rememberSaveable
34
- import androidx.compose.runtime.setValue
35
- import androidx.compose.ui.Alignment
36
- import androidx.compose.ui.Modifier
37
- import androidx.compose.ui.platform.LocalContext
38
- import androidx.compose.ui.text.TextStyle
39
- import androidx.compose.ui.text.font.FontWeight
40
- import androidx.compose.ui.unit.dp
41
- import androidx.compose.ui.unit.sp
42
- import dev.pyrossh.onlyBible.domain.bibles
43
- import dev.pyrossh.onlyBible.domain.chapterSizes
44
- import kotlinx.coroutines.Job
45
- import kotlinx.coroutines.launch
46
- import java.util.Locale
47
-
48
- enum class MenuType {
49
- Bible,
50
- Book,
51
- Chapter,
52
- }
53
-
54
- fun shortName(name: String): String {
55
- if (name[0] == '1' || name[0] == '2' || name[0] == '3') {
56
- return "${name[0]}${name[2].uppercase()}${name.substring(3, 4).lowercase()}"
57
- }
58
- return "${name[0].uppercase()}${name.substring(1, 3).lowercase()}"
59
- }
60
-
61
- fun LazyGridScope.header(
62
- content: @Composable LazyGridItemScope.() -> Unit
63
- ) {
64
- item(span = { GridItemSpan(this.maxLineSpan) }, content = content)
65
- }
66
-
67
- @Composable
68
- fun AppDrawer(
69
- model: AppViewModel,
70
- navigateToChapter: (ChapterScreenProps) -> Unit,
71
- content: @Composable ((MenuType, Int) -> Job) -> Unit
72
- ) {
73
- val context = LocalContext.current
74
- val scope = rememberCoroutineScope()
75
- val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
76
- var bookIndex by rememberSaveable {
77
- mutableIntStateOf(0)
78
- }
79
- var menuType by rememberSaveable {
80
- mutableStateOf(MenuType.Chapter)
81
- }
82
- val bookNames by model.bookNames.collectAsState()
83
- val openDrawer = { m: MenuType, b: Int ->
84
- model.clearSelectedVerses()
85
- menuType = m
86
- bookIndex = b
87
- scope.launch {
88
- drawerState.apply {
89
- if (isClosed) open() else close()
90
- }
91
- }
92
- }
93
- ModalNavigationDrawer(
94
- gesturesEnabled = drawerState.isOpen,
95
- drawerState = drawerState,
96
- drawerContent = {
97
- ModalDrawerSheet(
98
- drawerTonalElevation = 2.dp,
99
- ) {
100
- Column(
101
- modifier = Modifier
102
- .fillMaxSize()
103
- .padding(horizontal = 16.dp)
104
- .padding(bottom = 16.dp),
105
- ) {
106
- if (menuType == MenuType.Bible) {
107
- LazyVerticalGrid(
108
- modifier = Modifier.fillMaxSize(),
109
- verticalArrangement = Arrangement.spacedBy(10.dp),
110
- horizontalArrangement = Arrangement.spacedBy(10.dp),
111
- columns = GridCells.Fixed(2)
112
- ) {
113
- header {
114
- Row(
115
- modifier = Modifier.fillMaxWidth(),
116
- horizontalArrangement = Arrangement.SpaceBetween,
117
- verticalAlignment = Alignment.CenterVertically,
118
- ) {
119
- Text(
120
- text = "Select a bible",
121
- fontSize = 20.sp,
122
- fontWeight = FontWeight.W500,
123
- )
124
- IconButton(onClick = {
125
- scope.launch {
126
- drawerState.close();
127
- }
128
- }) {
129
- Icon(Icons.Filled.Close, "Close")
130
- }
131
- }
132
- }
133
- items(bibles) { b ->
134
- val arr = b.split("_")
135
- val loc = Locale(arr[0])
136
- QuickButton(
137
- title = loc.getDisplayName(Locale.ENGLISH),
138
- subtitle = if (arr.size > 1)
139
- arr[1].uppercase()
140
- else
141
- loc.getDisplayName(loc),
142
- ) {
143
- scope.launch {
144
- drawerState.close()
145
- }.invokeOnCompletion {
146
- model.bible = b
147
- model.loadBible()
148
- context.setLocale(loc)
149
- }
150
- }
151
- }
152
- }
153
- }
154
- if (menuType == MenuType.Book) {
155
- LazyVerticalGrid(
156
- modifier = Modifier.fillMaxSize(),
157
- verticalArrangement = Arrangement.spacedBy(10.dp),
158
- horizontalArrangement = Arrangement.spacedBy(10.dp),
159
- columns = GridCells.Fixed(5)
160
- ) {
161
- header {
162
- Row(
163
- modifier = Modifier.fillMaxWidth(),
164
- horizontalArrangement = Arrangement.SpaceBetween,
165
- verticalAlignment = Alignment.CenterVertically,
166
- ) {
167
- Text(
168
- text = context.getString(R.string.old_testament),
169
- fontSize = 18.sp,
170
- fontWeight = FontWeight.W500,
171
- )
172
- IconButton(onClick = {
173
- scope.launch {
174
- drawerState.close();
175
- }
176
- }) {
177
- Icon(Icons.Filled.Close, "Close")
178
- }
179
- }
180
- }
181
- items(39) { b ->
182
- QuickButton(
183
- title = shortName(bookNames[b]),
184
- subtitle = null,
185
- ) {
186
- bookIndex = b
187
- menuType = MenuType.Chapter
188
- }
189
- }
190
- header {
191
- Row(
192
- modifier = Modifier.padding(top = 16.dp, bottom = 8.dp),
193
- horizontalArrangement = Arrangement.SpaceBetween,
194
- verticalAlignment = Alignment.CenterVertically,
195
- ) {
196
- Text(
197
- text = context.getString(R.string.new_testament),
198
- fontSize = 18.sp,
199
- fontWeight = FontWeight.W500
200
- )
201
- }
202
- }
203
- items(27) { i ->
204
- val b = 39 + i
205
- QuickButton(
206
- title = shortName(bookNames[b]),
207
- subtitle = null,
208
- ) {
209
- bookIndex = b
210
- menuType = MenuType.Chapter
211
- }
212
- }
213
- }
214
- }
215
-
216
- if (menuType == MenuType.Chapter) {
217
- LazyVerticalGrid(
218
- modifier = Modifier.fillMaxSize(),
219
- verticalArrangement = Arrangement.spacedBy(10.dp),
220
- horizontalArrangement = Arrangement.spacedBy(10.dp),
221
- columns = GridCells.Fixed(5)
222
- ) {
223
- header {
224
- Row(
225
- modifier = Modifier.fillMaxWidth(),
226
- horizontalArrangement = Arrangement.SpaceBetween,
227
- verticalAlignment = Alignment.CenterVertically,
228
- ) {
229
- Text(
230
- text = bookNames[bookIndex],
231
- fontSize = 20.sp,
232
- fontWeight = FontWeight.W500
233
- )
234
- IconButton(onClick = {
235
- scope.launch {
236
- drawerState.close();
237
- }
238
- }) {
239
- Icon(Icons.Filled.Close, "Close")
240
- }
241
- }
242
- }
243
-
244
- items(chapterSizes[bookIndex]) { c ->
245
- QuickButton(
246
- title = "${c + 1}",
247
- subtitle = null,
248
- ) {
249
- scope.launch {
250
- navigateToChapter(
251
- ChapterScreenProps(
252
- bookIndex = bookIndex,
253
- chapterIndex = c,
254
- )
255
- )
256
- drawerState.close();
257
- }
258
- }
259
- }
260
- }
261
- }
262
- }
263
- }
264
- },
265
- ) {
266
- content(openDrawer)
267
- }
268
- }
269
-
270
- @Composable
271
- fun QuickButton(title: String, subtitle: String?, onClick: () -> Unit) {
272
- Button(
273
- shape = RoundedCornerShape(2.dp),
274
- contentPadding = PaddingValues(4.dp),
275
- onClick = onClick
276
- ) {
277
- Column(
278
- horizontalAlignment = Alignment.CenterHorizontally,
279
- modifier = Modifier.padding(vertical = 8.dp)
280
- ) {
281
- Text(
282
- style = TextStyle(
283
- fontSize = 18.sp,
284
- fontWeight = FontWeight.W500,
285
- ),
286
- text = title,
287
- )
288
- if (!subtitle.isNullOrEmpty()) {
289
- Text(
290
- modifier = Modifier.padding(top = 8.dp),
291
- style = TextStyle(
292
- fontSize = 18.sp,
293
- fontWeight = FontWeight.W500,
294
- ),
295
- text = "($subtitle)",
296
- )
297
- }
298
- }
299
- }
300
- }
app/src/main/java/dev/pyrossh/onlyBible/AppHost.kt CHANGED
@@ -4,7 +4,6 @@ import androidx.compose.animation.EnterTransition
4
4
  import androidx.compose.animation.ExitTransition
5
5
  import androidx.compose.animation.core.tween
6
6
  import androidx.compose.runtime.Composable
7
- import androidx.compose.ui.platform.LocalView
8
7
  import androidx.navigation.compose.NavHost
9
8
  import androidx.navigation.compose.composable
10
9
  import androidx.navigation.compose.rememberNavController
@@ -58,43 +57,41 @@ fun AppHost(model: AppViewModel) {
58
57
  )
59
58
  }
60
59
  }
61
- AppDrawer(model = model, navigateToChapter = navigateToChapter) { openDrawer ->
62
- NavHost(
60
+ NavHost(
63
- navController = navController,
61
+ navController = navController,
64
- startDestination = ChapterScreenProps(0, 0)
62
+ startDestination = ChapterScreenProps(0, 0)
65
- ) {
63
+ ) {
66
- composable<ChapterScreenProps>(
64
+ composable<ChapterScreenProps>(
67
- enterTransition = {
65
+ enterTransition = {
68
- val props = this.targetState.toRoute<ChapterScreenProps>()
66
+ val props = this.targetState.toRoute<ChapterScreenProps>()
69
- slideIntoContainer(
67
+ slideIntoContainer(
70
- Dir.valueOf(props.dir).slideDirection(),
68
+ Dir.valueOf(props.dir).slideDirection(),
71
- tween(400),
69
+ tween(400),
72
- )
70
+ )
73
- },
71
+ },
74
- exitTransition = {
72
+ exitTransition = {
75
- ExitTransition.None
73
+ ExitTransition.None
76
- },
74
+ },
77
- popEnterTransition = {
75
+ popEnterTransition = {
78
- EnterTransition.None
76
+ EnterTransition.None
79
- },
77
+ },
80
- popExitTransition = {
78
+ popExitTransition = {
81
- val props = this.targetState.toRoute<ChapterScreenProps>()
79
+ val props = this.targetState.toRoute<ChapterScreenProps>()
82
- slideOutOfContainer(
80
+ slideOutOfContainer(
83
- Dir.valueOf(props.dir).reverse().slideDirection(),
81
+ Dir.valueOf(props.dir).reverse().slideDirection(),
84
- tween(400),
82
+ tween(400),
85
- )
86
- }
87
- ) {
88
- val props = it.toRoute<ChapterScreenProps>()
89
- ChapterScreen(
90
- model = model,
91
- onSwipeLeft = onSwipeLeft,
92
- onSwipeRight = onSwipeRight,
93
- bookIndex = props.bookIndex,
94
- chapterIndex = props.chapterIndex,
95
- openDrawer = openDrawer,
96
83
  )
97
84
  }
85
+ ) {
86
+ val props = it.toRoute<ChapterScreenProps>()
87
+ ChapterScreen(
88
+ model = model,
89
+ onSwipeLeft = onSwipeLeft,
90
+ onSwipeRight = onSwipeRight,
91
+ bookIndex = props.bookIndex,
92
+ chapterIndex = props.chapterIndex,
93
+ navigateToChapter = navigateToChapter,
94
+ )
98
95
  }
99
96
  }
100
97
  }
app/src/main/java/dev/pyrossh/onlyBible/ChapterScreen.kt CHANGED
@@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.items
17
17
  import androidx.compose.material.icons.Icons
18
18
  import androidx.compose.material.icons.outlined.MoreVert
19
19
  import androidx.compose.material.icons.rounded.Search
20
+ import androidx.compose.material3.ButtonDefaults.ContentPadding
20
21
  import androidx.compose.material3.ExperimentalMaterial3Api
21
22
  import androidx.compose.material3.Icon
22
23
  import androidx.compose.material3.IconButton
@@ -31,19 +32,22 @@ import androidx.compose.runtime.MutableIntState
31
32
  import androidx.compose.runtime.collectAsState
32
33
  import androidx.compose.runtime.getValue
33
34
  import androidx.compose.runtime.mutableIntStateOf
35
+ import androidx.compose.runtime.mutableStateOf
36
+ import androidx.compose.runtime.remember
34
37
  import androidx.compose.runtime.saveable.rememberSaveable
38
+ import androidx.compose.runtime.setValue
35
39
  import androidx.compose.ui.Modifier
36
40
  import androidx.compose.ui.input.pointer.PointerInputScope
37
41
  import androidx.compose.ui.input.pointer.pointerInput
38
- import androidx.compose.ui.platform.LocalContext
39
42
  import androidx.compose.ui.platform.LocalView
40
43
  import androidx.compose.ui.text.TextStyle
41
44
  import androidx.compose.ui.text.font.FontWeight
42
45
  import androidx.compose.ui.unit.dp
43
46
  import androidx.compose.ui.unit.sp
47
+ import dev.pyrossh.onlyBible.composables.BibleSelector
48
+ import dev.pyrossh.onlyBible.composables.ChapterSelector
44
49
  import dev.pyrossh.onlyBible.composables.EmbeddedSearchBar
45
50
  import dev.pyrossh.onlyBible.composables.VerseView
46
- import kotlinx.coroutines.Job
47
51
  import kotlinx.parcelize.Parcelize
48
52
  import kotlinx.serialization.Serializable
49
53
  import kotlin.math.abs
@@ -106,7 +110,6 @@ suspend fun PointerInputScope.detectSwipe(
106
110
  }
107
111
  )
108
112
 
109
-
110
113
  @OptIn(ExperimentalMaterial3Api::class)
111
114
  @Composable
112
115
  fun ChapterScreen(
@@ -115,15 +118,16 @@ fun ChapterScreen(
115
118
  onSwipeRight: () -> Any,
116
119
  bookIndex: Int,
117
120
  chapterIndex: Int,
118
- openDrawer: (MenuType, Int) -> Job,
121
+ navigateToChapter: (ChapterScreenProps) -> Unit,
119
122
  ) {
120
123
  val view = LocalView.current
121
- val context = LocalContext.current
122
124
  val verses by model.verses.collectAsState()
123
125
  val bookNames by model.bookNames.collectAsState()
124
126
  val searchText by model.searchText.collectAsState()
125
127
  val isSearching by model.isSearching.collectAsState()
126
128
  val versesList by model.versesList.collectAsState()
129
+ var chapterSelectorShown by remember { mutableStateOf(false) }
130
+ var bibleSelectorShown by remember { mutableStateOf(false) }
127
131
  val fontSizeDelta = model.fontSizeDelta
128
132
  val headingColor = MaterialTheme.colorScheme.onSurface // MaterialTheme.colorScheme.primary,
129
133
  val chapterVerses =
@@ -182,26 +186,17 @@ fun ChapterScreen(
182
186
  .fillMaxWidth(),
183
187
  ) {
184
188
  TextButton(
185
- contentPadding = PaddingValues(0.dp),
189
+ contentPadding = PaddingValues(
186
- onClick = { openDrawer(MenuType.Book, bookIndex) }
190
+ top = ContentPadding.calculateTopPadding(),
187
- ) {
188
- Text(
189
- text = bookNames[bookIndex] +
190
- (if (bookNames[bookIndex].length <= 4) "\u3164" else ""),
191
- // this unicode character is to prevent Job for shifting to right
192
- style = TextStyle(
193
- fontSize = 22.sp,
191
+ end = 12.dp,
194
- fontWeight = FontWeight.W500,
195
- color = headingColor,
192
+ bottom = ContentPadding.calculateBottomPadding()
196
- )
193
+ ),
197
- )
194
+ onClick = {
195
+ chapterSelectorShown = true
198
- }
196
+ }
199
- TextButton(
200
- contentPadding = PaddingValues(0.dp),
201
- onClick = { openDrawer(MenuType.Chapter, bookIndex) }
202
197
  ) {
203
198
  Text(
204
- text = "${chapterIndex + 1}",
199
+ text = "${bookNames[bookIndex]} ${chapterIndex + 1}",
205
200
  style = TextStyle(
206
201
  fontSize = 22.sp,
207
202
  fontWeight = FontWeight.W500,
@@ -221,7 +216,9 @@ fun ChapterScreen(
221
216
  tint = headingColor,
222
217
  )
223
218
  }
224
- TextButton(onClick = { openDrawer(MenuType.Bible, bookIndex) }) {
219
+ TextButton(onClick = {
220
+ bibleSelectorShown = true
221
+ }) {
225
222
  Text(
226
223
  text = model.getBibleName(),
227
224
  style = TextStyle(
@@ -246,6 +243,20 @@ fun ChapterScreen(
246
243
  )
247
244
  },
248
245
  ) { innerPadding ->
246
+ if (bibleSelectorShown) {
247
+ BibleSelector(
248
+ model = model,
249
+ onClose = { bibleSelectorShown = false },
250
+ )
251
+ }
252
+ if (chapterSelectorShown) {
253
+ ChapterSelector(
254
+ model = model,
255
+ onClose = { chapterSelectorShown = false },
256
+ navigateToChapter = navigateToChapter,
257
+ )
258
+ }
259
+
249
260
  LazyColumn(
250
261
  state = rememberSaveable(saver = LazyListState.Saver) {
251
262
  model.scrollState
app/src/main/java/dev/pyrossh/onlyBible/composables/BibleSelector.kt ADDED
@@ -0,0 +1,78 @@
1
+ package dev.pyrossh.onlyBible.composables
2
+
3
+ import androidx.compose.foundation.clickable
4
+ import androidx.compose.foundation.layout.fillMaxWidth
5
+ import androidx.compose.foundation.layout.height
6
+ import androidx.compose.foundation.layout.padding
7
+ import androidx.compose.foundation.lazy.LazyColumn
8
+ import androidx.compose.foundation.lazy.items
9
+ import androidx.compose.foundation.shape.RoundedCornerShape
10
+ import androidx.compose.material3.Card
11
+ import androidx.compose.material3.ListItem
12
+ import androidx.compose.material3.ListItemDefaults
13
+ import androidx.compose.material3.MaterialTheme
14
+ import androidx.compose.material3.Text
15
+ import androidx.compose.runtime.Composable
16
+ import androidx.compose.ui.Modifier
17
+ import androidx.compose.ui.platform.LocalContext
18
+ import androidx.compose.ui.text.font.FontWeight
19
+ import androidx.compose.ui.unit.dp
20
+ import androidx.compose.ui.window.Dialog
21
+ import dev.pyrossh.onlyBible.AppViewModel
22
+ import dev.pyrossh.onlyBible.domain.bibles
23
+ import dev.pyrossh.onlyBible.setLocale
24
+ import java.util.Locale
25
+
26
+ @Composable
27
+ fun BibleSelector(
28
+ model: AppViewModel,
29
+ onClose: () -> Unit,
30
+ ) {
31
+ val context = LocalContext.current
32
+ val height = context.resources.configuration.screenHeightDp.dp / 2
33
+ Dialog(onDismissRequest = { onClose() }) {
34
+ Card(
35
+ modifier = Modifier
36
+ .fillMaxWidth()
37
+ .height(height),
38
+ shape = RoundedCornerShape(8.dp),
39
+ ) {
40
+ LazyColumn {
41
+ items(bibles) {
42
+ val arr = it.split("_")
43
+ val loc = Locale(arr[0])
44
+ ListItem(
45
+ modifier = Modifier.clickable {
46
+ onClose()
47
+ model.bible = it
48
+ model.loadBible()
49
+ context.setLocale(loc)
50
+ },
51
+ colors = ListItemDefaults.colors(
52
+ containerColor = if (model.bible == it)
53
+ MaterialTheme.colorScheme.outline
54
+ else
55
+ MaterialTheme.colorScheme.background
56
+ ),
57
+ headlineContent = {
58
+ Text(
59
+ modifier = Modifier.padding(start = 4.dp),
60
+ fontWeight = FontWeight.W600,
61
+ text = loc.getDisplayName(Locale.ENGLISH),
62
+ )
63
+ },
64
+ supportingContent = {
65
+ Text(
66
+ modifier = Modifier.padding(start = 4.dp),
67
+ text = if (arr.size > 1)
68
+ arr[1].uppercase()
69
+ else
70
+ loc.getDisplayName(loc)
71
+ )
72
+ }
73
+ )
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
app/src/main/java/dev/pyrossh/onlyBible/composables/ChapterSelector.kt ADDED
@@ -0,0 +1,156 @@
1
+ package dev.pyrossh.onlyBible.composables
2
+
3
+ import androidx.compose.foundation.clickable
4
+ import androidx.compose.foundation.layout.Arrangement
5
+ import androidx.compose.foundation.layout.Spacer
6
+ import androidx.compose.foundation.layout.fillMaxSize
7
+ import androidx.compose.foundation.layout.fillMaxWidth
8
+ import androidx.compose.foundation.layout.height
9
+ import androidx.compose.foundation.layout.padding
10
+ import androidx.compose.foundation.lazy.LazyColumn
11
+ import androidx.compose.foundation.lazy.grid.GridCells
12
+ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
13
+ import androidx.compose.foundation.lazy.rememberLazyListState
14
+ import androidx.compose.foundation.shape.RoundedCornerShape
15
+ import androidx.compose.material3.ButtonColors
16
+ import androidx.compose.material3.Card
17
+ import androidx.compose.material3.ExperimentalMaterial3Api
18
+ import androidx.compose.material3.ExposedDropdownMenuDefaults
19
+ import androidx.compose.material3.ListItem
20
+ import androidx.compose.material3.ListItemDefaults
21
+ import androidx.compose.material3.MaterialTheme
22
+ import androidx.compose.material3.Surface
23
+ import androidx.compose.material3.Text
24
+ import androidx.compose.material3.TextButton
25
+ import androidx.compose.runtime.Composable
26
+ import androidx.compose.runtime.LaunchedEffect
27
+ import androidx.compose.runtime.collectAsState
28
+ import androidx.compose.runtime.getValue
29
+ import androidx.compose.runtime.mutableIntStateOf
30
+ import androidx.compose.runtime.mutableStateOf
31
+ import androidx.compose.runtime.remember
32
+ import androidx.compose.runtime.setValue
33
+ import androidx.compose.ui.Modifier
34
+ import androidx.compose.ui.graphics.Color
35
+ import androidx.compose.ui.platform.LocalContext
36
+ import androidx.compose.ui.text.font.FontWeight
37
+ import androidx.compose.ui.unit.dp
38
+ import androidx.compose.ui.window.Dialog
39
+ import dev.pyrossh.onlyBible.AppViewModel
40
+ import dev.pyrossh.onlyBible.ChapterScreenProps
41
+ import dev.pyrossh.onlyBible.domain.BOOKS_COUNT
42
+ import dev.pyrossh.onlyBible.domain.chapterSizes
43
+
44
+ @OptIn(ExperimentalMaterial3Api::class)
45
+ @Composable
46
+ fun ChapterSelector(
47
+ model: AppViewModel,
48
+ onClose: () -> Unit,
49
+ navigateToChapter: (ChapterScreenProps) -> Unit
50
+ ) {
51
+ val context = LocalContext.current
52
+ val height = context.resources.configuration.screenHeightDp.dp / 2
53
+ val bookNames by model.bookNames.collectAsState()
54
+ var expanded by remember { mutableStateOf(false) }
55
+ var bookIndex by remember { mutableIntStateOf(model.bookIndex) }
56
+ val scrollState = rememberLazyListState()
57
+ LaunchedEffect(key1 = bookIndex) {
58
+ scrollState.scrollToItem(0, 0)
59
+ }
60
+ Dialog(onDismissRequest = { onClose() }) {
61
+ Card(
62
+ modifier = Modifier
63
+ .fillMaxWidth()
64
+ .height(height),
65
+ shape = RoundedCornerShape(8.dp),
66
+ ) {
67
+ ListItem(
68
+ modifier = Modifier
69
+ .clickable {
70
+ expanded = !expanded
71
+ },
72
+ headlineContent = {
73
+ Text(
74
+ modifier = Modifier.padding(start = 4.dp),
75
+ fontWeight = FontWeight.W600,
76
+ text = bookNames[bookIndex]
77
+ )
78
+ },
79
+ trailingContent = {
80
+ ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
81
+ }
82
+ )
83
+ if (expanded) {
84
+ LazyColumn(
85
+ state = scrollState,
86
+ ) {
87
+ items(BOOKS_COUNT) {
88
+ ListItem(
89
+ modifier = Modifier.clickable {
90
+ bookIndex = it
91
+ expanded = false
92
+ },
93
+ colors = ListItemDefaults.colors(
94
+ containerColor = if (bookIndex == it)
95
+ MaterialTheme.colorScheme.outline
96
+ else
97
+ MaterialTheme.colorScheme.background
98
+ ),
99
+ headlineContent = {
100
+ Text(
101
+ modifier = Modifier.padding(start = 4.dp),
102
+ fontWeight = FontWeight.W600,
103
+ text = bookNames[it],
104
+ )
105
+ },
106
+ )
107
+ }
108
+ }
109
+ }
110
+ LazyVerticalGrid(
111
+ modifier = Modifier
112
+ .fillMaxSize()
113
+ .padding(16.dp),
114
+ verticalArrangement = Arrangement.spacedBy(10.dp),
115
+ horizontalArrangement = Arrangement.spacedBy(10.dp),
116
+ columns = GridCells.Fixed(5)
117
+ ) {
118
+ items(chapterSizes[bookIndex]) { c ->
119
+ Surface(
120
+ shadowElevation = 1.dp,
121
+ shape = RoundedCornerShape(8.dp),
122
+ modifier = Modifier
123
+ .fillMaxWidth()
124
+ ) {
125
+ TextButton(
126
+ colors = ButtonColors(
127
+ containerColor = Color.White,
128
+ contentColor = Color.Black,
129
+ disabledContentColor = Color.Gray,
130
+ disabledContainerColor = Color.Gray,
131
+ ),
132
+ shape = RoundedCornerShape(8.dp),
133
+ onClick = {
134
+ onClose()
135
+ navigateToChapter(
136
+ ChapterScreenProps(
137
+ bookIndex = bookIndex,
138
+ chapterIndex = c,
139
+ )
140
+ )
141
+ }
142
+ ) {
143
+ Text(
144
+ fontWeight = FontWeight.W600,
145
+ text = "${c + 1}"
146
+ )
147
+ }
148
+ }
149
+ }
150
+ item {
151
+ Spacer(modifier = Modifier.padding(bottom = 8.dp))
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }