mirror of
https://github.com/yattee/yattee.git
synced 2025-11-22 14:41:19 +00:00
Thumbnails were being stretched vertically due to incorrect aspect ratio handling. Fixed by: - Using .scaledToFill() on thumbnails to fill the container width - Constraining container to 16:9 aspect ratio with .fit mode - Adding matching aspect ratio to placeholder to prevent layout shift during loading This ensures thumbnails maintain proper proportions while filling the full cell width.
84 lines
2.3 KiB
Swift
84 lines
2.3 KiB
Swift
import CachedAsyncImage
|
|
import SDWebImageSwiftUI
|
|
import SwiftUI
|
|
|
|
struct ThumbnailView: View {
|
|
var url: URL?
|
|
private let thumbnails = ThumbnailsModel.shared
|
|
private let thumbnailExtension: String?
|
|
|
|
init(url: URL?) {
|
|
self.url = url
|
|
thumbnailExtension = Self.extractExtension(from: url)
|
|
}
|
|
|
|
private static func extractExtension(from url: URL?) -> String? {
|
|
guard let url,
|
|
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil }
|
|
|
|
let pathComponents = urlComponents.path.components(separatedBy: ".")
|
|
guard pathComponents.count > 1 else { return nil }
|
|
|
|
return pathComponents.last
|
|
}
|
|
|
|
var body: some View {
|
|
if url != nil {
|
|
viewForThumbnailExtension
|
|
} else {
|
|
placeholder
|
|
}
|
|
}
|
|
|
|
@ViewBuilder var viewForThumbnailExtension: some View {
|
|
if AccountsModel.shared.app != .piped, thumbnailExtension != nil {
|
|
if thumbnailExtension == "webp" {
|
|
webImage
|
|
} else {
|
|
asyncImageIfAvailable
|
|
}
|
|
} else {
|
|
webImage
|
|
}
|
|
}
|
|
|
|
var webImage: some View {
|
|
WebImage(url: url)
|
|
.onFailure { _ in
|
|
if let url {
|
|
thumbnails.insertUnloadable(url)
|
|
}
|
|
}
|
|
.placeholder { placeholder }
|
|
.resizable()
|
|
}
|
|
|
|
@ViewBuilder var asyncImageIfAvailable: some View {
|
|
// swiftlint:disable:next deployment_target
|
|
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
CachedAsyncImage(url: url, urlCache: BaseCacheModel.imageCache) { phase in
|
|
switch phase {
|
|
case let .success(image):
|
|
image
|
|
.resizable()
|
|
case .failure:
|
|
placeholder.onAppear {
|
|
guard let url else { return }
|
|
thumbnails.insertUnloadable(url)
|
|
}
|
|
default:
|
|
placeholder
|
|
}
|
|
}
|
|
} else {
|
|
placeholder
|
|
}
|
|
}
|
|
|
|
var placeholder: some View {
|
|
Rectangle()
|
|
.fill(Color("PlaceholderColor"))
|
|
.aspectRatio(Constants.aspectRatio16x9, contentMode: .fit)
|
|
}
|
|
}
|