commit 04939b02c703e7f8d94e4e6ed30951020088d1fe
parent b9c2b35dc7f8aabe4d7bd6c0f02005fe7248f72a
Author: Michael Camilleri <[email protected]>
Date: Wed, 18 Feb 2026 19:05:38 +0900
Add polish to pull-to-clear animations
Co-Authored-By: Codex GPT 5.3 <[email protected]>
Diffstat:
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/ListlessiOS/Helpers/TaskRowMetrics.swift b/ListlessiOS/Helpers/TaskRowMetrics.swift
@@ -7,5 +7,5 @@ enum TaskRowMetrics {
static let contentVerticalPadding: CGFloat = 14
static let contentHorizontalPadding: CGFloat = 16
static let activeLeadingPadding: CGFloat = 24
- static let completedLeadingPadding: CGFloat = 16
+ static let completedLeadingPadding: CGFloat = 24
}
diff --git a/ListlessiOS/Views/PullToClear.swift b/ListlessiOS/Views/PullToClear.swift
@@ -8,17 +8,33 @@ struct PullToClearIndicator: View {
private var progress: CGFloat { min(1, pullOffset / pullClearThreshold) }
private var isReady: Bool { pullOffset >= pullClearThreshold }
+ private let textSlideDistance: CGFloat = 22
var body: some View {
HStack(spacing: 6) {
- Image(systemName: isReady ? "checkmark" : "trash")
- .foregroundStyle(.secondary)
- .fontWeight(.semibold)
- .animation(.easeInOut(duration: 0.15), value: isReady)
- Text(isReady ? "Release to clear" : "Clear completed")
- .foregroundStyle(.secondary)
- .font(.body)
- .animation(.easeInOut(duration: 0.15), value: isReady)
+ ZStack {
+ Image(systemName: "checkmark")
+ .offset(y: isReady ? 0 : -textSlideDistance)
+ Image(systemName: "tray")
+ .offset(y: isReady ? textSlideDistance : 0)
+ }
+ .frame(width: 26, height: textSlideDistance, alignment: .leading)
+ .clipped()
+ .foregroundStyle(.secondary)
+ .font(.system(size: 17))
+ .fontWeight(.semibold)
+ .animation(.easeInOut(duration: 0.15), value: isReady)
+ ZStack(alignment: .leading) {
+ Text("Release to clear")
+ .offset(y: isReady ? 0 : -textSlideDistance)
+ Text("Clear completed")
+ .offset(y: isReady ? textSlideDistance : 0)
+ }
+ .foregroundStyle(.secondary)
+ .font(.body)
+ .frame(height: textSlideDistance, alignment: .topLeading)
+ .clipped()
+ .animation(.easeInOut(duration: 0.15), value: isReady)
}
.frame(maxWidth: .infinity)
.frame(height: 56)