// // MediaPreviewItem.swift // suixinkan // import UIKit /// 媒体预览资源项,描述可全屏预览的图片或视频。 public struct MediaPreviewItem: Hashable { /// 媒体类型。 public enum MediaType: Equatable { case image case video } /// 预览资源来源。 public enum Source { case remoteImage(URL) case localImageFile(URL) case image(UIImage) case remoteVideo(URL) case localVideoFile(URL) } /// 资源唯一标识,用于 Diffable Data Source。 public let id: UUID /// 预览资源来源。 public let source: Source /// 创建媒体预览资源项。 public init(id: UUID = UUID(), source: Source) { self.id = id self.source = source } /// 媒体类型。 public var mediaType: MediaType { switch source { case .remoteImage, .localImageFile, .image: return .image case .remoteVideo, .localVideoFile: return .video } } /// 是否为图片资源。 public var isImage: Bool { mediaType == .image } /// 是否为视频资源。 public var isVideo: Bool { mediaType == .video } /// 通过远程图片地址创建资源项,空字符串或非法地址返回 nil。 public static func remoteImage(_ urlString: String) -> MediaPreviewItem? { makeRemoteURL(from: urlString).map { MediaPreviewItem(source: .remoteImage($0)) } } /// 通过远程视频地址创建资源项,空字符串或非法地址返回 nil。 public static func remoteVideo(_ urlString: String) -> MediaPreviewItem? { makeRemoteURL(from: urlString).map { MediaPreviewItem(source: .remoteVideo($0)) } } /// 通过本地图片文件地址创建资源项。 public static func localImage(url: URL) -> MediaPreviewItem { MediaPreviewItem(source: .localImageFile(url)) } /// 通过本地图片对象创建资源项。 public static func image(_ image: UIImage) -> MediaPreviewItem { MediaPreviewItem(source: .image(image)) } /// 通过本地视频文件地址创建资源项。 public static func localVideo(url: URL) -> MediaPreviewItem { MediaPreviewItem(source: .localVideoFile(url)) } /// 将起始索引限制在可用范围内。 public static func clampedStartIndex(_ startIndex: Int, itemCount: Int) -> Int { guard itemCount > 0 else { return 0 } return min(max(0, startIndex), itemCount - 1) } /// 从媒体数组中读取安全的起始资源项。 public static func currentItem(in items: [MediaPreviewItem], startIndex: Int) -> MediaPreviewItem? { guard !items.isEmpty else { return nil } return items[clampedStartIndex(startIndex, itemCount: items.count)] } public static func == (lhs: MediaPreviewItem, rhs: MediaPreviewItem) -> Bool { lhs.id == rhs.id } public func hash(into hasher: inout Hasher) { hasher.combine(id) } private static func makeRemoteURL(from text: String) -> URL? { let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty, let url = URL(string: trimmed) else { return nil } guard let scheme = url.scheme?.lowercased(), ["http", "https"].contains(scheme) else { return nil } return url } }