velody/apps/apple/VelodyMac/Sources/MacLibraryView.swift

97 lines
3.1 KiB
Swift

import Foundation
import SwiftUI
import VelodyDomain
struct MacLibraryView: View {
@State private var viewModel = MacLibraryViewModel()
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Private Library Foundation")
.font(.largeTitle)
Text("Selected folder")
.font(.headline)
Text(viewModel.selectedFolderPath)
.textSelection(.enabled)
.foregroundStyle(.secondary)
HStack(spacing: 12) {
Button("Choose Music Folder") {
viewModel.chooseFolder()
}
Button("Scan MP3 Files") {
Task {
await viewModel.scanMP3Files()
}
}
.disabled(viewModel.selectedFolderPath == "No folder selected" || viewModel.isScanning)
}
HStack(spacing: 12) {
Text("Discovered tracks: \(viewModel.discoveredTrackCount)")
.font(.headline)
if viewModel.isScanning {
ProgressView()
.controlSize(.small)
}
}
Text(viewModel.scanStatus)
.foregroundStyle(.secondary)
List(viewModel.tracks) { track in
VStack(alignment: .leading, spacing: 4) {
Text(track.title)
.font(.headline)
Text(track.artist)
.foregroundStyle(.secondary)
if let album = track.album {
Text(album)
.font(.caption)
.foregroundStyle(.secondary)
}
if let durationSeconds = track.durationSeconds {
Text("Duration: \(format(durationSeconds: durationSeconds))")
.font(.caption2)
.foregroundStyle(.tertiary)
}
Text(track.localFilePath)
.font(.caption2)
.foregroundStyle(.tertiary)
.lineLimit(1)
}
.padding(.vertical, 4)
}
.overlay {
if viewModel.tracks.isEmpty && !viewModel.isScanning {
ContentUnavailableView(
"No MP3 Files Discovered",
systemImage: "music.note.list",
description: Text("Choose a folder, then run a manual scan.")
)
}
}
Spacer(minLength: 0)
}
.padding(24)
.task {
await viewModel.loadIfNeeded()
}
}
private func format(durationSeconds: Double) -> String {
let totalSeconds = Int(durationSeconds.rounded())
let minutes = totalSeconds / 60
let seconds = totalSeconds % 60
return String(format: "%d:%02d", minutes, seconds)
}
}