@@ -4,7 +4,10 @@ import androidx.compose.animation.core.Animatable
4
4
import androidx.compose.animation.core.animateDpAsState
5
5
import androidx.compose.animation.core.tween
6
6
import androidx.compose.foundation.background
7
- import androidx.compose.foundation.gestures.detectDragGestures
7
+ import androidx.compose.foundation.clickable
8
+ import androidx.compose.foundation.gestures.Orientation
9
+ import androidx.compose.foundation.gestures.draggable
10
+ import androidx.compose.foundation.gestures.rememberDraggableState
8
11
import androidx.compose.foundation.layout.Arrangement
9
12
import androidx.compose.foundation.layout.Box
10
13
import androidx.compose.foundation.layout.PaddingValues
@@ -26,7 +29,6 @@ import androidx.compose.material3.Card
26
29
import androidx.compose.material3.CardDefaults
27
30
import androidx.compose.material3.Icon
28
31
import androidx.compose.material3.Text
29
- import androidx.compose.material3.TextButton
30
32
import androidx.compose.runtime.Composable
31
33
import androidx.compose.runtime.getValue
32
34
import androidx.compose.runtime.mutableStateOf
@@ -37,9 +39,8 @@ import androidx.compose.ui.Alignment
37
39
import androidx.compose.ui.Modifier
38
40
import androidx.compose.ui.draw.clip
39
41
import androidx.compose.ui.graphics.Color
40
- import androidx.compose.ui.input.pointer.pointerInput
41
42
import androidx.compose.ui.platform.LocalDensity
42
- import androidx.compose.ui.res.painterResource
43
+ import androidx.compose.ui.text.style.TextAlign
43
44
import androidx.compose.ui.unit.Dp
44
45
import androidx.compose.ui.unit.IntOffset
45
46
import androidx.compose.ui.unit.dp
@@ -54,13 +55,22 @@ fun SwipeableCard(
54
55
modifier : Modifier = Modifier ,
55
56
task : Task ,
56
57
viewModel : TaskViewModel ,
58
+ onDelete : () -> Unit ,
59
+ onEdit : () -> Unit ,
57
60
content : @Composable () -> Unit
58
61
) {
62
+ val isExpanded = viewModel.expandedMap[task.uid] ? : false
59
63
var isShowing by remember { mutableStateOf(false ) }
60
64
val scope = rememberCoroutineScope()
61
65
val offsetX = remember { Animatable (0f ) }
62
66
val maxSwipe = with (LocalDensity .current) { 200 .dp.toPx() }
63
67
68
+ val cardHeight by animateDpAsState(
69
+ targetValue = if (isExpanded) 100 .dp else 50 .dp,
70
+ animationSpec = tween(300 ),
71
+ label = " cardHeight"
72
+ )
73
+
64
74
fun interpolateDp (offset : Float , maxSwipe : Float , start : Dp , end : Dp ): Dp {
65
75
val fraction = (- offset / maxSwipe).coerceIn(0f , 1f )
66
76
return end + (start - end) * fraction
@@ -85,11 +95,17 @@ fun SwipeableCard(
85
95
bottomEnd = 12 .dp
86
96
)
87
97
98
+ val draggableState = rememberDraggableState { delta ->
99
+ scope.launch {
100
+ offsetX.snapTo((offsetX.value + delta).coerceIn(- maxSwipe, 0f ))
101
+ }
102
+ }
103
+
88
104
Box (
89
105
modifier = modifier
90
106
.fillMaxWidth()
91
107
.padding(start = 12 .dp, top = 12 .dp, end = 12 .dp)
92
- .height(80 .dp )
108
+ .height(cardHeight )
93
109
.background(Color .Transparent )
94
110
) {
95
111
Row (
@@ -104,7 +120,7 @@ fun SwipeableCard(
104
120
) {
105
121
Button (
106
122
onClick = {
107
- viewModel.deleteTask(task )
123
+ onDelete( )
108
124
scope.launch {
109
125
offsetX.animateTo(0f , animationSpec = tween(300 ))
110
126
}
@@ -124,7 +140,7 @@ fun SwipeableCard(
124
140
}
125
141
Button (
126
142
onClick = {
127
- viewModel.setUpdateTaskId(task.uid )
143
+ onEdit( )
128
144
isShowing = true
129
145
},
130
146
shape = RoundedCornerShape (50 ),
@@ -158,35 +174,51 @@ fun SwipeableCard(
158
174
Card (
159
175
modifier = Modifier
160
176
.offset { IntOffset (offsetX.value.roundToInt(), 0 ) }
161
- .pointerInput(Unit ) {
162
- detectDragGestures(
163
- onDrag = { change, dragAmount ->
164
- change.consume()
165
- val newValue = offsetX.value + dragAmount.x
166
- scope.launch {
167
- offsetX.snapTo(newValue.coerceIn(- maxSwipe, 0f ))
168
- }
169
- },
170
- onDragEnd = {
171
- scope.launch {
172
- if (offsetX.value < - maxSwipe / 2 ) {
173
- offsetX.animateTo(- maxSwipe, animationSpec = tween(300 ))
174
- } else {
175
- offsetX.animateTo(0f , animationSpec = tween(300 ))
176
- }
177
- }
177
+ .clickable { viewModel.toggleExpanded(task.uid) }
178
+ .draggable(
179
+ state = draggableState,
180
+ orientation = Orientation .Horizontal ,
181
+ onDragStopped = { velocity ->
182
+ scope.launch {
183
+ val target = if (offsetX.value < - maxSwipe / 2 ) - maxSwipe else 0f
184
+ offsetX.animateTo(target, animationSpec = tween(300 ))
178
185
}
179
- )
180
- }
186
+ }
187
+ )
181
188
.fillMaxSize(),
182
189
elevation = CardDefaults .cardElevation(defaultElevation = 4 .dp),
183
190
shape = frontShape
184
191
) {
185
- Box (
186
- modifier = Modifier .fillMaxSize(),
187
- contentAlignment = Alignment .CenterStart
188
- ) {
189
- content()
192
+ Box (modifier = Modifier .fillMaxSize()) {
193
+ Card (
194
+ modifier = Modifier
195
+ .fillMaxHeight()
196
+ .width(50 .dp)
197
+ .align(Alignment .CenterStart ),
198
+ shape = RoundedCornerShape (topStart = 12 .dp, bottomStart = 12 .dp),
199
+ colors = CardDefaults .cardColors(containerColor = Color (task.cardColor)),
200
+ elevation = CardDefaults .cardElevation(defaultElevation = 0 .dp)
201
+ ) {
202
+ Box (
203
+ modifier = Modifier .fillMaxSize(),
204
+ contentAlignment = Alignment .Center
205
+ ) {
206
+ Text (
207
+ text = task.uid.toString(),
208
+ color = Color .White ,
209
+ textAlign = TextAlign .Center
210
+ )
211
+ }
212
+ }
213
+
214
+ Box (
215
+ modifier = Modifier
216
+ .fillMaxSize()
217
+ .padding(start = 48 .dp),
218
+ contentAlignment = Alignment .CenterStart
219
+ ) {
220
+ content()
221
+ }
190
222
}
191
223
}
192
224
}
0 commit comments