Project.swift 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. //
  2. // Project.swift
  3. // Todos
  4. //
  5. // Created by Sam Jaffe on 2/28/26.
  6. //
  7. import Foundation
  8. import SwiftData
  9. import SwiftUI
  10. @Model
  11. final class Project: Codable, Ordered, Aggregate {
  12. typealias Element = Task
  13. var uuid: UUID = UUID()
  14. var sortOrder: Int = 0
  15. var name: String = "New Project"
  16. var category: String = ""
  17. @Relationship(deleteRule: .cascade, inverse: \Task.project)
  18. var tasks: [Task] = []
  19. init(sortOrder: Int = 0) {
  20. self.sortOrder = sortOrder
  21. }
  22. func move(fromOffsets: IndexSet, toOffset: Int) {
  23. tasks.move(fromOffsets: fromOffsets, toOffset: toOffset)
  24. reindex()
  25. }
  26. func remove(_ item: Element) {
  27. tasks.removeAll(where: { $0.id == item.id })
  28. reindex()
  29. }
  30. func reindex() {
  31. for (index, item) in tasks.enumerated() {
  32. item.sortOrder = index
  33. }
  34. }
  35. func yaml(_ indent: Int = 0) -> String {
  36. let hdr = String(repeating: " ", count: indent)
  37. var rval = hdr + "\(name):\n"
  38. if !category.isEmpty {
  39. rval += hdr + " # In Category: \(category)\n"
  40. }
  41. rval += tasks.map({ $0.yaml(indent + 1) }).joined()
  42. return rval
  43. }
  44. enum CodingKeys: CodingKey { case category, name, tasks }
  45. required init(from decoder: any Decoder) throws {
  46. let container = try decoder.container(keyedBy: CodingKeys.self)
  47. category = try container.decode(String.self, forKey: .category)
  48. name = try container.decode(String.self, forKey: .name)
  49. tasks = try container.decode([Task].self, forKey: .tasks)
  50. tasks.forEach({ $0.project = self })
  51. }
  52. func encode(to encoder: any Encoder) throws {
  53. var container = encoder.container(keyedBy: CodingKeys.self)
  54. try container.encode(category, forKey: .category)
  55. try container.encode(tasks, forKey: .tasks)
  56. try container.encode(name, forKey: .name)
  57. }
  58. }