listless

A simple list app for Apple platforms
Log | Files | Refs | README | LICENSE

commit 1c747f5cf8e2a14218deb788e9087c8267a85ac3
parent cfeed7a5f1aa2c64e5b8382009d5ab76eb3c9f6f
Author: Michael Camilleri <[email protected]>
Date:   Wed,  1 Apr 2026 19:09:59 +0900

Try alternative fix for animation bug

The previous commit's fix didn't work. This approach takes advantage of
the `completion` argument to the `.withAnimation` modifier to reset the
status of a view so that if it is recycled by SwiftUI, it's back in its
reset state.

Co-Authored-By: Claude 4.6 Opus <[email protected]>

Diffstat:
MListlessiOS/Extensions/ItemListView+Undo.swift | 1-
MListlessiOS/Helpers/ItemRowSwipeGesture.swift | 5++++-
MListlessiOS/Views/ItemListView.swift | 1-
MListlessiOS/Views/ItemRowView.swift | 12------------
4 files changed, 4 insertions(+), 15 deletions(-)

diff --git a/ListlessiOS/Extensions/ItemListView+Undo.swift b/ListlessiOS/Extensions/ItemListView+Undo.swift @@ -68,7 +68,6 @@ extension ItemListView { } catch { presentStoreError(error) } - iState.undoGeneration &+= 1 dismissUndoToast() } diff --git a/ListlessiOS/Helpers/ItemRowSwipeGesture.swift b/ListlessiOS/Helpers/ItemRowSwipeGesture.swift @@ -149,10 +149,13 @@ struct ItemRowSwipeGesture: ViewModifier { // ForEach re-evaluation animate it out of the active section. triggerAction(action: onComplete) } else { - // Delete: slide off screen + // Delete: slide off screen, then reset so undo doesn't + // restore the row with a frozen swipe state. triggerAction(action: onDelete) withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) { swipeOffset = -400 + } completion: { + resetSwipeState() } } } else { diff --git a/ListlessiOS/Views/ItemListView.swift b/ListlessiOS/Views/ItemListView.swift @@ -23,7 +23,6 @@ struct ItemListView: View, ItemListViewProtocol { var draftPlacement: DraftItemPlacement? var draftTitle: String = "" var fetchWorkaround: Int = 0 - var undoGeneration: Int = 0 var isShowingOverlay: Bool { isShowingSettings || isShowingSyncDiagnostics || isShowingRenameAlert diff --git a/ListlessiOS/Views/ItemRowView.swift b/ListlessiOS/Views/ItemRowView.swift @@ -15,7 +15,6 @@ struct ItemRowView: View { let isLastActiveItem: Bool let onStartEdit: (UUID) -> Void let onEndEdit: (UUID, _ shouldCreateNewItem: Bool) -> Void - let undoGeneration: Int @FocusState.Binding var focusedField: FocusField? @AppStorage("colorTheme") private var colorThemeRaw = 0 @@ -37,7 +36,6 @@ struct ItemRowView: View { isDragging: Binding<Bool> = .constant(false), isSwiping: Binding<Bool> = .constant(false), isLastActiveItem: Bool = false, - undoGeneration: Int = 0, focusedField: FocusState<FocusField?>.Binding, onToggle: @escaping (UUID) -> Void, onTitleChange: @escaping (UUID, String) -> Void, @@ -54,7 +52,6 @@ struct ItemRowView: View { _isDragging = isDragging _isSwiping = isSwiping self.isLastActiveItem = isLastActiveItem - self.undoGeneration = undoGeneration self.onToggle = onToggle self.onTitleChange = onTitleChange self.onDelete = onDelete @@ -176,15 +173,6 @@ struct ItemRowView: View { .onChange(of: colorThemeRaw) { _, _ in cachedAccentColor = computeAccentColor() } - .onChange(of: undoGeneration) { _, _ in - var transaction = Transaction(animation: nil) - transaction.disablesAnimations = true - withTransaction(transaction) { - swipeOffset = 0 - swipeDirection = .none - isSwipeTriggered = false - } - } .itemSwipeGesture( isDragging: $isDragging, isEditing: focusedField == .item(itemID),