TaskView.swift 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //
  2. // TaskView.swift
  3. // Todos
  4. //
  5. // Created by Sam Jaffe on 2/28/26.
  6. //
  7. import SwiftUI
  8. import SwiftData
  9. struct TaskView: View {
  10. @Environment(\.modelContext) private var modelContext
  11. @AppStorage(UserDefaultsKeys.Category) var allGroups = CodableArray<Category>()
  12. @Binding var task: Task
  13. @State private var showDialogue: Bool = false
  14. @State private var hideTags: Bool = false
  15. @State private var hideNotes: Bool = false
  16. @State private var empty = Category()
  17. let unset: Priority? = nil
  18. @FocusState private var isFocused: Bool
  19. var body: some View {
  20. VStack {
  21. HStack {
  22. if let priority = task.priority {
  23. Image(systemName: priority.label)
  24. .foregroundStyle(priority.style)
  25. .bold()
  26. .frame(width: 20)
  27. .padding(.trailing, -10)
  28. }
  29. StatusPicker(status: $task.status)
  30. .onChange(of: task.status) {
  31. if task.status.isStrong {
  32. task.subtasks
  33. .filter({ !$0.status.isStrong })
  34. .forEach({ subtask in subtask.status = task.status })
  35. }
  36. }
  37. TextField("Task Name", text: $task.name)
  38. .focused($isFocused)
  39. if let grp = $allGroups.first(where: { $0.name.wrappedValue == task.category }) {
  40. ColorPicker("", selection: grp.color).disabled(true).scaledToFit()
  41. }
  42. Button(action: addItem) {
  43. Image(systemName: "plus")
  44. .help("Add a Subtask")
  45. }
  46. Button {
  47. showDialogue = !showDialogue
  48. } label: {
  49. Label("", systemImage: "ellipsis.circle")
  50. .foregroundStyle(.gray)
  51. .font(.title2)
  52. }
  53. .buttonStyle(.borderless)
  54. .popover(isPresented: $showDialogue) {
  55. List{
  56. Picker("Category", selection: $task.category) {
  57. Text(empty.name).tag("")
  58. ForEach(allGroups) { group in
  59. Text(group.name)
  60. }
  61. }
  62. .fixedSize(horizontal: true, vertical: false)
  63. Picker("Priority", selection: $task.priority) {
  64. Text("").tag(unset)
  65. ForEach(Priority.allCases) { unit in
  66. Text(unit.id).tag(unit)
  67. }
  68. }
  69. }
  70. }
  71. Text("")
  72. }
  73. if isFocused || !(hideTags || task.tags.isEmpty) {
  74. HStack {
  75. TagBarView(task: $task)
  76. .font(.footnote)
  77. .padding(.leading, 30)
  78. VisibilityTapper(hideToggle: $hideTags)
  79. }.focused($isFocused)
  80. }
  81. if isFocused || !(hideNotes || task.notes.isEmpty) {
  82. HStack {
  83. TextField("Notes", text: $task.notes, axis: .vertical)
  84. .font(.footnote)
  85. .padding(.leading, 30)
  86. VisibilityTapper(hideToggle: $hideNotes)
  87. }.focused($isFocused)
  88. }
  89. }
  90. }
  91. private func addItem() {
  92. withAnimation {
  93. let newSubtask = SubTask(parent: task)
  94. modelContext.insert(newSubtask)
  95. task.subtasks.append(newSubtask)
  96. }
  97. }
  98. }
  99. #Preview {
  100. @Previewable @State var task = Task()
  101. TaskView(task: $task)
  102. .frame(minHeight: 100) // Preview does not resize window properly
  103. }