fix: swipe vs tap — use highPriorityGesture + hidden NavigationLink
- DragGesture with minimumDistance:15 as highPriorityGesture - Tap only navigates when not swiping - Tapping while swiped closes the delete button - Hidden NavigationLink for programmatic navigation - Reverted FitnessTabView back to page-style TabView Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,16 +31,18 @@ struct FitnessTabView: View {
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 8)
|
||||
|
||||
// Content — no page swipe (conflicts with swipe-to-delete)
|
||||
Group {
|
||||
switch selectedSubTab {
|
||||
case 0: TodayView()
|
||||
case 1: TemplatesView()
|
||||
case 2: GoalsView()
|
||||
case 3: FoodLibraryView()
|
||||
default: TodayView()
|
||||
}
|
||||
// Content
|
||||
TabView(selection: $selectedSubTab) {
|
||||
TodayView()
|
||||
.tag(0)
|
||||
TemplatesView()
|
||||
.tag(1)
|
||||
GoalsView()
|
||||
.tag(2)
|
||||
FoodLibraryView()
|
||||
.tag(3)
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
}
|
||||
.background(Color.canvas)
|
||||
.navigationBarHidden(true)
|
||||
|
||||
@@ -68,16 +68,16 @@ struct MealSectionView: View {
|
||||
|
||||
if isExpanded {
|
||||
ForEach(entries) { entry in
|
||||
SwipeToDeleteRow(onDelete: { onDelete(entry) }) {
|
||||
NavigationLink(destination: EntryDetailView(entry: entry, onDelete: {
|
||||
onDelete(entry)
|
||||
})) {
|
||||
SwipeToDeleteRow(
|
||||
onDelete: { onDelete(entry) },
|
||||
onTap: { /* handled by NavigationLink */ },
|
||||
destination: { EntryDetailView(entry: entry, onDelete: { onDelete(entry) }) }
|
||||
) {
|
||||
entryRow(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(Color.surfaceCard)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
.shadow(color: .black.opacity(0.04), radius: 6, y: 2)
|
||||
@@ -118,40 +118,62 @@ struct MealSectionView: View {
|
||||
|
||||
// MARK: - Swipe to Delete Row
|
||||
|
||||
struct SwipeToDeleteRow<Content: View>: View {
|
||||
struct SwipeToDeleteRow<Content: View, Destination: View>: View {
|
||||
let onDelete: () -> Void
|
||||
let onTap: () -> Void
|
||||
let destination: () -> Destination
|
||||
@ViewBuilder let content: () -> Content
|
||||
|
||||
@State private var offset: CGFloat = 0
|
||||
@State private var showDelete = false
|
||||
@State private var isSwiping = false
|
||||
@State private var showDetail = false
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .trailing) {
|
||||
// Delete background
|
||||
// Delete button background
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
onDelete()
|
||||
offset = 0
|
||||
isSwiping = false
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "trash.fill")
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 70, height: .infinity)
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
.frame(width: 70)
|
||||
}
|
||||
.background(Color.red)
|
||||
}
|
||||
|
||||
// Content
|
||||
// Content row
|
||||
content()
|
||||
.offset(x: offset)
|
||||
.gesture(
|
||||
DragGesture()
|
||||
.background(
|
||||
NavigationLink(destination: destination(), isActive: $showDetail) {
|
||||
EmptyView()
|
||||
}
|
||||
.opacity(0)
|
||||
)
|
||||
.onTapGesture {
|
||||
if !isSwiping {
|
||||
showDetail = true
|
||||
} else {
|
||||
// Close swipe
|
||||
withAnimation(.easeOut(duration: 0.2)) {
|
||||
offset = 0
|
||||
isSwiping = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.highPriorityGesture(
|
||||
DragGesture(minimumDistance: 15)
|
||||
.onChanged { value in
|
||||
if value.translation.width < 0 {
|
||||
offset = max(value.translation.width, -80)
|
||||
} else if showDelete {
|
||||
} else if isSwiping {
|
||||
offset = min(value.translation.width - 70, 0)
|
||||
}
|
||||
}
|
||||
@@ -159,10 +181,10 @@ struct SwipeToDeleteRow<Content: View>: View {
|
||||
withAnimation(.easeOut(duration: 0.2)) {
|
||||
if value.translation.width < -40 {
|
||||
offset = -70
|
||||
showDelete = true
|
||||
isSwiping = true
|
||||
} else {
|
||||
offset = 0
|
||||
showDelete = false
|
||||
isSwiping = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user