11package com.cornellappdev.uplift.ui.components.profile.achievements
22
33import androidx.compose.animation.core.Animatable
4+ import androidx.compose.animation.core.AnimationVector1D
45import androidx.compose.animation.core.LinearOutSlowInEasing
56import androidx.compose.animation.core.animateDpAsState
67import androidx.compose.animation.core.animateFloatAsState
@@ -37,6 +38,7 @@ import androidx.compose.ui.geometry.Offset
3738import androidx.compose.ui.graphics.Brush
3839import androidx.compose.ui.graphics.Color
3940import androidx.compose.ui.graphics.graphicsLayer
41+ import androidx.compose.ui.input.pointer.PointerInputScope
4042import androidx.compose.ui.input.pointer.pointerInput
4143import androidx.compose.ui.input.pointer.positionChange
4244import androidx.compose.ui.input.pointer.util.VelocityTracker
@@ -62,6 +64,7 @@ import com.cornellappdev.uplift.util.YELLOW03
6264import com.cornellappdev.uplift.util.YELLOW04
6365import com.cornellappdev.uplift.util.YELLOW05
6466import com.cornellappdev.uplift.util.montserratFamily
67+ import kotlinx.coroutines.CoroutineScope
6568import kotlinx.coroutines.coroutineScope
6669import kotlinx.coroutines.launch
6770import java.lang.Float.min
@@ -80,33 +83,23 @@ data class PRCardData(
8083
8184@Composable
8285fun PRCards (
83- prCardDataList : List <PRCardData >,
84- onMoveToBack : (PRCardData ) -> Unit
86+ prCardDataList : List <PRCardData >, onMoveToBack : (PRCardData ) -> Unit
8587) {
8688 Box (
87- Modifier
88- .fillMaxWidth(),
89- contentAlignment = Alignment .CenterStart
89+ Modifier .fillMaxWidth(), contentAlignment = Alignment .CenterStart
9090 ) {
9191 prCardDataList.forEachIndexed { idx, prCardData ->
9292 key(prCardData) {
9393 PRCard (
9494 order = idx,
9595 totalCount = prCardDataList.size,
96- title = prCardData.title,
97- weight = prCardData.weight,
98- reps = prCardData.reps,
99- backgroundGradient = prCardData.backgroundGradient,
100- innerBorderGradient = prCardData.innerBorderGradient,
101- titleColor = prCardData.titleColor,
102- weightAndRepsColor = prCardData.weightAndRepsColor,
96+ prCardData = prCardData,
10397 onMoveToBack = {
10498 onMoveToBack(prCardData)
10599 },
106- onUpdate = {
100+ onUpdatePressed = {
107101 /* TODO: Fill in with update function */
108- }
109- )
102+ })
110103 }
111104 }
112105 }
@@ -116,15 +109,9 @@ fun PRCards(
116109fun PRCard (
117110 order : Int ,
118111 totalCount : Int ,
119- title : String ,
120- weight : Int ,
121- reps : Int ,
122- backgroundGradient : Brush ,
123- innerBorderGradient : Brush ,
124- titleColor : Color ,
125- weightAndRepsColor : Color ,
112+ prCardData : PRCardData ,
126113 onMoveToBack : () -> Unit ,
127- onUpdate : () -> Unit
114+ onUpdatePressed : () -> Unit
128115) {
129116 val animatedScale by animateFloatAsState(
130117 targetValue = 1f - (totalCount - order) * 0.05f ,
@@ -140,14 +127,14 @@ fun PRCard(
140127 scaleX = animatedScale
141128 scaleY = animatedScale
142129 }
143- .swipeToRight { onMoveToBack() }
130+ .onSwipeToRight { onMoveToBack() }
144131 .height(311 .dp)
145132 .width(229 .dp)
146133 .shadow(
147134 elevation = 6 .dp,
148135 shape = RoundedCornerShape (22 .dp),
149136 )
150- .background(backgroundGradient, RoundedCornerShape (22 .dp))
137+ .background(prCardData. backgroundGradient, RoundedCornerShape (22 .dp))
151138 .padding(6 .dp)
152139
153140 ) {
@@ -157,24 +144,23 @@ fun PRCard(
157144 .height(298 .dp)
158145 .border(
159146 width = 1.4 .dp,
160- brush = innerBorderGradient,
147+ brush = prCardData. innerBorderGradient,
161148 shape = RoundedCornerShape (16.5 .dp)
162149 )
163150 .padding(vertical = 39 .dp)
164151 ) {
165- PRCardContent (title, titleColor, weight, reps, weightAndRepsColor, onUpdate)
152+ PRCardContent (
153+ prCardData,
154+ onUpdatePressed
155+ )
166156 }
167157 }
168158}
169159
170160@Composable
171161private fun PRCardContent (
172- title : String ,
173- titleColor : Color ,
174- weight : Int ,
175- reps : Int ,
176- weightAndRepsColor : Color ,
177- onUpdate : () -> Unit
162+ prCardData : PRCardData ,
163+ onUpdatePressed : () -> Unit
178164) {
179165 Column (
180166 modifier = Modifier
@@ -189,30 +175,30 @@ private fun PRCardContent(
189175 )
190176 Spacer (modifier = Modifier .height(11 .dp))
191177 Text (
192- text = title,
193- color = titleColor,
178+ text = prCardData. title,
179+ color = prCardData. titleColor,
194180 fontFamily = montserratFamily,
195181 fontSize = 22 .sp,
196182 fontWeight = FontWeight .Bold ,
197183 )
198184 Spacer (modifier = Modifier .height(16 .dp))
199185 Text (
200- text = " $weight lb / $reps reps" ,
201- color = weightAndRepsColor,
186+ text = " ${prCardData. weight} lb / ${prCardData. reps} reps" ,
187+ color = prCardData. weightAndRepsColor,
202188 fontFamily = montserratFamily,
203189 fontSize = 16 .sp,
204190 fontWeight = FontWeight .Medium ,
205191 )
206192 Spacer (modifier = Modifier .weight(1f ))
207193 UpdateButton (
208- onUpdate = onUpdate
194+ onUpdatePressed = onUpdatePressed
209195 )
210196 }
211197}
212198
213199@Composable
214200private fun UpdateButton (
215- onUpdate : () -> Unit
201+ onUpdatePressed : () -> Unit
216202) {
217203 val yellowBorderGradient = Brush .linearGradient(
218204 colors = listOf (LIGHT_YELLOW , PRIMARY_YELLOW )
@@ -223,16 +209,13 @@ private fun UpdateButton(
223209 .width(82 .dp)
224210 .height(32 .dp)
225211 .background(
226- color = PRIMARY_BLACK ,
227- shape = RoundedCornerShape (30 .dp)
212+ color = PRIMARY_BLACK , shape = RoundedCornerShape (30 .dp)
228213 )
229214 .border(
230- width = 1.4 .dp,
231- brush = yellowBorderGradient,
232- shape = RoundedCornerShape (30 .dp)
215+ width = 1.4 .dp, brush = yellowBorderGradient, shape = RoundedCornerShape (30 .dp)
233216 )
234217 .clickable(
235- onClick = onUpdate ,
218+ onClick = onUpdatePressed ,
236219 )
237220 ) {
238221 Text (
@@ -245,7 +228,7 @@ private fun UpdateButton(
245228 }
246229}
247230
248- private fun Modifier.swipeToRight (
231+ private fun Modifier.onSwipeToRight (
249232 onMoveToBack : () -> Unit
250233): Modifier = composed {
251234 val offsetX = remember { Animatable (0f ) }
@@ -274,35 +257,54 @@ private fun Modifier.swipeToRight(
274257 if (targetOffsetX.absoluteValue <= size.width) {
275258 launch { offsetX.animateTo(targetValue = 0f , initialVelocity = velocity) }
276259 } else {
277- val boomerangDuration = 600
278- val maxDistanceToFling =
279- (size.width * 4 ).toFloat()
280- val distanceToFling = min(
281- targetOffsetX.absoluteValue + size.width, maxDistanceToFling
260+ onAnimateBoomerang(
261+ this @pointerInput,
262+ targetOffsetX,
263+ this @coroutineScope,
264+ offsetX,
265+ velocity,
266+ clearedHurdle,
267+ setClearedHurdle = { clearedHurdle = it },
268+ onMoveToBack
282269 )
283-
284- launch {
285- offsetX.animateTo(
286- targetValue = 0f ,
287- initialVelocity = velocity,
288- animationSpec = keyframes {
289- durationMillis = boomerangDuration
290- distanceToFling at (boomerangDuration / 2 ) using LinearOutSlowInEasing
291- 40f at boomerangDuration - 70
292- }
293- ) {
294- if (value >= size.width * 2 && ! clearedHurdle) {
295- onMoveToBack()
296- clearedHurdle = true
297- }
298- }
299- clearedHurdle = false
300- }
301270 }
302271 }
303272 }
273+ }.offset { IntOffset (offsetX.value.roundToInt(), 0 ) }
274+ }
275+
276+ private fun onAnimateBoomerang (
277+ pointerInputScope : PointerInputScope ,
278+ targetOffsetX : Float ,
279+ coroutineScope : CoroutineScope ,
280+ offsetX : Animatable <Float , AnimationVector1D >,
281+ velocity : Float ,
282+ clearedHurdle : Boolean ,
283+ setClearedHurdle : (Boolean ) -> Unit ,
284+ onMoveToBack : () -> Unit
285+ ) {
286+ val boomerangDuration = 600
287+ val maxDistanceToFling = (pointerInputScope.size.width * 4 ).toFloat()
288+ val distanceToFling = min(
289+ targetOffsetX.absoluteValue + pointerInputScope.size.width, maxDistanceToFling
290+ )
291+ val boomerangAnimationOffset = 70
292+ coroutineScope.launch {
293+ offsetX.animateTo(
294+ targetValue = 0f ,
295+ initialVelocity = velocity,
296+ animationSpec = keyframes {
297+ durationMillis = boomerangDuration
298+ distanceToFling at (boomerangDuration / 2 ) using LinearOutSlowInEasing
299+ 40f at boomerangDuration - boomerangAnimationOffset
300+ }) {
301+ if (value >= pointerInputScope.size.width * 2 && ! clearedHurdle) {
302+ onMoveToBack()
303+ setClearedHurdle(true )
304+ }
305+ }
306+ setClearedHurdle(false )
304307 }
305- .offset { IntOffset (offsetX.value.roundToInt(), 0 ) }
306308}
307309
308310@Preview
@@ -357,11 +359,9 @@ private fun PRCardsPreview() {
357359 )
358360 }
359361 PRCards (
360- prCardDataList = prCardDataList,
361- onMoveToBack = { prCardData ->
362+ prCardDataList = prCardDataList, onMoveToBack = { prCardData ->
362363 prCardDataList = listOf (prCardData) + (prCardDataList - prCardData)
363- }
364- )
364+ })
365365}
366366
367367
0 commit comments