Skip to content

Commit 70277b1

Browse files
added search and title to BottomSelectDialog (#26)
* added search and title to BottomSelectDialog * handle keyboard * Fix BottomSheet shape for tablets --------- Co-authored-by: Volodymyr Chekyrta <[email protected]>
1 parent 3e3c2bf commit 70277b1

File tree

9 files changed

+361
-175
lines changed

9 files changed

+361
-175
lines changed

auth/src/main/java/com/raccoongang/auth/presentation/signup/SignUpFragment.kt

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.compose.ui.layout.ContentScale
2828
import androidx.compose.ui.platform.*
2929
import androidx.compose.ui.res.painterResource
3030
import androidx.compose.ui.res.stringResource
31+
import androidx.compose.ui.text.input.TextFieldValue
3132
import androidx.compose.ui.text.style.TextAlign
3233
import androidx.compose.ui.tooling.preview.Devices
3334
import androidx.compose.ui.tooling.preview.Preview
@@ -111,8 +112,10 @@ internal fun RegistrationScreen(
111112
) {
112113
val scaffoldState = rememberScaffoldState()
113114
val configuration = LocalConfiguration.current
115+
val focusManager = LocalFocusManager.current
114116
val bottomSheetScaffoldState = rememberModalBottomSheetState(
115-
initialValue = ModalBottomSheetValue.Hidden
117+
initialValue = ModalBottomSheetValue.Hidden,
118+
skipHalfExpanded = true
116119
)
117120
val coroutine = rememberCoroutineScope()
118121
val keyboardController = LocalSoftwareKeyboardController.current
@@ -140,6 +143,16 @@ internal fun RegistrationScreen(
140143

141144
val listState = rememberLazyListState()
142145

146+
var bottomDialogTitle by rememberSaveable {
147+
mutableStateOf("")
148+
}
149+
150+
var searchValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
151+
mutableStateOf(TextFieldValue())
152+
}
153+
154+
val isImeVisible by isImeVisibleState()
155+
143156
LaunchedEffect(validationError) {
144157
if (validationError) {
145158
coroutine.launch {
@@ -149,6 +162,13 @@ internal fun RegistrationScreen(
149162
}
150163
}
151164

165+
LaunchedEffect(bottomSheetScaffoldState.isVisible) {
166+
if (!bottomSheetScaffoldState.isVisible) {
167+
focusManager.clearFocus()
168+
searchValue = TextFieldValue("")
169+
}
170+
}
171+
152172
Scaffold(
153173
scaffoldState = scaffoldState,
154174
modifier = Modifier
@@ -193,17 +213,9 @@ internal fun RegistrationScreen(
193213
)
194214
}
195215

196-
val bottomSheetWeight by remember(key1 = windowSize) {
197-
mutableStateOf(
198-
windowSize.windowSizeValue(
199-
expanded = if (configuration.orientation == ORIENTATION_PORTRAIT) 0.8f else 0.6f,
200-
compact = 1f
201-
)
202-
)
203-
}
204-
205216
ModalBottomSheetLayout(
206217
modifier = Modifier
218+
.padding(bottom = if (isImeVisible && bottomSheetScaffoldState.isVisible) 120.dp else 0.dp)
207219
.noRippleClickable {
208220
if (bottomSheetScaffoldState.isVisible) {
209221
coroutine.launch {
@@ -212,24 +224,25 @@ internal fun RegistrationScreen(
212224
}
213225
},
214226
sheetState = bottomSheetScaffoldState,
215-
sheetShape = BottomSheetShape(
216-
width = configuration.screenWidthDp.px,
217-
height = configuration.screenHeightDp.px,
218-
weight = bottomSheetWeight
219-
),
227+
sheetShape = MaterialTheme.appShapes.screenBackgroundShape,
220228
scrimColor = Color.Black.copy(alpha = 0.4f),
221229
sheetBackgroundColor = MaterialTheme.appColors.background,
222230
sheetContent = {
223231
SheetContent(
232+
title = bottomDialogTitle,
233+
searchValue = searchValue,
224234
expandedList = expandedList,
235+
listState = listState,
225236
onItemClick = { item ->
226237
mapFields[serverFieldName.value] = item.value
227238
selectableNamesMap[serverFieldName.value] = item.name
228239
coroutine.launch {
229240
bottomSheetScaffoldState.hide()
230241
}
231242
},
232-
listState = listState
243+
searchValueChanged = {
244+
searchValue = TextFieldValue(it)
245+
}
233246
)
234247
}
235248
) {
@@ -337,6 +350,7 @@ internal fun RegistrationScreen(
337350
if (bottomSheetScaffoldState.isVisible) {
338351
bottomSheetScaffoldState.hide()
339352
} else {
353+
bottomDialogTitle = field.label
340354
showErrorMap[field.name] = false
341355
bottomSheetScaffoldState.show()
342356
}
@@ -363,6 +377,7 @@ internal fun RegistrationScreen(
363377
if (bottomSheetScaffoldState.isVisible) {
364378
bottomSheetScaffoldState.hide()
365379
} else {
380+
bottomDialogTitle = field.label
366381
showErrorMap[field.name] = false
367382
bottomSheetScaffoldState.show()
368383
}

auth/src/main/java/com/raccoongang/auth/presentation/ui/AuthUI.kt

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,29 @@ import androidx.compose.animation.core.animateFloat
66
import androidx.compose.animation.core.tween
77
import androidx.compose.animation.core.updateTransition
88
import androidx.compose.foundation.background
9-
import androidx.compose.foundation.layout.*
9+
import androidx.compose.foundation.layout.Arrangement
10+
import androidx.compose.foundation.layout.Column
11+
import androidx.compose.foundation.layout.Row
12+
import androidx.compose.foundation.layout.Spacer
13+
import androidx.compose.foundation.layout.fillMaxWidth
14+
import androidx.compose.foundation.layout.height
1015
import androidx.compose.foundation.lazy.rememberLazyListState
1116
import androidx.compose.foundation.text.KeyboardActions
1217
import androidx.compose.foundation.text.KeyboardOptions
13-
import androidx.compose.material.*
18+
import androidx.compose.material.Icon
19+
import androidx.compose.material.MaterialTheme
20+
import androidx.compose.material.OutlinedTextField
21+
import androidx.compose.material.Text
22+
import androidx.compose.material.TextFieldDefaults
1423
import androidx.compose.material.icons.Icons
1524
import androidx.compose.material.icons.filled.ChevronRight
1625
import androidx.compose.material.icons.filled.ExpandMore
17-
import androidx.compose.runtime.*
26+
import androidx.compose.runtime.Composable
27+
import androidx.compose.runtime.getValue
28+
import androidx.compose.runtime.mutableStateOf
29+
import androidx.compose.runtime.remember
1830
import androidx.compose.runtime.saveable.rememberSaveable
31+
import androidx.compose.runtime.setValue
1932
import androidx.compose.runtime.snapshots.SnapshotStateMap
2033
import androidx.compose.ui.Modifier
2134
import androidx.compose.ui.draw.rotate
@@ -25,7 +38,11 @@ import androidx.compose.ui.focus.focusTarget
2538
import androidx.compose.ui.focus.onFocusChanged
2639
import androidx.compose.ui.platform.LocalFocusManager
2740
import androidx.compose.ui.res.stringResource
28-
import androidx.compose.ui.text.input.*
41+
import androidx.compose.ui.text.input.ImeAction
42+
import androidx.compose.ui.text.input.KeyboardType
43+
import androidx.compose.ui.text.input.PasswordVisualTransformation
44+
import androidx.compose.ui.text.input.TextFieldValue
45+
import androidx.compose.ui.text.input.VisualTransformation
2946
import androidx.compose.ui.tooling.preview.Preview
3047
import androidx.compose.ui.unit.dp
3148
import com.raccoongang.auth.R
@@ -63,6 +80,7 @@ fun RequiredFields(
6380
}
6481
)
6582
}
83+
6684
RegistrationFieldType.PLAINTEXT -> {
6785
val linkedText =
6886
TextConverter.htmlTextToLinkedText(field.label)
@@ -72,9 +90,11 @@ fun RequiredFields(
7290
linkTextColor = MaterialTheme.appColors.primary
7391
)
7492
}
93+
7594
RegistrationFieldType.CHECKBOX -> {
7695
//Text("checkbox")
7796
}
97+
7898
RegistrationFieldType.SELECT -> {
7999
SelectableRegisterField(
80100
registrationField = field,
@@ -85,6 +105,7 @@ fun RequiredFields(
85105
}
86106
)
87107
}
108+
88109
RegistrationFieldType.TEXTAREA -> {
89110
InputRegistrationField(
90111
modifier = Modifier
@@ -100,6 +121,7 @@ fun RequiredFields(
100121
}
101122
)
102123
}
124+
103125
RegistrationFieldType.UNKNOWN -> {
104126

105127
}
@@ -134,6 +156,7 @@ fun OptionalFields(
134156
}
135157
)
136158
}
159+
137160
RegistrationFieldType.PLAINTEXT -> {
138161
val linkedText =
139162
TextConverter.htmlTextToLinkedText(
@@ -145,9 +168,11 @@ fun OptionalFields(
145168
linkTextColor = MaterialTheme.appColors.primary
146169
)
147170
}
171+
148172
RegistrationFieldType.CHECKBOX -> {
149173
//Text("checkbox")
150174
}
175+
151176
RegistrationFieldType.SELECT -> {
152177
SelectableRegisterField(
153178
registrationField = field,
@@ -159,6 +184,7 @@ fun OptionalFields(
159184
onSelectClick(serverName, field, list)
160185
})
161186
}
187+
162188
RegistrationFieldType.TEXTAREA -> {
163189
InputRegistrationField(
164190
modifier = Modifier
@@ -177,6 +203,7 @@ fun OptionalFields(
177203
}
178204
)
179205
}
206+
180207
RegistrationFieldType.UNKNOWN -> {
181208
}
182209
}
@@ -535,9 +562,11 @@ private fun SheetContentPreview() {
535562
NewEdxTheme {
536563
Column(Modifier.background(MaterialTheme.appColors.background)) {
537564
SheetContent(
565+
searchValue = TextFieldValue(),
538566
expandedList = listOf(option, option, option),
539567
onItemClick = {},
540-
listState = rememberLazyListState()
568+
listState = rememberLazyListState(),
569+
searchValueChanged = {}
541570
)
542571
}
543572
}

core/src/main/java/com/raccoongang/core/presentation/dialog/SelectBottomDialogFragment.kt

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
package com.raccoongang.core.presentation.dialog
22

3-
import android.content.res.Configuration
43
import android.graphics.Color
54
import android.graphics.drawable.ColorDrawable
65
import android.os.Bundle
76
import android.view.LayoutInflater
87
import android.view.ViewGroup
8+
import androidx.compose.foundation.background
9+
import androidx.compose.foundation.layout.Box
10+
import androidx.compose.foundation.layout.fillMaxWidth
11+
import androidx.compose.foundation.layout.widthIn
912
import androidx.compose.foundation.lazy.rememberLazyListState
1013
import androidx.compose.material.MaterialTheme
1114
import androidx.compose.material.Surface
1215
import androidx.compose.runtime.getValue
1316
import androidx.compose.runtime.mutableStateOf
14-
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.saveable.rememberSaveable
18+
import androidx.compose.runtime.setValue
19+
import androidx.compose.ui.Alignment
20+
import androidx.compose.ui.Modifier
21+
import androidx.compose.ui.draw.clip
1522
import androidx.compose.ui.platform.ComposeView
16-
import androidx.compose.ui.platform.LocalConfiguration
1723
import androidx.compose.ui.platform.ViewCompositionStrategy
24+
import androidx.compose.ui.text.input.TextFieldValue
25+
import androidx.compose.ui.unit.dp
1826
import androidx.fragment.app.DialogFragment
1927
import com.google.android.material.bottomsheet.BottomSheetBehavior
2028
import com.google.android.material.bottomsheet.BottomSheetDialog
@@ -23,15 +31,12 @@ import com.raccoongang.core.R
2331
import com.raccoongang.core.domain.model.RegistrationField
2432
import com.raccoongang.core.extension.parcelableArrayList
2533
import com.raccoongang.core.ui.SheetContent
26-
import com.raccoongang.core.ui.px
27-
import com.raccoongang.core.ui.rememberWindowSize
28-
import com.raccoongang.core.ui.theme.BottomSheetShape
2934
import com.raccoongang.core.ui.theme.NewEdxTheme
3035
import com.raccoongang.core.ui.theme.appColors
31-
import com.raccoongang.core.ui.windowSizeValue
36+
import com.raccoongang.core.ui.theme.appShapes
3237
import org.koin.androidx.viewmodel.ext.android.viewModel
3338

34-
class SelectBottomDialogFragment() : BottomSheetDialogFragment() {
39+
class SelectBottomDialogFragment : BottomSheetDialogFragment() {
3540

3641
private val viewModel by viewModel<SelectDialogViewModel>()
3742

@@ -44,7 +49,7 @@ class SelectBottomDialogFragment() : BottomSheetDialogFragment() {
4449
override fun onCreateView(
4550
inflater: LayoutInflater,
4651
container: ViewGroup?,
47-
savedInstanceState: Bundle?
52+
savedInstanceState: Bundle?,
4853
) = ComposeView(requireContext()).apply {
4954
if (dialog != null && dialog!!.window != null) {
5055
dialog!!.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
@@ -55,34 +60,41 @@ class SelectBottomDialogFragment() : BottomSheetDialogFragment() {
5560
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
5661
setContent {
5762
NewEdxTheme {
58-
val windowSize = rememberWindowSize()
59-
val configuration = LocalConfiguration.current
6063
val listState = rememberLazyListState()
61-
val bottomSheetWeight by remember(key1 = windowSize) {
62-
mutableStateOf(
63-
windowSize.windowSizeValue(
64-
expanded = if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) 0.8f else 0.6f,
65-
compact = 1f
66-
)
67-
)
64+
65+
var searchValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
66+
mutableStateOf(TextFieldValue())
6867
}
6968

70-
Surface(
71-
shape = BottomSheetShape(
72-
width = configuration.screenWidthDp.px,
73-
height = configuration.screenHeightDp.px,
74-
weight = bottomSheetWeight
75-
),
76-
color = MaterialTheme.appColors.background
77-
) {
78-
SheetContent(
79-
expandedList = viewModel.values,
80-
onItemClick = { item ->
81-
viewModel.sendCourseEventChanged(item.value)
82-
dismiss()
83-
},
84-
listState = listState
85-
)
69+
Surface(color = androidx.compose.ui.graphics.Color.Transparent) {
70+
Box(
71+
modifier = Modifier,
72+
contentAlignment = Alignment.TopCenter
73+
) {
74+
Box(
75+
modifier = Modifier
76+
.widthIn(max = 640.dp)
77+
.fillMaxWidth()
78+
.background(
79+
color = MaterialTheme.appColors.background,
80+
shape = MaterialTheme.appShapes.screenBackgroundShape
81+
)
82+
.clip(MaterialTheme.appShapes.screenBackgroundShape)
83+
) {
84+
SheetContent(
85+
searchValue = searchValue,
86+
expandedList = viewModel.values,
87+
onItemClick = { item ->
88+
viewModel.sendCourseEventChanged(item.value)
89+
dismiss()
90+
},
91+
listState = listState,
92+
searchValueChanged = {
93+
searchValue = TextFieldValue(it)
94+
}
95+
)
96+
}
97+
}
8698
}
8799
}
88100
}
@@ -92,7 +104,7 @@ class SelectBottomDialogFragment() : BottomSheetDialogFragment() {
92104
private const val ARG_LIST_VALUES = "argListValues"
93105

94106
fun newInstance(
95-
values: List<RegistrationField.Option>
107+
values: List<RegistrationField.Option>,
96108
): SelectBottomDialogFragment {
97109
val dialog = SelectBottomDialogFragment()
98110
dialog.arguments = Bundle().apply {

0 commit comments

Comments
 (0)