Files
QueueCube/QueueCube/PlaylistView.swift

161 lines
3.7 KiB
Swift

//
// PlaylistView.swift
// QueueCube
//
// Created by James Magahern on 3/3/25.
//
import SwiftUI
struct PlaylistItem: Identifiable
{
let index: Int
let id: String
let title: String
let filename: String
let isCurrent: Bool
}
struct FavoriteItem: Identifiable
{
let id: String
let title: String
let filename: String
}
@Observable
class PlaylistViewModel
{
var isPlaying: Bool = false
var items: [PlaylistItem] = []
var onSeek: (PlaylistItem) -> Void = { _ in }
var onDelete: (PlaylistItem) -> Void = { _ in }
}
@Observable
class FavoritesViewModel
{
var items: [FavoriteItem] = []
var onPlay: (FavoriteItem) -> Void = { _ in }
}
struct PlaylistView: View
{
var model: PlaylistViewModel
var body: some View {
List(model.items) { item in
PlaylistItemCell(
title: item.title,
subtitle: item.filename,
state: item.isCurrent ? (model.isPlaying ? PlaylistItemCell.State.playing : PlaylistItemCell.State.paused)
: .queued,
onLeadingIconClick: { model.onSeek(item) },
onDeleteButtonClick: { model.onDelete(item) },
)
}
}
}
struct FavoritesView: View
{
var model: FavoritesViewModel
var body: some View {
List(model.items) { item in
FavoriteItemCell(
title: item.title,
subtitle: item.filename,
onPlayButtonClick: { model.onPlay(item) }
)
}
}
}
struct PlaylistItemCell: View
{
let title: String
let subtitle: String
let state: State
let onLeadingIconClick: () -> Void
let onDeleteButtonClick: () -> Void
var body: some View {
let icon: String = switch state {
case .queued: "play.fill"
case .playing: "speaker.wave.3.fill"
case .paused: "speaker.fill"
}
HStack {
Button(action: onLeadingIconClick) { Image(systemName: icon) }
.buttonStyle(BorderlessButtonStyle())
.tint(Color.primary)
.frame(width: 15.0)
VStack(alignment: .leading) {
Text(title)
.font(.body.bold())
.lineLimit(1)
Text(subtitle)
.foregroundColor(.secondary)
.lineLimit(1)
}
Spacer()
HStack {
Button(action: onDeleteButtonClick) {
Image(systemName: "xmark")
.tint(.red)
}
}
}
.listRowBackground(state != .queued ? Color.white.opacity(0.15) : nil)
.padding([.top, .bottom], 8.0)
}
// MARK: - Types
enum State {
case queued
case playing
case paused
}
}
struct FavoriteItemCell: View
{
let title: String
let subtitle: String
let onPlayButtonClick: () -> Void
var body: some View {
HStack {
Button(action: onPlayButtonClick) {
Image(systemName: "play.fill")
}
.buttonStyle(BorderlessButtonStyle())
.tint(Color.primary)
.frame(width: 15.0)
VStack(alignment: .leading) {
Text(title)
.font(.body.bold())
.lineLimit(1)
Text(subtitle)
.foregroundColor(.secondary)
.lineLimit(1)
}
Spacer()
}
.padding([.top, .bottom], 8.0)
}
}