mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Merge pull request #740 from stonerl/thumbnails
Improved thumbnail handling
This commit is contained in:
commit
61d589a9b5
@ -20,21 +20,23 @@ final class ThumbnailsModel: ObservableObject {
|
|||||||
return unloadable.contains(url)
|
return unloadable.contains(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
func best(_ video: Video) -> URL? {
|
func best(_ video: Video) -> (url: URL?, quality: Thumbnail.Quality?) {
|
||||||
for quality in availableQualitites {
|
for quality in availableQualitites {
|
||||||
let url = video.thumbnailURL(quality: quality)
|
let url = video.thumbnailURL(quality: quality)
|
||||||
if !isUnloadable(url) {
|
if !isUnloadable(url) {
|
||||||
return url
|
return (url, quality)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var availableQualitites: [Thumbnail.Quality] {
|
private var availableQualitites: [Thumbnail.Quality] {
|
||||||
switch Defaults[.thumbnailsQuality] {
|
switch Defaults[.thumbnailsQuality] {
|
||||||
case .highest:
|
case .highest:
|
||||||
return [.maxresdefault, .medium, .default]
|
return [.maxres, .high, .medium, .default]
|
||||||
|
case .high:
|
||||||
|
return [.high, .medium, .default]
|
||||||
case .medium:
|
case .medium:
|
||||||
return [.medium, .default]
|
return [.medium, .default]
|
||||||
case .low:
|
case .low:
|
||||||
|
@ -4,6 +4,8 @@ import SwiftUI
|
|||||||
|
|
||||||
enum Constants {
|
enum Constants {
|
||||||
static let overlayAnimation = Animation.linear(duration: 0.2)
|
static let overlayAnimation = Animation.linear(duration: 0.2)
|
||||||
|
static let aspectRatio16x9 = 16.0 / 9.0
|
||||||
|
static let aspectRatio4x3 = 4.0 / 3.0
|
||||||
|
|
||||||
static var isAppleTV: Bool {
|
static var isAppleTV: Bool {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
|
@ -462,12 +462,14 @@ enum ButtonLabelStyle: String, CaseIterable, Defaults.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ThumbnailsQuality: String, CaseIterable, Defaults.Serializable {
|
enum ThumbnailsQuality: String, CaseIterable, Defaults.Serializable {
|
||||||
case highest, medium, low
|
case highest, high, medium, low
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .highest:
|
case .highest:
|
||||||
return "Highest quality".localized()
|
return "Best quality".localized()
|
||||||
|
case .high:
|
||||||
|
return "High quality".localized()
|
||||||
case .medium:
|
case .medium:
|
||||||
return "Medium quality".localized()
|
return "Medium quality".localized()
|
||||||
case .low:
|
case .low:
|
||||||
|
@ -265,7 +265,7 @@ struct PlayerControls: View {
|
|||||||
|
|
||||||
var controlsBackgroundURL: URL? {
|
var controlsBackgroundURL: URL? {
|
||||||
if let video = player.videoForDisplay,
|
if let video = player.videoForDisplay,
|
||||||
let url = thumbnails.best(video)
|
let url = thumbnails.best(video).url
|
||||||
{
|
{
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ import SwiftUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var thumbnailHeight: Double {
|
static var thumbnailHeight: Double {
|
||||||
thumbnailWidth / (16 / 9)
|
thumbnailWidth / Constants.aspectRatio16x9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ import SwiftUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var thumbnailHeight: Double {
|
static var thumbnailHeight: Double {
|
||||||
thumbnailWidth / 1.7777
|
thumbnailWidth / Constants.aspectRatio16x9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,7 @@ struct VideoPlayerView: View {
|
|||||||
static let hiddenOffset = 0.0
|
static let hiddenOffset = 0.0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static let defaultAspectRatio = 16 / 9.0
|
static let defaultAspectRatio = Constants.aspectRatio16x9
|
||||||
static var defaultMinimumHeightLeft: Double {
|
static var defaultMinimumHeightLeft: Double {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
335
|
335
|
||||||
|
@ -219,22 +219,18 @@ struct VideoBanner: View {
|
|||||||
return watch!.finished ? 0.5 : 1
|
return watch!.finished ? 0.5 : 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private var thumbnailWidth: Double {
|
|
||||||
#if os(tvOS)
|
|
||||||
356
|
|
||||||
#else
|
|
||||||
120
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private var thumbnailHeight: Double {
|
private var thumbnailHeight: Double {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
200
|
200
|
||||||
#else
|
#else
|
||||||
72
|
75
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var thumbnailWidth: Double {
|
||||||
|
thumbnailHeight * Constants.aspectRatio16x9
|
||||||
|
}
|
||||||
|
|
||||||
private var videoDurationLabel: String? {
|
private var videoDurationLabel: String? {
|
||||||
guard videoDuration != 0 else { return nil }
|
guard videoDuration != 0 else { return nil }
|
||||||
return (videoDuration ?? video?.length)?.formattedAsPlaybackTime()
|
return (videoDuration ?? video?.length)?.formattedAsPlaybackTime()
|
||||||
|
@ -440,7 +440,7 @@ struct VideoCell: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.mask(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
.mask(RoundedRectangle(cornerRadius: thumbnailRoundingCornerRadius))
|
||||||
.modifier(AspectRatioModifier())
|
.aspectRatio(Constants.aspectRatio16x9, contentMode: .fill)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var time: String? {
|
private var time: String? {
|
||||||
@ -471,24 +471,6 @@ struct VideoCell: View {
|
|||||||
.lineLimit(lineLimit)
|
.lineLimit(lineLimit)
|
||||||
.truncationMode(.middle)
|
.truncationMode(.middle)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AspectRatioModifier: ViewModifier {
|
|
||||||
@Environment(\.horizontalCells) private var horizontalCells
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
Group {
|
|
||||||
if horizontalCells {
|
|
||||||
content
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
.aspectRatio(
|
|
||||||
VideoPlayerView.defaultAspectRatio,
|
|
||||||
contentMode: .fill
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VideoCellThumbnail: View {
|
struct VideoCellThumbnail: View {
|
||||||
@ -496,7 +478,15 @@ struct VideoCellThumbnail: View {
|
|||||||
@ObservedObject private var thumbnails = ThumbnailsModel.shared
|
@ObservedObject private var thumbnails = ThumbnailsModel.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ThumbnailView(url: thumbnails.best(video))
|
GeometryReader { geometry in
|
||||||
|
let (url, quality) = thumbnails.best(video)
|
||||||
|
let aspectRatio = (quality == .default || quality == .high) ? Constants.aspectRatio4x3 : Constants.aspectRatio16x9
|
||||||
|
|
||||||
|
ThumbnailView(url: url)
|
||||||
|
.aspectRatio(aspectRatio, contentMode: .fill)
|
||||||
|
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||||
|
.clipped()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user