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 isHovering = false9 10 var body: some View {11 Button(action: action) {12 AsyncImage(url: URL(string: wallpaper.thumbs.small)) { phase in13 switch phase {14 case .empty:15 Rectangle()16 .fill(Color.gray.opacity(0.2))17 .overlay(ProgressView())18 case .success(let image):19 image20 .resizable()21 .aspectRatio(contentMode: .fill)22 case .failure:23 Button {24 retryID = UUID()25 } label: {26 Rectangle()27 .fill(Color.red.opacity(0.1))28 .overlay(29 VStack {30 Image(systemName: "exclamationmark.triangle")31 Text("Retry")32 .font(.caption)33 }34 )35 }36 .buttonStyle(.plain)37 @unknown default:38 EmptyView()39 }40 }41 .id(retryID)42 .frame(height: 100)43 .clipped()44 .cornerRadius(8)45 .overlay(46 RoundedRectangle(cornerRadius: 8)47 .stroke(isHovering ? Color.accentColor : Color.clear, lineWidth: 2)48 )49 .shadow(radius: isHovering ? 4 : 0)50 .overlay(51 52 Group {53 if isHovering || favoritesManager.isFavorite(wallpaper) {54 Button {55 favoritesManager.toggleFavorite(wallpaper)56 } label: {57 Image(systemName: favoritesManager.isFavorite(wallpaper) ? "heart.fill" : "heart")58 .foregroundColor(favoritesManager.isFavorite(wallpaper) ? .red : .white)59 .shadow(radius: 2)60 .font(.system(size: 16, weight: .bold))61 .padding(6)62 .background(Color.black.opacity(0.3))63 .clipShape(Circle())64 }65 .buttonStyle(.plain)66 .padding(6)67 .transition(.opacity)68 }69 },70 alignment: .topTrailing71 )72 .scaleEffect(isHovering ? 1.02 : 1.0)73 .animation(.spring(response: 0.3), value: isHovering)74 }75 .buttonStyle(.plain)76 .onHover { isHovering = $0 }77 .help("\(wallpaper.resolution)\n\(wallpaper.purity)")78 }79}