feat: swipe left to delete food entries + tap for detail
- Custom SwipeToDeleteRow with drag gesture - Swipe left reveals red trash button - Tap still opens EntryDetailView with delete option - Both paths call the same onDelete callback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -68,16 +68,11 @@ struct MealSectionView: View {
|
|||||||
|
|
||||||
if isExpanded {
|
if isExpanded {
|
||||||
ForEach(entries) { entry in
|
ForEach(entries) { entry in
|
||||||
NavigationLink(destination: EntryDetailView(entry: entry, onDelete: {
|
SwipeToDeleteRow(onDelete: { onDelete(entry) }) {
|
||||||
onDelete(entry)
|
NavigationLink(destination: EntryDetailView(entry: entry, onDelete: {
|
||||||
})) {
|
|
||||||
entryRow(entry)
|
|
||||||
}
|
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
|
||||||
Button(role: .destructive) {
|
|
||||||
onDelete(entry)
|
onDelete(entry)
|
||||||
} label: {
|
})) {
|
||||||
Label("Delete", systemImage: "trash")
|
entryRow(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,3 +115,59 @@ struct MealSectionView: View {
|
|||||||
.background(Color.surfaceCard)
|
.background(Color.surfaceCard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Swipe to Delete Row
|
||||||
|
|
||||||
|
struct SwipeToDeleteRow<Content: View>: View {
|
||||||
|
let onDelete: () -> Void
|
||||||
|
@ViewBuilder let content: () -> Content
|
||||||
|
@State private var offset: CGFloat = 0
|
||||||
|
@State private var showDelete = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack(alignment: .trailing) {
|
||||||
|
// Delete background
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Button {
|
||||||
|
withAnimation(.easeInOut(duration: 0.2)) {
|
||||||
|
onDelete()
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "trash.fill")
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.frame(width: 70, height: .infinity)
|
||||||
|
}
|
||||||
|
.frame(width: 70)
|
||||||
|
.background(Color.red)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content
|
||||||
|
content()
|
||||||
|
.offset(x: offset)
|
||||||
|
.gesture(
|
||||||
|
DragGesture()
|
||||||
|
.onChanged { value in
|
||||||
|
if value.translation.width < 0 {
|
||||||
|
offset = max(value.translation.width, -80)
|
||||||
|
} else if showDelete {
|
||||||
|
offset = min(value.translation.width - 70, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onEnded { value in
|
||||||
|
withAnimation(.easeOut(duration: 0.2)) {
|
||||||
|
if value.translation.width < -40 {
|
||||||
|
offset = -70
|
||||||
|
showDelete = true
|
||||||
|
} else {
|
||||||
|
offset = 0
|
||||||
|
showDelete = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.clipShape(Rectangle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user