Skip to content

Commit a16087d

Browse files
committed
Added swipe to delete order
1 parent ddca1fe commit a16087d

3 files changed

Lines changed: 117 additions & 34 deletions

File tree

app/src/main/java/com/kaeru/app/ui/screens/HistoryScreen.kt

Lines changed: 113 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.foundation.shape.CircleShape
99
import androidx.compose.foundation.shape.RoundedCornerShape
1010
import androidx.compose.material.icons.Icons
1111
import androidx.compose.material.icons.filled.CheckCircle
12+
import androidx.compose.material.icons.filled.Delete
1213
import androidx.compose.material.icons.outlined.LocalShipping
1314
import androidx.compose.material3.*
1415
import androidx.compose.runtime.*
@@ -32,6 +33,11 @@ import com.kaeru.app.tracking.utils.DateUtils
3233
import com.kaeru.app.ui.components.TransitCalendarDialog
3334
import kotlin.math.abs
3435
import androidx.compose.runtime.saveable.rememberSaveable
36+
import androidx.compose.ui.draw.alpha
37+
import androidx.compose.ui.draw.scale
38+
import androidx.compose.ui.graphics.Color
39+
import com.kaeru.app.ui.components.AnimatedFilterChip
40+
import kotlinx.coroutines.launch
3541

3642
@Composable
3743
fun HistoryScreen(
@@ -59,6 +65,9 @@ fun HistoryScreen(
5965
TrackingFilter.ALL -> history
6066
}
6167
}
68+
val coroutineScope = rememberCoroutineScope()
69+
val snackbarHostState = remember { SnackbarHostState() }
70+
val isSwipeEnabled by viewModel.isSwipeToDeleteEnabled.collectAsState()
6271

6372
Scaffold(
6473
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
@@ -130,45 +139,83 @@ fun HistoryScreen(
130139
icon = Icons.Default.CheckCircle
131140
)
132141

133-
FilterChip(
134-
selected = currentFilter == TrackingFilter.ALL,
135-
onClick = { currentFilter = TrackingFilter.ALL },
136-
label = { Text("Todos") },
137-
leadingIcon = if (currentFilter == TrackingFilter.ALL) {
138-
{ Icon(painterResource(R.drawable.ic_package_outlined), null, modifier = Modifier.size(16.dp)) }
139-
} else null,
140-
shape = CircleShape
141-
)
142+
AnimatedFilterChip(
143+
selected = currentFilter == TrackingFilter.ALL,
144+
onClick = { currentFilter = TrackingFilter.ALL },
145+
label = stringResource(R.string.all_label),
146+
icon = Icons.Default.CheckCircle
147+
)
148+
}
142149
}
143150
}
144-
}
145-
146-
if (history.isEmpty()) {
147-
item {
148-
Box(
149-
modifier = Modifier
150-
.fillMaxWidth()
151-
.height(300.dp),
152-
contentAlignment = Alignment.Center
153-
) {
154-
val emptyText = when(currentFilter) {
155-
TrackingFilter.IN_TRANSIT -> "Nenhuma encomenda em trânsito"
156-
TrackingFilter.DELIVERED -> "Nenhuma encomenda entregue"
157-
TrackingFilter.ALL -> stringResource(R.string.no_packages_saved)
151+
if (history.isEmpty()) {
152+
item {
153+
Box(
154+
modifier = Modifier
155+
.fillMaxWidth()
156+
.height(300.dp),
157+
contentAlignment = Alignment.Center
158+
) {
159+
val emptyText = when (currentFilter) {
160+
TrackingFilter.IN_TRANSIT -> stringResource(R.string.no_packages_saved)
161+
TrackingFilter.DELIVERED -> stringResource(R.string.no_packages_saved)
162+
TrackingFilter.ALL -> stringResource(R.string.no_packages_saved)
163+
}
164+
Text(
165+
text = emptyText,
166+
color = MaterialTheme.colorScheme.onSurfaceVariant
167+
)
158168
}
159-
Text(
160-
text = emptyText,
161-
color = MaterialTheme.colorScheme.onSurfaceVariant
162-
)
163169
}
164-
}
165-
} else {
166-
items(filteredHistory, key = { it.code }) { item ->
167-
Box(modifier = Modifier.animateItem()) {
168-
HistoryCardNew(
169-
item = item,
170-
onClick = { onNavigateToResult(item.code) }
170+
} else {
171+
items(filteredHistory, key = { it.code }) { item ->
172+
173+
var hasFiredDelete by remember { mutableStateOf(false) }
174+
val deletedOrder = stringResource(R.string.deleted_order)
175+
val undoAction = stringResource(R.string.undo_action)
176+
177+
val dismissState = rememberSwipeToDismissBoxState(
178+
positionalThreshold = { totalDistance -> totalDistance * 0.5f },
179+
confirmValueChange = { dismissValue ->
180+
181+
if (dismissValue == SwipeToDismissBoxValue.EndToStart) {
182+
183+
if (!hasFiredDelete) {
184+
hasFiredDelete = true
185+
186+
viewModel.deleteTracking(item.code)
187+
188+
coroutineScope.launch {
189+
val result = snackbarHostState.showSnackbar(
190+
message = deletedOrder,
191+
actionLabel = undoAction,
192+
duration = SnackbarDuration.Short
193+
)
194+
195+
if (result == SnackbarResult.ActionPerformed) {
196+
viewModel.restoreTracking(item)
197+
}
198+
}
199+
}
200+
false
201+
} else {
202+
false
203+
}
204+
}
171205
)
206+
207+
SwipeToDismissBox(
208+
state = dismissState,
209+
enableDismissFromEndToStart = isSwipeEnabled,
210+
enableDismissFromStartToEnd = false,
211+
backgroundContent = { SwipeToDeleteIcon(dismissState) },
212+
modifier = Modifier.animateItem()
213+
) {
214+
HistoryCardNew(
215+
item = item,
216+
onClick = { onNavigateToResult(item.code) }
217+
)
218+
}
172219
}
173220
}
174221
}
@@ -337,4 +384,36 @@ fun HistoryCardNew(
337384

338385
enum class TrackingFilter {
339386
IN_TRANSIT, DELIVERED, ALL
387+
}
388+
389+
@OptIn(ExperimentalMaterial3Api::class)
390+
@Composable
391+
fun SwipeToDeleteIcon(state: SwipeToDismissBoxState) {
392+
val isDragging = state.dismissDirection == SwipeToDismissBoxValue.EndToStart
393+
val dragAmount = if (!isDragging) 0f else {
394+
if (state.targetValue == SwipeToDismissBoxValue.Settled) {
395+
state.progress * 0.5f
396+
} else {
397+
0.5f + (1f - state.progress) * 0.5f
398+
}
399+
}
400+
val iconAlpha = dragAmount.coerceIn(0f, 1f)
401+
val iconScale = (0.5f + (dragAmount * 0.7f)).coerceIn(0.5f, 1.2f)
402+
403+
Box(
404+
modifier = Modifier
405+
.fillMaxSize()
406+
.padding(horizontal = 24.dp),
407+
contentAlignment = Alignment.CenterEnd
408+
) {
409+
Icon(
410+
imageVector = Icons.Default.Delete,
411+
contentDescription = null,
412+
tint = MaterialTheme.colorScheme.error,
413+
modifier = Modifier
414+
.size(28.dp)
415+
.scale(iconScale)
416+
.alpha(iconAlpha)
417+
)
418+
}
340419
}

app/src/main/res/values-pt-rBR/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,6 @@
9696
<string name="theme_description">Customize o tema do seu aplicativo</string>
9797
<string name="themes_and_appearance">Temas e Aparência</string>
9898
<string name="appearance">Aparência</string>
99+
<string name="deleted_order">Encomenda apagada</string>
100+
<string name="undo_action">Desfazer</string>
99101
</resources>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,6 @@
9797
<string name="theme_description">Customize your app theme</string>
9898
<string name="themes_and_appearance">Themes and appearance</string>
9999
<string name="appearance">Appearance</string>
100+
<string name="deleted_order">Order deleted</string>
101+
<string name="undo_action">Undo</string>
100102
</resources>

0 commit comments

Comments
 (0)