import Foundation import Observation import VelodyDomain import VelodyPersistence @MainActor @Observable final class MacLibraryViewModel { var tracks: [LibraryTrack] = [] var selectedFolderPath = "No folder selected" var scanStatus = "Choose a folder to begin local discovery." var discoveredTrackCount = 0 var isScanning = false private let folderAccessService: any VelodyPersistence.FolderAccessService private let localMusicScanner: any LocalMusicScanner private let store = InMemoryLocalLibraryStore() private var hasLoaded = false init() { let folderAccessService = FolderAccessService() let localMusicScanner = FileSystemLocalMusicScanner( metadataReader: AVFoundationMetadataReader() ) self.folderAccessService = folderAccessService self.localMusicScanner = localMusicScanner if let url = folderAccessService.storedFolderURL() { selectedFolderPath = url.path scanStatus = "Folder restored. Run a manual scan to discover MP3 files." } } func loadIfNeeded() async { guard !hasLoaded else { return } hasLoaded = true tracks = await store.loadTracks() discoveredTrackCount = tracks.count } func chooseFolder() { if let url = folderAccessService.chooseFolder() { selectedFolderPath = url.path scanStatus = "Folder selected. Run a manual scan to discover MP3 files." tracks = [] discoveredTrackCount = 0 Task { await store.replaceTracks([]) } } } func scanMP3Files() async { guard let folderURL = folderAccessService.storedFolderURL() else { scanStatus = "Choose a folder before scanning." return } isScanning = true scanStatus = "Scanning MP3 files..." defer { isScanning = false } do { let discoveredTracks = try await localMusicScanner.scanFolder(at: folderURL) await store.replaceTracks(discoveredTracks) tracks = await store.loadTracks() discoveredTrackCount = tracks.count scanStatus = "Scan finished. Found \(discoveredTrackCount) MP3 file(s)." } catch { scanStatus = "Scan failed: \(error.localizedDescription)" } } }