Add list views for channels, playlists and placeholders

This commit is contained in:
Arkadiusz Fal
2022-12-13 11:40:08 +01:00
parent d38a507be5
commit 1cd2dbe5f7
11 changed files with 332 additions and 43 deletions

View File

@@ -45,14 +45,6 @@ struct ChannelCell: View {
var labelContent: some View {
VStack {
HStack(alignment: .top, spacing: 3) {
Image(systemName: "person.crop.rectangle")
Text("Channel".localized().uppercased())
.fontWeight(.light)
.opacity(0.6)
}
.foregroundColor(.secondary)
WebImage(url: channel.thumbnailURL, options: [.lowPriority])
.resizable()
.placeholder {

View File

@@ -0,0 +1,97 @@
import SwiftUI
struct ChannelListItem: View {
var channel: Channel
@Environment(\.inChannelView) private var inChannelView
@Environment(\.inNavigationView) private var inNavigationView
@Environment(\.navigationStyle) private var navigationStyle
var body: some View {
channelControl
.contentShape(Rectangle())
}
@ViewBuilder private var channelControl: some View {
if !channel.name.isEmpty {
#if os(tvOS)
channelButton
#else
if navigationStyle == .tab, inNavigationView {
channelNavigationLink
} else {
channelButton
}
#endif
}
}
@ViewBuilder private var channelNavigationLink: some View {
NavigationLink(destination: ChannelVideosView(channel: channel)) {
label
}
}
@ViewBuilder private var channelButton: some View {
Button {
guard !inChannelView else { return }
NavigationModel.shared.openChannel(
channel,
navigationStyle: navigationStyle
)
} label: {
label
}
#if os(tvOS)
.buttonStyle(.card)
#else
.buttonStyle(.plain)
#endif
.help("\(channel.name) Channel")
}
@ViewBuilder private var displayAuthor: some View {
if !channel.name.isEmpty {
Text(channel.name)
.fontWeight(.semibold)
}
}
private var label: some View {
HStack(alignment: .top, spacing: 12) {
VStack {
ChannelAvatarView(channel: channel)
#if os(tvOS)
.frame(width: 90, height: 90)
#else
.frame(width: 60, height: 60)
#endif
}
.frame(width: thumbnailWidth)
displayAuthor
.multilineTextAlignment(.leading)
}
.frame(maxWidth: .infinity, alignment: .leading)
#if os(tvOS)
.frame(minHeight: 120)
#else
.frame(minHeight: 60)
#endif
}
private var thumbnailWidth: Double {
#if os(tvOS)
250
#else
100
#endif
}
}
struct ChannelListItem_Previews: PreviewProvider {
static var previews: some View {
ChannelListItem(channel: Video.fixture.channel)
}
}

View File

@@ -29,14 +29,6 @@ struct ChannelPlaylistCell: View {
var content: some View {
VStack {
HStack(alignment: .top, spacing: 3) {
Image(systemName: "list.and.film")
Text("Playlist".localized().uppercased())
.fontWeight(.light)
.opacity(0.6)
}
.foregroundColor(.secondary)
WebImage(url: playlist.thumbnailURL, options: [.lowPriority])
.resizable()
.placeholder {

View File

@@ -0,0 +1,104 @@
import SwiftUI
struct ChannelPlaylistListItem: View {
var playlist: ChannelPlaylist
@Environment(\.inNavigationView) private var inNavigationView
@Environment(\.navigationStyle) private var navigationStyle
var body: some View {
playlistControl
.contentShape(Rectangle())
}
var thumbnailView: some View {
ThumbnailView(url: playlist.thumbnailURL)
#if os(tvOS)
.frame(width: 250, height: 140)
#else
.frame(width: 100, height: 60)
#endif
.clipShape(RoundedRectangle(cornerRadius: 2))
}
@ViewBuilder private var playlistControl: some View {
#if os(tvOS)
playlistButton
#else
if navigationStyle == .tab, inNavigationView {
playlistNavigationLink
} else {
playlistButton
}
#endif
}
@ViewBuilder private var playlistNavigationLink: some View {
NavigationLink(destination: ChannelPlaylistView(playlist: playlist)) {
label
}
}
@ViewBuilder private var playlistButton: some View {
Button {
NavigationModel.shared.openChannelPlaylist(
playlist,
navigationStyle: navigationStyle
)
} label: {
label
}
#if os(tvOS)
.buttonStyle(.card)
#else
.buttonStyle(.plain)
#endif
.help("\(playlist.title) playlist")
}
@ViewBuilder private var displayTitle: some View {
Text(playlist.title)
.fontWeight(.semibold)
}
private var label: some View {
HStack(alignment: .top, spacing: 12) {
VStack {
thumbnailView
}
.frame(width: thumbnailWidth)
#if os(tvOS)
.frame(minHeight: 100)
#else
.frame(minHeight: 60)
#endif
VStack(alignment: .leading) {
displayTitle
Text("\(playlist.videosCount ?? playlist.videos.count) videos")
.font(.caption)
.foregroundColor(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.multilineTextAlignment(.leading)
}
#if os(tvOS)
.padding(.vertical)
#endif
.frame(maxWidth: .infinity, alignment: .leading)
}
private var thumbnailWidth: Double {
#if os(tvOS)
250
#else
100
#endif
}
}
struct ChannelPlaylistListItem_Previews: PreviewProvider {
static var previews: some View {
ChannelPlaylistListItem(playlist: ChannelPlaylist.fixture)
}
}

View File

@@ -43,9 +43,14 @@ struct ChannelPlaylistView: View {
#if os(tvOS)
HStack {
if let playlist = presentedPlaylist {
ThumbnailView(url: store.item?.thumbnailURL ?? playlist.thumbnailURL)
.frame(width: 140, height: 80)
.clipShape(RoundedRectangle(cornerRadius: 2))
Text(playlist.title)
.font(.title2)
.font(.headline)
.frame(alignment: .leading)
.lineLimit(1)
Spacer()
@@ -129,6 +134,7 @@ struct ChannelPlaylistView: View {
ThumbnailView(url: store.item?.thumbnailURL ?? playlist?.thumbnailURL)
.frame(width: 60, height: 30)
.clipShape(RoundedRectangle(cornerRadius: 2))
Text(label)
.font(.headline)
.foregroundColor(.primary)

View File

@@ -50,7 +50,7 @@ struct ChannelVideosView: View {
thumbnail
Text(navigationTitle)
.font(.title2)
.font(.headline)
.frame(alignment: .leading)
Spacer()

View File

@@ -9,28 +9,77 @@ struct ContentItemView: View {
Group {
switch item.contentType {
case .video:
if listingStyle == .cells {
VideoCell(video: item.video)
} else {
PlayerQueueRow(item: .init(item.video))
.contextMenu {
VideoContextMenuView(video: item.video)
}
#if os(tvOS)
.padding(.horizontal, 30)
#endif
#if !os(tvOS)
Divider()
#endif
}
case .playlist:
ChannelPlaylistCell(playlist: item.playlist)
videoItem(item.video)
case .channel:
ChannelCell(channel: item.channel)
channelItem(item.channel)
case .playlist:
playlistItem(item.playlist)
default:
PlaceholderCell()
placeholderItem()
}
}
}
@ViewBuilder func videoItem(_ video: Video) -> some View {
if listingStyle == .cells {
VideoCell(video: video)
} else {
PlayerQueueRow(item: .init(video))
.contextMenu {
VideoContextMenuView(video: video)
}
#if os(tvOS)
.padding(.horizontal, 30)
#endif
#if !os(tvOS)
Divider()
#endif
}
}
@ViewBuilder func playlistItem(_ playlist: ChannelPlaylist) -> some View {
if listingStyle == .cells {
ChannelPlaylistCell(playlist: playlist)
} else {
ChannelPlaylistListItem(playlist: playlist)
#if os(tvOS)
.padding(.horizontal, 30)
#endif
#if !os(tvOS)
Divider()
#endif
}
}
@ViewBuilder func channelItem(_ channel: Channel) -> some View {
if listingStyle == .cells {
ChannelCell(channel: channel)
} else {
ChannelListItem(channel: channel)
#if os(tvOS)
.padding(.horizontal, 30)
#endif
#if !os(tvOS)
Divider()
#endif
}
}
@ViewBuilder func placeholderItem() -> some View {
if listingStyle == .cells {
PlaceholderCell()
} else {
PlaceholderListItem()
#if os(tvOS)
.padding(.horizontal, 30)
#endif
#if !os(tvOS)
Divider()
#endif
}
}
}

View File

@@ -0,0 +1,15 @@
import Defaults
import SwiftUI
struct PlaceholderListItem: View {
var body: some View {
VideoBanner(id: UUID().uuidString, video: .fixture)
.redacted(reason: .placeholder)
}
}
struct PlaceholderListItem_Previews: PreviewProvider {
static var previews: some View {
PlaceholderListItem()
}
}