Files
yattee/Yattee/Views/Channel/ChannelPlaylistRow.swift

123 lines
3.8 KiB
Swift

//
// ChannelPlaylistRow.swift
// Yattee
//
// Row view for displaying a playlist in channel playlists tab.
//
import SwiftUI
import NukeUI
struct ChannelPlaylistRow: View {
let playlist: Playlist
var style: VideoRowStyle = .regular
// Size configuration based on style (unified with VideoRowStyle)
private var thumbnailWidth: CGFloat {
style.thumbnailWidth
}
private var thumbnailHeight: CGFloat {
style.thumbnailHeight
}
private var titleFont: Font {
switch style {
case .large: return .body
case .regular: return .subheadline
case .compact: return .caption
}
}
private var titleLineLimit: Int {
switch style {
case .large: return 3
case .regular: return 2
case .compact: return 1
}
}
private var cornerRadius: CGFloat {
style == .compact ? 4 : 8
}
var body: some View {
NavigationLink(value: NavigationDestination.playlist(.remote(playlist.id, instance: nil, title: playlist.title))) {
HStack(spacing: 12) {
// Thumbnail
LazyImage(url: playlist.thumbnailURL) { state in
if let image = state.image {
image
.resizable()
.aspectRatio(contentMode: .fill)
} else {
thumbnailPlaceholder
}
}
.frame(width: thumbnailWidth, height: thumbnailHeight)
.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
.overlay(alignment: .bottomTrailing) {
if style != .compact {
videoCountBadge
}
}
// Info
VStack(alignment: .leading, spacing: style == .compact ? 2 : 4) {
Text(playlist.title)
.font(titleFont)
.fontWeight(.medium)
.lineLimit(titleLineLimit)
if style != .compact && !playlist.authorName.isEmpty {
Text(playlist.authorName)
.font(.caption)
.foregroundStyle(.secondary)
}
if style == .compact {
Text("playlist.videoCount \(playlist.videoCount)")
.font(.caption2)
.foregroundStyle(.secondary)
} else {
Text("playlist.videoCount \(playlist.videoCount)")
.font(.caption)
.foregroundStyle(.tertiary)
}
}
Spacer()
}
.contentShape(Rectangle())
}
.zoomTransitionSource(id: playlist.id)
.buttonStyle(.plain)
}
private var thumbnailPlaceholder: some View {
RoundedRectangle(cornerRadius: cornerRadius)
.fill(.quaternary)
.overlay {
Image(systemName: "list.bullet.rectangle.fill")
.font(style == .compact ? .caption : .title2)
.foregroundStyle(.secondary)
}
}
private var videoCountBadge: some View {
HStack(spacing: 2) {
Image(systemName: "play.rectangle.fill")
.font(.caption2)
Text("\(playlist.videoCount)")
.font(.caption2)
.fontWeight(.medium)
}
.padding(.horizontal, 6)
.padding(.vertical, 3)
.background(.black.opacity(0.75))
.foregroundStyle(.white)
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding(6)
}
}