Implement song project list

This commit is contained in:
Codex
2026-09-13 14:17:38 +02:00
parent 60b4f1b916
commit e28d45ae18
3 changed files with 90 additions and 10 deletions
@@ -5,6 +5,33 @@ public protocol ProjectStore: Sendable {
func save(_ project: SongProject) async throws
func open(id: String) async throws -> SongProject
func loadProjectIDs() async throws -> [String]
func loadProjectList() async throws -> [SongProjectListItem]
}
public struct SongProjectListItem: Codable, Equatable, Identifiable, Sendable {
public let id: String
public var title: String
public var idea: String
public var createdAt: Date
public var updatedAt: Date
public init(id: String, title: String, idea: String, createdAt: Date, updatedAt: Date) {
self.id = id
self.title = title
self.idea = idea
self.createdAt = createdAt
self.updatedAt = updatedAt
}
public init(project: SongProject) {
self.init(
id: project.id,
title: project.title,
idea: project.idea,
createdAt: project.createdAt,
updatedAt: project.updatedAt
)
}
}
public actor LocalSongProjectStore: ProjectStore {
@@ -43,15 +70,23 @@ public actor LocalSongProjectStore: ProjectStore {
}
public func loadProjectIDs() async throws -> [String] {
try await loadProjectList().map(\.id)
}
public func loadProjectList() async throws -> [SongProjectListItem] {
try ensureDirectoryExists()
let fileURLs = try FileManager.default.contentsOfDirectory(
at: directoryURL,
includingPropertiesForKeys: nil
)
return fileURLs
.filter { $0.pathExtension == Self.fileExtension }
.map { $0.deletingPathExtension().lastPathComponent }
.sorted()
return try projectFileURLs()
.map { url in
let data = try Data(contentsOf: url)
let project = try decoder.decode(SongProject.self, from: data)
return SongProjectListItem(project: project)
}
.sorted { left, right in
if left.updatedAt == right.updatedAt {
return left.title.localizedStandardCompare(right.title) == .orderedAscending
}
return left.updatedAt > right.updatedAt
}
}
private func ensureDirectoryExists() throws {
@@ -66,6 +101,14 @@ public actor LocalSongProjectStore: ProjectStore {
try data.write(to: url, options: [.atomic])
}
private func projectFileURLs() throws -> [URL] {
try FileManager.default.contentsOfDirectory(
at: directoryURL,
includingPropertiesForKeys: nil
)
.filter { $0.pathExtension == Self.fileExtension }
}
private func projectURL(for id: String) -> URL {
directoryURL
.appendingPathComponent(id)