jellyflood/Swiftfin/Views/PagingLibraryView/Components/LibraryRow.swift

137 lines
4.4 KiB
Swift

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import JellyfinAPI
import SwiftUI
extension PagingLibraryView {
struct LibraryRow: View {
@State
private var contentWidth: CGFloat = 0
private let item: Element
private var onSelect: () -> Void
private let posterType: PosterType
private func imageView(from element: Element) -> ImageView {
switch posterType {
case .portrait:
ImageView(element.portraitPosterImageSource(maxWidth: 60))
case .landscape:
ImageView(element.landscapePosterImageSources(maxWidth: 110, single: false))
}
}
@ViewBuilder
private func itemAccessoryView(item: BaseItemDto) -> some View {
DotHStack {
if item.type == .episode, let seasonEpisodeLocator = item.seasonEpisodeLabel {
Text(seasonEpisodeLocator)
} else if let premiereYear = item.premiereDateYear {
Text(premiereYear)
}
if let runtime = item.runTimeLabel {
Text(runtime)
}
if let officialRating = item.officialRating {
Text(officialRating)
}
}
}
@ViewBuilder
private func personAccessoryView(person: BaseItemPerson) -> some View {
if let subtitle = person.subtitle {
Text(subtitle)
}
}
@ViewBuilder
private var accessoryView: some View {
switch item {
case let element as BaseItemDto:
itemAccessoryView(item: element)
case let element as BaseItemPerson:
personAccessoryView(person: element)
default:
AssertionFailureView("Used an unexpected type within a `PagingLibaryView`?")
}
}
// MARK: body
var body: some View {
ZStack(alignment: .bottomTrailing) {
Button {
onSelect()
} label: {
HStack(alignment: .center, spacing: EdgeInsets.defaultEdgePadding) {
ZStack {
Color.clear
imageView(from: item)
.failure {
SystemImageContentView(systemName: item.typeSystemImage)
}
}
.posterStyle(posterType)
.frame(width: posterType == .landscape ? 110 : 60)
.posterShadow()
.padding(.vertical, 8)
HStack {
VStack(alignment: .leading, spacing: 5) {
Text(item.displayTitle)
.font(posterType == .landscape ? .subheadline : .callout)
.fontWeight(.regular)
.foregroundColor(.primary)
.lineLimit(2)
.multilineTextAlignment(.leading)
accessoryView
.font(.caption)
.foregroundColor(Color(UIColor.lightGray))
}
Spacer()
}
.frame(maxWidth: .infinity)
.onSizeChanged { newSize in
contentWidth = newSize.width
}
}
}
Color.secondarySystemFill
.frame(width: contentWidth, height: 1)
}
.edgePadding(.horizontal)
}
}
}
extension PagingLibraryView.LibraryRow {
init(item: Element, posterType: PosterType) {
self.init(
item: item,
onSelect: {},
posterType: posterType
)
}
func onSelect(_ action: @escaping () -> Void) -> Self {
copy(modifying: \.onSelect, with: action)
}
}