From 8fb2a2a14e4aa2ffc696b30bc6252fe34d848e08 Mon Sep 17 00:00:00 2001 From: Ilyas Hallak Date: Thu, 4 Sep 2025 12:14:20 +0200 Subject: [PATCH] fix: Add circular progress for delete countdown --- readeck/UI/Bookmarks/BookmarkCardView.swift | 39 +++++++------------ readeck/UI/Bookmarks/BookmarksViewModel.swift | 9 +++-- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/readeck/UI/Bookmarks/BookmarkCardView.swift b/readeck/UI/Bookmarks/BookmarkCardView.swift index f5fe1f6..d0e118c 100644 --- a/readeck/UI/Bookmarks/BookmarkCardView.swift +++ b/readeck/UI/Bookmarks/BookmarkCardView.swift @@ -59,17 +59,26 @@ struct BookmarkCardView: View { .opacity(pendingDelete != nil ? 0.4 : 1.0) .animation(.easeInOut(duration: 0.2), value: pendingDelete != nil) - // Undo button overlay + // Undo toast overlay with progress background if let pendingDelete = pendingDelete { VStack(spacing: 0) { Spacer() - // Undo button area - only when user interacts + // Undo button area with circular progress HStack { - HStack(spacing: 6) { - Image(systemName: "trash") - .foregroundColor(.secondary) - .font(.caption2) + HStack(spacing: 8) { + // Circular progress indicator + ZStack { + Circle() + .stroke(Color.gray.opacity(0.3), lineWidth: 2) + .frame(width: 16, height: 16) + Circle() + .trim(from: 0, to: CGFloat(pendingDelete.progress)) + .stroke(Color.accentColor, style: StrokeStyle(lineWidth: 2, lineCap: .round)) + .rotationEffect(.degrees(-90)) + .frame(width: 16, height: 16) + .animation(.linear(duration: 0.1), value: pendingDelete.progress) + } Text("Deleting...") .font(.caption2) @@ -99,24 +108,6 @@ struct BookmarkCardView: View { .shadow(color: .black.opacity(0.1), radius: 2, x: 0, y: 1) .transition(.opacity.combined(with: .move(edge: .bottom))) } - - // Progress Bar am unteren Rand - if let pendingDelete = pendingDelete { - VStack(spacing: 0) { - Spacer() - - // Progress Bar - ProgressView(value: pendingDelete.progress, total: 1.0) - .progressViewStyle(LinearProgressViewStyle(tint: .red)) - .scaleEffect(x: 1, y: 1.5, anchor: .center) - .clipShape( - .rect( - bottomLeadingRadius: layout == .compact ? 8 : 12, - bottomTrailingRadius: layout == .compact ? 8 : 12 - ) - ) - } - } } .swipeActions(edge: .trailing, allowsFullSwipe: true) { if pendingDelete == nil { diff --git a/readeck/UI/Bookmarks/BookmarksViewModel.swift b/readeck/UI/Bookmarks/BookmarksViewModel.swift index 8e9a4ca..7836fc6 100644 --- a/readeck/UI/Bookmarks/BookmarksViewModel.swift +++ b/readeck/UI/Bookmarks/BookmarksViewModel.swift @@ -234,7 +234,7 @@ class BookmarksViewModel { private func startDeleteCountdown(for bookmarkId: String) { let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] timer in - Task { @MainActor in + DispatchQueue.main.async { guard let self = self, let pendingDelete = self.pendingDeletes[bookmarkId] else { timer.invalidate() @@ -243,6 +243,9 @@ class BookmarksViewModel { pendingDelete.progress += 1.0 / 30.0 // 3 seconds / 0.1 interval = 30 steps + // Trigger UI update by modifying the dictionary + self.pendingDeletes[bookmarkId] = pendingDelete + if pendingDelete.progress >= 1.0 { timer.invalidate() } @@ -273,10 +276,10 @@ class BookmarksViewModel { } } -class PendingDelete: Identifiable, ObservableObject { +class PendingDelete: Identifiable { let id = UUID() let bookmark: Bookmark - @Published var progress: Double = 0.0 + var progress: Double = 0.0 var timer: Timer? var deleteTask: Task?