1import SwiftUI23struct WallpaperItem: View {4 let wallpaper: Wallpaper5 let action: () -> Void6 @ObservedObject var favoritesManager = FavoritesManager.shared7 @State private var retryID = UUID()8 @State private var attempt = 09 @State private var isHovering = false1011 12 13 private let maxAttempts = 41415 var body: some View {16 Button(action: action) {17 AsyncImage(url: URL(string: wallpaper.thumbs.small)) { phase in18 switch phase {19 case .empty:20 Rectangle()21 .fill(Color.gray.opacity(0.2))22 .overlay(ProgressView())23 case .success(let image):24 image25 .resizable()26 .aspectRatio(contentMode: .fill)27 case .failure:28 Rectangle()29 .fill(Color.gray.opacity(0.2))30 .overlay(31 attempt < maxAttempts32 ? AnyView(ProgressView())33 : AnyView(Image(systemName: "photo")34 .foregroundColor(.gray.opacity(0.6)))35 )36 .task {37 guard attempt < maxAttempts else { return }38 39 let delay = UInt64(attempt + 1) * 800_000_00040 try? await Task.sleep(nanoseconds: delay)41 guard !Task.isCancelled else { return }42 attempt += 143 retryID = UUID()44 }45 @unknown default:46 EmptyView()47 }48 }49 .id(retryID)50 .frame(height: 100)51 .clipped()52 .cornerRadius(8)53 .overlay(54 RoundedRectangle(cornerRadius: 8)55 .stroke(isHovering ? Color.accentColor : Color.clear, lineWidth: 2)56 )57 .shadow(radius: isHovering ? 4 : 0)58 .overlay(59 60 Group {61 if isHovering || favoritesManager.isFavorite(wallpaper) {62 Button {63 favoritesManager.toggleFavorite(wallpaper)64 } label: {65 Image(systemName: favoritesManager.isFavorite(wallpaper) ? "heart.fill" : "heart")66 .foregroundColor(favoritesManager.isFavorite(wallpaper) ? .red : .white)67 .shadow(radius: 2)68 .font(.system(size: 16, weight: .bold))69 .padding(6)70 .background(Color.black.opacity(0.3))71 .clipShape(Circle())72 }73 .buttonStyle(.plain)74 .padding(6)75 .transition(.opacity)76 }77 },78 alignment: .topTrailing79 )80 .scaleEffect(isHovering ? 1.02 : 1.0)81 .animation(.spring(response: 0.3), value: isHovering)82 }83 .buttonStyle(.plain)84 .onHover { isHovering = $0 }85 .help("\(wallpaper.resolution)\n\(wallpaper.purity)")86 }87}