import UIKit class GIFCollectionViewCell: UICollectionViewCell { private let gifPlayerView: GIFPlayerView = { let player = GIFPlayerView() player.layer.cornerRadius = 8 player.clipsToBounds = true return player }() private let loadingIndicator: UIActivityIndicatorView = { let indicator = UIActivityIndicatorView(style: .medium) indicator.hidesWhenStopped = true return indicator }() private let placeholderLabel: UILabel = { let label = UILabel() label.text = "GIF" label.textAlignment = .center label.font = .systemFont(ofSize: 12, weight: .medium) label.textColor = .systemGray return label }() private var gifData: Data? override init(frame: CGRect) { super.init(frame: frame) setupUI() } required init?(coder: NSCoder) { super.init(coder: coder) setupUI() } override func prepareForReuse() { super.prepareForReuse() gifData = nil gifPlayerView.stopAnimating() placeholderLabel.isHidden = false loadingIndicator.stopAnimating() } private func setupUI() { contentView.addSubview(gifPlayerView) contentView.addSubview(loadingIndicator) contentView.addSubview(placeholderLabel) gifPlayerView.translatesAutoresizingMaskIntoConstraints = false loadingIndicator.translatesAutoresizingMaskIntoConstraints = false placeholderLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ gifPlayerView.topAnchor.constraint(equalTo: contentView.topAnchor), gifPlayerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), gifPlayerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), gifPlayerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), loadingIndicator.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), loadingIndicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), placeholderLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), placeholderLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), ]) contentView.layer.cornerRadius = 8 contentView.layer.borderWidth = 1 contentView.layer.borderColor = UIColor.systemGray4.cgColor } func configure(with gif: GIF) { // Reset UI gifPlayerView.stopAnimating() placeholderLabel.isHidden = false loadingIndicator.startAnimating() // Load the GIF data from local storage DispatchQueue.global(qos: .userInitiated).async { [weak self] in if let gifData = GIFStorageService.shared.getGIFData(for: gif) { DispatchQueue.main.async { guard let self = self else { return } self.loadingIndicator.stopAnimating() self.gifData = gifData self.gifPlayerView.loadGIF(from: gifData) self.gifPlayerView.startAnimating() self.placeholderLabel.isHidden = true } } else { DispatchQueue.main.async { guard let self = self else { return } self.loadingIndicator.stopAnimating() self.placeholderLabel.isHidden = false } } } } }