97 lines
3.1 KiB
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)
|
|
}
|
|
}
|