Implement song project list
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user