11package com.threegap.bitnagil.presentation.emotion.component.template
22
33import androidx.compose.animation.AnimatedVisibility
4+ import androidx.compose.animation.EnterTransition
5+ import androidx.compose.animation.ExitTransition
46import androidx.compose.animation.core.Animatable
57import androidx.compose.animation.core.tween
68import androidx.compose.animation.fadeIn
@@ -67,14 +69,35 @@ import com.threegap.bitnagil.presentation.emotion.model.mvi.EmotionState
6769import kotlinx.coroutines.delay
6870import kotlinx.coroutines.launch
6971import kotlin.math.absoluteValue
70- import kotlin.math.max
7172
7273@Composable
7374fun SwipeEmotionSelectionScreen (
7475 state : EmotionState ,
7576 onClickPreviousButton : () -> Unit ,
7677 onSelectEmotion : (String ) -> Unit ,
7778) {
79+ val fadeInTransition = remember { fadeIn(animationSpec = tween(150 )) }
80+ val fadeOutTransition = remember { fadeOut(animationSpec = tween(50 )) }
81+
82+ val emotions = remember(state.emotionTypeUiModels) { state.emotionTypeUiModels + EmotionUiModel .Default }
83+ val actualItemCount = emotions.size
84+
85+ val pagerState = rememberPagerState(
86+ initialPage = Int .MAX_VALUE / 2 - (Int .MAX_VALUE / 2 % actualItemCount),
87+ pageCount = { Int .MAX_VALUE },
88+ )
89+ var showText by remember { mutableStateOf(true ) }
90+ val currentItem = emotions[pagerState.currentPage % actualItemCount]
91+
92+ LaunchedEffect (pagerState.isScrollInProgress) {
93+ if (pagerState.isScrollInProgress) {
94+ showText = false
95+ } else {
96+ delay(250 )
97+ showText = true
98+ }
99+ }
100+
78101 Column (
79102 modifier = Modifier
80103 .fillMaxSize()
@@ -99,47 +122,21 @@ fun SwipeEmotionSelectionScreen(
99122 ) {
100123 state.emotionTypeUiModels.forEach { emotion ->
101124 EmotionMarbleImage (
102- modifier = Modifier
103- .size(40 .dp)
104- .background(color = BitnagilTheme .colors.coolGray98),
125+ modifier = Modifier .size(40 .dp),
105126 image = emotion.image,
127+ alpha = if (emotion.emotionType == currentItem.emotionType) 1f else 0.3f
106128 )
107129 }
108130 }
109131
110132 Spacer (modifier = Modifier .height(26 .dp))
111133
112- Column (
113- horizontalAlignment = Alignment .CenterHorizontally ,
114- ) {
115- Box (
116- modifier = Modifier
117- .background(Color (0xFFEFECFF ), shape = RoundedCornerShape (12 .dp))
118- .padding(20 .dp),
119- contentAlignment = Alignment .Center ,
120- ) {
121- Text (
122- " 평온함은 마음이 고요하고 편안해\n 균형을 이루는 상태에요" ,
123- style = BitnagilTheme .typography.cafe24SsurroundAir2.copy(color = Color (0xFF692BD0 )),
124- textAlign = TextAlign .Center ,
125- )
126- }
127-
128- Canvas (
129- modifier = Modifier
130- .height(10 .dp)
131- .width(24 .dp),
132- ) {
133- val path = Path ().apply {
134- moveTo(0f , 0f )
135- lineTo(size.width, 0f )
136- lineTo(size.width / 2 , size.height)
137- lineTo(0f , 0f )
138- close()
139- }
140- drawPath(path, color = Color (0xFFEFECFF ))
141- }
142- }
134+ EmotionDescriptionText (
135+ emotion = currentItem,
136+ showText = showText,
137+ enterTransition = fadeInTransition,
138+ exitTransition = fadeOutTransition
139+ )
143140
144141 Spacer (modifier = Modifier .height(16 .dp))
145142
@@ -149,18 +146,23 @@ fun SwipeEmotionSelectionScreen(
149146 EmotionPager (
150147 modifier = Modifier
151148 .fillMaxSize()
149+ .padding(bottom = 90 .dp)
152150 .zIndex(1f ),
153- emotions = state.emotionTypeUiModels ,
151+ emotions = emotions ,
154152 enabled = ! state.isLoading,
155153 onSelectEmotion = onSelectEmotion,
154+ pagerState = pagerState,
155+ showText = showText,
156+ marbleNameTextEnterTransition = fadeInTransition,
157+ marbleNameTextExitTransition = fadeOutTransition,
156158 )
157159
158160 Column (
159161 modifier = Modifier .align(Alignment .BottomCenter ),
160162 horizontalAlignment = Alignment .CenterHorizontally ,
161163 ) {
162164 GestureDescriptionText (
163- currentEmotionSelectable = state.emotionTypeUiModels.any { it. selectable } ,
165+ currentEmotionSelectable = currentItem. selectable,
164166 )
165167
166168 Spacer (modifier = Modifier .height(12 .dp))
@@ -187,6 +189,58 @@ fun SwipeEmotionSelectionScreen(
187189 }
188190}
189191
192+ @Composable
193+ private fun EmotionDescriptionText (
194+ emotion : EmotionUiModel ,
195+ showText : Boolean ,
196+ enterTransition : EnterTransition ,
197+ exitTransition : ExitTransition ,
198+ ) {
199+ Box (
200+ modifier = Modifier .height(102 .dp)
201+ ) {
202+ AnimatedVisibility (
203+ visible = emotion.message != null && showText,
204+ enter = enterTransition,
205+ exit = exitTransition,
206+ ) {
207+ Column (
208+ horizontalAlignment = Alignment .CenterHorizontally ,
209+ ) {
210+ Box (
211+ modifier = Modifier
212+ .background(Color (emotion.symbolBackgroundColor), shape = RoundedCornerShape (12 .dp))
213+ .padding(20 .dp),
214+ contentAlignment = Alignment .Center ,
215+ ) {
216+ Text (
217+ text = emotion.message ? : " " ,
218+ style = BitnagilTheme .typography.cafe24SsurroundAir2.copy(color = Color (emotion.symbolColor)),
219+ textAlign = TextAlign .Center ,
220+ maxLines = 2 ,
221+ minLines = 2 ,
222+ )
223+ }
224+
225+ Canvas (
226+ modifier = Modifier
227+ .height(10 .dp)
228+ .width(24 .dp),
229+ ) {
230+ val path = Path ().apply {
231+ moveTo(0f , 0f )
232+ lineTo(size.width, 0f )
233+ lineTo(size.width / 2 , size.height)
234+ lineTo(0f , 0f )
235+ close()
236+ }
237+ drawPath(path, color = Color (emotion.symbolBackgroundColor))
238+ }
239+ }
240+ }
241+ }
242+ }
243+
190244@Composable
191245private fun GestureDescriptionText (
192246 currentEmotionSelectable : Boolean ,
@@ -237,25 +291,12 @@ private fun EmotionPager(
237291 emotions : List <EmotionUiModel >,
238292 enabled : Boolean ,
239293 onSelectEmotion : (String ) -> Unit ,
294+ pagerState : PagerState ,
295+ showText : Boolean ,
296+ marbleNameTextEnterTransition : EnterTransition ,
297+ marbleNameTextExitTransition : ExitTransition ,
240298) {
241- val actualItemCount = max(1 , emotions.size)
242-
243- val pagerState = rememberPagerState(
244- initialPage = Int .MAX_VALUE / 2 - (Int .MAX_VALUE / 2 % actualItemCount),
245- pageCount = { Int .MAX_VALUE },
246- )
247-
248- var showText by remember { mutableStateOf(true ) }
249- val currentItem = emotions[pagerState.currentPage % actualItemCount]
250-
251- LaunchedEffect (pagerState.isScrollInProgress) {
252- if (pagerState.isScrollInProgress) {
253- showText = false
254- } else {
255- delay(500 )
256- showText = true
257- }
258- }
299+ val currentItem = emotions[pagerState.currentPage % emotions.size]
259300
260301 BoxWithConstraints (
261302 modifier = modifier,
@@ -264,9 +305,10 @@ private fun EmotionPager(
264305 val density = LocalDensity .current
265306 val screenWidth = with (density) { constraints.maxWidth.toDp() }
266307
267- val itemWidth = 140 .dp
268- val contentPadding = (screenWidth - itemWidth) / 2
269- val pageSpacing = ((screenWidth - itemWidth * 2 ) / 2 )
308+ val itemSize = 140 .dp
309+ val centerItemYOffset = 50 .dp
310+ val contentPadding = (screenWidth - itemSize) / 2
311+ val pageSpacing = ((screenWidth - itemSize * 2 ) / 2 )
270312
271313 HorizontalPager (
272314 modifier = Modifier .fillMaxHeight(),
@@ -275,32 +317,33 @@ private fun EmotionPager(
275317 contentPadding = PaddingValues (horizontal = contentPadding),
276318 verticalAlignment = Alignment .Top ,
277319 ) { page ->
278- val itemIndex = page % actualItemCount
320+ val itemIndex = page % emotions.size
279321 EmotionPagerItem (
280322 emotion = emotions[itemIndex],
281323 pagerState = pagerState,
282324 page = page,
283- size = itemWidth,
284- maximumDraggableYOffset = constraints.maxHeight - 280 .dp.dpToPx(),
285- enabled = enabled,
325+ size = itemSize,
326+ centerItemYOffset = centerItemYOffset.dpToPx(),
327+ maximumDraggableYOffset = constraints.maxHeight - (itemSize + centerItemYOffset).dpToPx(),
328+ enabled = enabled && emotions[itemIndex].selectable,
286329 onSelectEmotion = onSelectEmotion,
287330 )
288331 }
289332
290333 AnimatedVisibility (
291334 visible = showText,
292- enter = fadeIn(animationSpec = tween( 150 )) ,
293- exit = fadeOut(animationSpec = tween( 50 )) ,
335+ enter = marbleNameTextEnterTransition ,
336+ exit = marbleNameTextExitTransition ,
294337 ) {
295338 Box (
296339 modifier = Modifier
297- .background(Color (0x99E1D5FA ), shape = RoundedCornerShape (10 .dp))
340+ .background(Color (currentItem.symbolBackgroundColor ), shape = RoundedCornerShape (10 .dp))
298341 .padding(horizontal = 16 .dp, vertical = 8 .dp),
299342 ) {
300343 Text (
301344 text = currentItem.emotionMarbleName,
302345 style = BitnagilTheme .typography.title3SemiBold,
303- color = Color (0xFF692BD0 ),
346+ color = Color (currentItem.symbolColor ),
304347 )
305348 }
306349 }
@@ -313,6 +356,7 @@ private fun EmotionPagerItem(
313356 pagerState : PagerState ,
314357 page : Int ,
315358 size : Dp ,
359+ centerItemYOffset : Float ,
316360 maximumDraggableYOffset : Float = Float .MAX_VALUE ,
317361 enabled : Boolean ,
318362 onSelectEmotion : (String ) -> Unit ,
@@ -330,7 +374,7 @@ private fun EmotionPagerItem(
330374 .size(size)
331375 .aspectRatio(1f )
332376 .graphicsLayer {
333- translationY = lerp(size.value * 1f , 0f , pageOffset)
377+ translationY = lerp(start = centerItemYOffset * 1f , stop = 0f , pageOffset)
334378 }
335379 .offset {
336380 IntOffset (0 , offsetY.value.toInt())
@@ -361,8 +405,7 @@ private fun EmotionPagerItem(
361405 )
362406 }
363407 },
364- )
365- .background(color = BitnagilTheme .colors.coolGray98),
408+ ),
366409 )
367410}
368411
@@ -380,6 +423,8 @@ private fun Preview() {
380423 url = " https://bitnagil-s3.s3.ap-northeast-2.amazonaws.com/home_satisfaction.png" ,
381424 offlineBackupImageResourceId = null ,
382425 ),
426+ symbolBackgroundColor = 0xFFEFECFF ,
427+ symbolColor = 0xFF692BD0 ,
383428 ),
384429 EmotionUiModel (
385430 emotionType = " emotionType" ,
@@ -388,8 +433,9 @@ private fun Preview() {
388433 url = " https://bitnagil-s3.s3.ap-northeast-2.amazonaws.com/home_satisfaction.png" ,
389434 offlineBackupImageResourceId = null ,
390435 ),
436+ symbolBackgroundColor = 0xFFE9FAD0 ,
437+ symbolColor = 0xFF609F00 ,
391438 ),
392- EmotionUiModel .Default
393439 ),
394440 isLoading = false ,
395441 step = EmotionScreenStep .Emotion ,
0 commit comments