Skip to content

Commit 7f18823

Browse files
authored
Merge pull request #129 from captures-2024/fix/SG-151-Scroll-Picker-interaction
[SG-151] scroll picker interaction
2 parents 4d44b44 + 1007fca commit 7f18823

File tree

6 files changed

+54
-39
lines changed

6 files changed

+54
-39
lines changed

core/model/src/main/kotlin/com/captures2024/soongan/core/model/AppConst.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ object AppConst {
3131

3232
object Gallery {
3333
const val PAGE_SIZE = 50
34+
const val SCROLL_PICKER_VISIBLE_OPTION_COUNT = 9
3435
}
3536
}
3637

@@ -47,8 +48,4 @@ object AppConst {
4748
const val ACCESS_TOKEN_ALLOW = "$AUTH_HEADER: true"
4849
const val REFRESH_TOKEN_ALLOW = "$AUTH_HEADER: false"
4950
}
50-
51-
object SavedStateHandle {
52-
const val UGC_HIDE_KEY = "ugc-hide-key"
53-
}
5451
}

gradle/libs.versions.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ android-credentials = "1.5.0"
4141
android-compose-bom = "2025.07.00"
4242
android-compose-activity = "1.10.1"
4343
android-compose-junit4-test = "1.8.3"
44+
android-compose-material3-alpha = "1.4.0-alpha02"
45+
android-compose-material-Icons-Core = "1.7.8"
4446

4547
# test
4648
test-junit = "4.13.2"
@@ -124,6 +126,8 @@ android-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-tes
124126
android-compose-activity = { group = "androidx.activity", name = "activity-compose", version.ref = "android-compose-activity" }
125127
android-compose-lifecycle = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "android-lifecycle-runtime" }
126128
android-compose-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "android-navigation" }
129+
android-compose-material3-alpha = { module = "androidx.compose.material3:material3", version.ref = "android-compose-material3-alpha" }
130+
android-compose-material-icons-core = { module = "androidx.compose.material:material-icons-core", version.ref = "android-compose-material-Icons-Core" }
127131

128132
# google
129133
google-ksp-gradle-plugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "google-ksp" }
@@ -274,3 +278,8 @@ androidx-android-test = [
274278
"test-androidx-junit",
275279
"test-androidx-espresso-core"
276280
]
281+
282+
compose-material3-alpha = [
283+
"android-compose-material3-alpha",
284+
"android-compose-material-icons-core",
285+
]

presentation/feature/main-feed/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ android {
88

99
dependencies {
1010
implementation(projects.presentation.viewmodel)
11+
implementation(libs.bundles.compose.material3.alpha)
1112
}

presentation/feature/main-feed/src/main/kotlin/com/captures2024/soongan/presentation/feature/main/feed/component/feed/FeedScrollPickerComponent.kt

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package com.captures2024.soongan.presentation.feature.main.feed.component.feed
22

33
import androidx.compose.foundation.border
4+
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
6+
import androidx.compose.foundation.interaction.MutableInteractionSource
57
import androidx.compose.foundation.layout.Box
68
import androidx.compose.foundation.layout.Column
79
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.fillMaxSize
811
import androidx.compose.foundation.layout.fillMaxWidth
912
import androidx.compose.foundation.layout.height
1013
import androidx.compose.foundation.layout.offset
1114
import androidx.compose.foundation.layout.padding
1215
import androidx.compose.foundation.layout.width
13-
import androidx.compose.foundation.layout.wrapContentSize
1416
import androidx.compose.foundation.lazy.LazyColumn
1517
import androidx.compose.foundation.lazy.rememberLazyListState
1618
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -25,23 +27,19 @@ import androidx.compose.runtime.snapshotFlow
2527
import androidx.compose.ui.Alignment
2628
import androidx.compose.ui.Modifier
2729
import androidx.compose.ui.draw.drawWithContent
28-
import androidx.compose.ui.geometry.Offset
2930
import androidx.compose.ui.graphics.BlendMode
3031
import androidx.compose.ui.graphics.Brush
3132
import androidx.compose.ui.graphics.Color
3233
import androidx.compose.ui.graphics.CompositingStrategy
3334
import androidx.compose.ui.graphics.RectangleShape
3435
import androidx.compose.ui.graphics.graphicsLayer
35-
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
36-
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
37-
import androidx.compose.ui.input.nestedscroll.nestedScroll
3836
import androidx.compose.ui.res.stringResource
3937
import androidx.compose.ui.text.font.FontWeight
4038
import androidx.compose.ui.unit.dp
4139
import androidx.compose.ui.unit.sp
4240
import com.captures2024.soongan.core.model.AppConst
4341
import com.captures2024.soongan.presentation.designsystem.ui.component.HeightSpacer
44-
import com.captures2024.soongan.presentation.designsystem.ui.component.WidthSpacer
42+
import com.captures2024.soongan.presentation.designsystem.ui.component.WeightSpacer
4543
import com.captures2024.soongan.presentation.designsystem.ui.component.text.SGText
4644
import com.captures2024.soongan.presentation.designsystem.ui.component.text.getSGNonScaleTextStyle
4745
import com.captures2024.soongan.presentation.designsystem.ui.theme.SGColor
@@ -70,7 +68,7 @@ internal fun FeedScrollTitlePickerComponent(
7068
text = stringResource(R.string.feed_scroll_title_picker_header_text),
7169
modifier = Modifier
7270
.align(Alignment.Start)
73-
.padding(start = 24.dp),
71+
.padding(start = 26.dp, top = 27.dp),
7472
style = getSGNonScaleTextStyle(
7573
color = SGColor.Grayscale.black100,
7674
fontSize = 20.sp,
@@ -85,12 +83,17 @@ internal fun FeedScrollTitlePickerComponent(
8583
options = options,
8684
modifier = Modifier.padding(horizontal = 10.dp),
8785
onChangedOption = onChangedOption,
86+
onItemClick = { clickedIndex ->
87+
onChangedOption(clickedIndex)
88+
},
8889
)
8990

9091
HeightSpacer(32.dp)
9192

9293
Row(
93-
modifier = Modifier.padding(bottom = 60.dp),
94+
modifier = Modifier
95+
.padding(bottom = 61.dp)
96+
.padding(horizontal = 48.dp),
9497
) {
9598
TempPickerButton(
9699
text = stringResource(R.string.feed_scroll_title_picker_dismiss_text),
@@ -99,7 +102,7 @@ internal fun FeedScrollTitlePickerComponent(
99102
borderColor = SGColor.black,
100103
onClick = onDismissRequest,
101104
)
102-
WidthSpacer(54.dp)
105+
WeightSpacer(1f)
103106
TempPickerButton(
104107
text = stringResource(R.string.feed_scroll_title_picker_confirm_text),
105108
textColor = SGColor.Grayscale.white,
@@ -116,10 +119,10 @@ private fun ScrollPicker(
116119
selectedOption: TitleOption,
117120
options: List<TitleOption>,
118121
modifier: Modifier = Modifier,
119-
visibleOptionCount: Int = 5,
120122
onChangedOption: (Int) -> Unit,
123+
onItemClick: ((Int) -> Unit)? = null,
121124
) {
122-
val median = visibleOptionCount / 2
125+
val median = AppConst.Main.Gallery.SCROLL_PICKER_VISIBLE_OPTION_COUNT / 2
123126
val spaceOptions = List(median) { null }
124127
val adjustedOptions = spaceOptions + options + spaceOptions
125128
val listCount = adjustedOptions.size
@@ -147,7 +150,7 @@ private fun ScrollPicker(
147150
1f to Color.Transparent,
148151
)
149152

150-
val boxHeight = 264.dp
153+
val boxHeight = 252.dp
151154
val itemSize = 28.dp
152155

153156
val upperDividerYOffset = boxHeight / 2 - itemSize / 2
@@ -160,6 +163,13 @@ private fun ScrollPicker(
160163
.collect { round -> onChangedOption(round) }
161164
}
162165

166+
LaunchedEffect(selectedOption) {
167+
val targetIndex = selectedOption.round - 1
168+
if (targetIndex != listState.firstVisibleItemIndex) {
169+
listState.animateScrollToItem(targetIndex)
170+
}
171+
}
172+
163173
Box(
164174
modifier = modifier
165175
.fillMaxWidth()
@@ -169,15 +179,6 @@ private fun ScrollPicker(
169179
blur = 0.dp,
170180
offsetX = 0.dp,
171181
offsetY = (-0.5).dp,
172-
)
173-
.nestedScroll(
174-
object : NestedScrollConnection {
175-
override fun onPostScroll(
176-
consumed: Offset,
177-
available: Offset,
178-
source: NestedScrollSource,
179-
): Offset = available
180-
},
181182
),
182183
) {
183184
HorizontalDivider(
@@ -198,15 +199,15 @@ private fun ScrollPicker(
198199
horizontalAlignment = Alignment.CenterHorizontally,
199200
modifier = Modifier
200201
.align(Alignment.Center)
201-
.wrapContentSize()
202-
.height(itemSize * visibleOptionCount)
202+
.fillMaxSize()
203203
.fadingEdge(fadingEdgeGradient),
204204
) {
205205
items(
206206
count = listCount,
207207
key = { it },
208208
) { index ->
209209
val distanceFromCenter = kotlin.math.abs(index - currentCenterIndex.value)
210+
val centerIndex = index - median
210211
val fontSize = when (distanceFromCenter) {
211212
0 -> 23.sp
212213
1 -> 18.sp
@@ -215,7 +216,19 @@ private fun ScrollPicker(
215216
}
216217

217218
Box(
218-
modifier = Modifier.height(itemSize),
219+
modifier = Modifier
220+
.height(itemSize)
221+
.fillMaxWidth()
222+
.then(
223+
if (onItemClick != null && centerIndex in options.indices) {
224+
Modifier.clickable(
225+
interactionSource = remember { MutableInteractionSource() },
226+
indication = null,
227+
) { onItemClick(centerIndex) }
228+
} else {
229+
Modifier
230+
},
231+
),
219232
contentAlignment = Alignment.Center,
220233
) {
221234
SGText(
@@ -279,11 +292,7 @@ private fun TempPickerButton(
279292
@DevicePreviews
280293
@Composable
281294
private fun FeedScrollTitlePicker_Preview() {
282-
val options = listOf(
283-
TitleOption(round = 1, subject = "주제"),
284-
TitleOption(round = 2, subject = "주제"),
285-
TitleOption(round = 3, subject = "주제"),
286-
)
295+
val options = List(15) { TitleOption(round = 1, subject = "주제") }
287296
FeedScrollTitlePickerComponent(
288297
selectedOption = options[0],
289298
options = options,
@@ -296,15 +305,10 @@ private fun FeedScrollTitlePicker_Preview() {
296305
@DevicePreviews
297306
@Composable
298307
private fun ScrollPicker_Preview() {
299-
val options = listOf(
300-
TitleOption(round = 1, subject = "주제"),
301-
TitleOption(round = 2, subject = "주제"),
302-
TitleOption(round = 3, subject = "주제"),
303-
)
308+
val options = List(15) { TitleOption(round = 1, subject = "주제") }
304309
ScrollPicker(
305310
selectedOption = options[0],
306311
options = options,
307-
visibleOptionCount = 5,
308312
onChangedOption = {},
309313
)
310314
}

presentation/feature/main-feed/src/main/kotlin/com/captures2024/soongan/presentation/feature/main/feed/component/feed/FeedTitlePickerBottomSheetComponent.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ internal fun FeedTitlePickerBottomSheetComponent(
3232
onDismissRequest = onDismissRequest,
3333
modifier = modifier,
3434
sheetState = sheetState,
35+
sheetGesturesEnabled = false,
3536
containerColor = Color.White,
37+
dragHandle = { null },
3638
) {
3739
FeedScrollTitlePickerComponent(
3840
selectedOption = currentSelectedOption,

presentation/feature/main-post/src/main/kotlin/com/captures2024/soongan/presentation/feature/main/post/component/info/input/PostInfoInputTitleComponent.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.ui.platform.LocalFocusManager
2020
import androidx.compose.ui.res.stringResource
2121
import androidx.compose.ui.text.font.FontWeight
2222
import androidx.compose.ui.text.input.ImeAction
23+
import androidx.compose.ui.text.style.TextAlign
2324
import androidx.compose.ui.unit.dp
2425
import androidx.compose.ui.unit.em
2526
import androidx.compose.ui.unit.sp
@@ -48,6 +49,7 @@ internal fun PostInfoInputTitleComponent(
4849
lineHeight = 22.sp,
4950
fontFamily = SGTypography.pretendard,
5051
letterSpacing = (-5).em,
52+
textAlign = TextAlign.Center,
5153
)
5254

5355
Column(horizontalAlignment = Alignment.End) {

0 commit comments

Comments
 (0)