Skip to content

Commit 551589d

Browse files
authored
Merge pull request #46 from GokhanDurmaz/ui_dev
dev(ui): modify swipeable card ui.
2 parents eb27f16 + 52fb235 commit 551589d

File tree

4 files changed

+120
-65
lines changed

4 files changed

+120
-65
lines changed

app/src/main/java/com/flowintent/workspace/nav/NavTopBar.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ import androidx.compose.material3.TopAppBar
2727
import androidx.compose.material3.TopAppBarDefaults
2828
import androidx.compose.runtime.Composable
2929
import androidx.compose.runtime.getValue
30+
import androidx.compose.runtime.mutableIntStateOf
3031
import androidx.compose.runtime.mutableStateOf
3132
import androidx.compose.runtime.remember
3233
import androidx.compose.runtime.setValue
3334
import androidx.compose.ui.Modifier
35+
import androidx.compose.ui.graphics.Color
36+
import androidx.compose.ui.graphics.toArgb
3437
import androidx.compose.ui.unit.dp
3538
import androidx.compose.ui.window.Dialog
3639
import androidx.hilt.navigation.compose.hiltViewModel
@@ -121,6 +124,25 @@ fun OpenTaskDialog(
121124
val toDoLabel = remember { mutableStateOf("") }
122125
val toDoContent = remember { mutableStateOf("") }
123126
val updateTaskId by viewModel.updateTaskId.collectAsStateWithLifecycle()
127+
val colors = listOf(
128+
Color(0xFF2B17DA),
129+
Color(0xFFE91E63),
130+
Color(0xFF4CAF50),
131+
Color(0xFFFF9800),
132+
Color(0xFF009688)
133+
)
134+
135+
val shuffledColors = remember { colors.shuffled().toMutableList() }
136+
var colorIndex by remember { mutableIntStateOf(0) }
137+
138+
fun getNextColor(): Color {
139+
if (colorIndex >= shuffledColors.size) {
140+
shuffledColors.shuffle()
141+
colorIndex = 0
142+
}
143+
return shuffledColors[colorIndex++]
144+
}
145+
124146

125147
Dialog(onDismissRequest = onDismiss) {
126148
Card {
@@ -167,7 +189,7 @@ fun OpenTaskDialog(
167189
title = toDoLabel.value,
168190
content = TaskRes.TaskContent(toDoContent.value),
169191
taskType = TaskType.LOCAL_TASKS,
170-
cardColor = 0xFF6200EE.toInt(),
192+
cardColor = getNextColor().toArgb(),
171193
iconColor = 0xFFFFFFFF.toInt(),
172194
textColor = 0xFF000000.toInt()
173195
)

app/src/main/java/com/flowintent/workspace/ui/SwipeableCard.kt

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import androidx.compose.animation.core.Animatable
44
import androidx.compose.animation.core.animateDpAsState
55
import androidx.compose.animation.core.tween
66
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
811
import androidx.compose.foundation.layout.Arrangement
912
import androidx.compose.foundation.layout.Box
1013
import androidx.compose.foundation.layout.PaddingValues
@@ -26,7 +29,6 @@ import androidx.compose.material3.Card
2629
import androidx.compose.material3.CardDefaults
2730
import androidx.compose.material3.Icon
2831
import androidx.compose.material3.Text
29-
import androidx.compose.material3.TextButton
3032
import androidx.compose.runtime.Composable
3133
import androidx.compose.runtime.getValue
3234
import androidx.compose.runtime.mutableStateOf
@@ -37,9 +39,8 @@ import androidx.compose.ui.Alignment
3739
import androidx.compose.ui.Modifier
3840
import androidx.compose.ui.draw.clip
3941
import androidx.compose.ui.graphics.Color
40-
import androidx.compose.ui.input.pointer.pointerInput
4142
import androidx.compose.ui.platform.LocalDensity
42-
import androidx.compose.ui.res.painterResource
43+
import androidx.compose.ui.text.style.TextAlign
4344
import androidx.compose.ui.unit.Dp
4445
import androidx.compose.ui.unit.IntOffset
4546
import androidx.compose.ui.unit.dp
@@ -54,13 +55,22 @@ fun SwipeableCard(
5455
modifier: Modifier = Modifier,
5556
task: Task,
5657
viewModel: TaskViewModel,
58+
onDelete: () -> Unit,
59+
onEdit: () -> Unit,
5760
content: @Composable () -> Unit
5861
) {
62+
val isExpanded = viewModel.expandedMap[task.uid] ?: false
5963
var isShowing by remember { mutableStateOf(false) }
6064
val scope = rememberCoroutineScope()
6165
val offsetX = remember { Animatable(0f) }
6266
val maxSwipe = with(LocalDensity.current) { 200.dp.toPx() }
6367

68+
val cardHeight by animateDpAsState(
69+
targetValue = if (isExpanded) 100.dp else 50.dp,
70+
animationSpec = tween(300),
71+
label = "cardHeight"
72+
)
73+
6474
fun interpolateDp(offset: Float, maxSwipe: Float, start: Dp, end: Dp): Dp {
6575
val fraction = (-offset / maxSwipe).coerceIn(0f, 1f)
6676
return end + (start - end) * fraction
@@ -85,11 +95,17 @@ fun SwipeableCard(
8595
bottomEnd = 12.dp
8696
)
8797

98+
val draggableState = rememberDraggableState { delta ->
99+
scope.launch {
100+
offsetX.snapTo((offsetX.value + delta).coerceIn(-maxSwipe, 0f))
101+
}
102+
}
103+
88104
Box(
89105
modifier = modifier
90106
.fillMaxWidth()
91107
.padding(start = 12.dp, top = 12.dp, end = 12.dp)
92-
.height(80.dp)
108+
.height(cardHeight)
93109
.background(Color.Transparent)
94110
) {
95111
Row(
@@ -104,7 +120,7 @@ fun SwipeableCard(
104120
) {
105121
Button(
106122
onClick = {
107-
viewModel.deleteTask(task)
123+
onDelete()
108124
scope.launch {
109125
offsetX.animateTo(0f, animationSpec = tween(300))
110126
}
@@ -124,7 +140,7 @@ fun SwipeableCard(
124140
}
125141
Button(
126142
onClick = {
127-
viewModel.setUpdateTaskId(task.uid)
143+
onEdit()
128144
isShowing = true
129145
},
130146
shape = RoundedCornerShape(50),
@@ -158,35 +174,51 @@ fun SwipeableCard(
158174
Card(
159175
modifier = Modifier
160176
.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))
178185
}
179-
)
180-
}
186+
}
187+
)
181188
.fillMaxSize(),
182189
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
183190
shape = frontShape
184191
) {
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+
}
190222
}
191223
}
192224
}

app/src/main/java/com/flowintent/workspace/ui/TaskListScreen.kt

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import androidx.compose.ui.unit.dp
3030
import androidx.compose.ui.unit.sp
3131
import androidx.hilt.navigation.compose.hiltViewModel
3232
import androidx.lifecycle.compose.collectAsStateWithLifecycle
33-
import com.flowintent.core.db.Task
3433
import com.flowintent.workspace.nav.ToDoNavTopBar
3534
import com.flowintent.workspace.ui.vm.TaskViewModel
3635
import com.flowintent.workspace.util.asString
@@ -108,38 +107,32 @@ private fun ListCardContent(viewModel: TaskViewModel = hiltViewModel()) {
108107
horizontalAlignment = Alignment.CenterHorizontally
109108
) {
110109
items(taskList) { task ->
111-
ToDoListCard(task, viewModel)
112-
}
113-
}
114-
}
115-
116-
@Composable
117-
private fun ToDoListCard(
118-
task: Task,
119-
viewModel: TaskViewModel
120-
) {
121-
SwipeableCard(
122-
task = task,
123-
viewModel = viewModel
124-
) {
125-
Column(
126-
modifier = Modifier
127-
.fillMaxWidth()
128-
.padding(12.dp)
129-
) {
130-
Text(
131-
text = task.title,
132-
fontSize = 16.sp,
133-
fontFamily = FontFamily.SansSerif,
134-
fontWeight = FontWeight.Bold
135-
)
136-
Text(
137-
text = task.content.asString(),
138-
modifier = Modifier.padding(top = 12.dp),
139-
fontSize = 16.sp,
140-
fontFamily = FontFamily.SansSerif,
141-
fontWeight = FontWeight.Bold
142-
)
110+
SwipeableCard(
111+
task = task,
112+
onDelete = { viewModel.deleteTask(task) },
113+
onEdit = { viewModel.setUpdateTaskId(task.uid) },
114+
viewModel = viewModel
115+
) {
116+
Column(
117+
modifier = Modifier
118+
.fillMaxWidth()
119+
.padding(12.dp)
120+
) {
121+
Text(
122+
text = task.title,
123+
fontSize = 16.sp,
124+
fontFamily = FontFamily.SansSerif,
125+
fontWeight = FontWeight.Bold
126+
)
127+
Text(
128+
text = task.content.asString(),
129+
modifier = Modifier.padding(top = 12.dp),
130+
fontSize = 16.sp,
131+
fontFamily = FontFamily.SansSerif,
132+
fontWeight = FontWeight.Bold
133+
)
134+
}
135+
}
143136
}
144137
}
145138
}

app/src/main/java/com/flowintent/workspace/ui/vm/TaskViewModel.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.flowintent.workspace.ui.vm
22

3+
import androidx.compose.runtime.mutableStateMapOf
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
56
import com.flowintent.core.db.Task
@@ -32,6 +33,13 @@ class TaskViewModel @Inject constructor(
3233
private val _deleteResult = MutableStateFlow<Boolean?>(null)
3334
val deleteResult: StateFlow<Boolean?> = _deleteResult.asStateFlow()
3435

36+
private val _expandedMap = mutableStateMapOf<Int, Boolean>()
37+
val expandedMap: Map<Int, Boolean> get() = _expandedMap
38+
39+
fun toggleExpanded(id: Int) {
40+
_expandedMap[id] = !(_expandedMap[id] ?: false)
41+
}
42+
3543
fun insertTask(task: Task) {
3644
viewModelScope.launch {
3745
repository.insertTask(task)

0 commit comments

Comments
 (0)