Replace status_id with in_progress boolean across mobile apps

- Remove TaskStatus model and status_id foreign key references
- Add in_progress boolean field to task models and forms
- Update TaskApi to use dedicated POST endpoints for task actions:
  - POST /tasks/:id/cancel/ instead of PATCH with is_cancelled
  - POST /tasks/:id/uncancel/
  - POST /tasks/:id/archive/
  - POST /tasks/:id/unarchive/
- Fix iOS TaskViewModel to use error-first pattern for Kotlin-Swift
  generic type bridging issues
- Update iOS callback signatures to pass full TaskResponse instead
  of just taskId to avoid stale closure lookups
- Add in_progress localization strings
- Update widget preview data to use inProgress boolean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-08 20:47:59 -06:00
parent a067228597
commit 4a04aff1e6
33 changed files with 314 additions and 376 deletions

View File

@@ -29,15 +29,13 @@ struct TaskFormView: View {
(!needsResidenceSelection || selectedResidence != nil) &&
selectedCategory != nil &&
selectedFrequency != nil &&
selectedPriority != nil &&
selectedStatus != nil
selectedPriority != nil
}
// Lookups from DataManagerObservable
private var taskCategories: [TaskCategory] { dataManager.taskCategories }
private var taskFrequencies: [TaskFrequency] { dataManager.taskFrequencies }
private var taskPriorities: [TaskPriority] { dataManager.taskPriorities }
private var taskStatuses: [TaskStatus] { dataManager.taskStatuses }
private var isLoadingLookups: Bool { !dataManager.lookupsInitialized }
// Form fields
@@ -47,7 +45,7 @@ struct TaskFormView: View {
@State private var selectedCategory: TaskCategory?
@State private var selectedFrequency: TaskFrequency?
@State private var selectedPriority: TaskPriority?
@State private var selectedStatus: TaskStatus?
@State private var inProgress: Bool
@State private var dueDate: Date
@State private var intervalDays: String
@State private var estimatedCost: String
@@ -66,7 +64,7 @@ struct TaskFormView: View {
_selectedCategory = State(initialValue: task.category)
_selectedFrequency = State(initialValue: task.frequency)
_selectedPriority = State(initialValue: task.priority)
_selectedStatus = State(initialValue: task.status)
_inProgress = State(initialValue: task.inProgress)
// Parse date from string
let formatter = DateFormatter()
@@ -78,6 +76,7 @@ struct TaskFormView: View {
} else {
_title = State(initialValue: "")
_description = State(initialValue: "")
_inProgress = State(initialValue: false)
_dueDate = State(initialValue: Date())
_intervalDays = State(initialValue: "")
_estimatedCost = State(initialValue: "")
@@ -246,16 +245,11 @@ struct TaskFormView: View {
}
}
Picker(L10n.Tasks.status, selection: $selectedStatus) {
Text(L10n.Tasks.selectStatus).tag(nil as TaskStatus?)
ForEach(taskStatuses, id: \.id) { status in
Text(status.displayName).tag(status as TaskStatus?)
}
}
Toggle(L10n.Tasks.inProgressLabel, isOn: $inProgress)
} header: {
Text(L10n.Tasks.priorityAndStatus)
} footer: {
Text(L10n.Tasks.bothRequired)
Text(L10n.Tasks.required)
.font(.caption)
.foregroundColor(Color.appError)
}
@@ -409,11 +403,6 @@ struct TaskFormView: View {
selectedPriority = taskPriorities.first { $0.name == "medium" } ?? taskPriorities.first
}
if selectedStatus == nil && !taskStatuses.isEmpty {
// Default to "pending"
selectedStatus = taskStatuses.first { $0.name == "pending" } ?? taskStatuses.first
}
// Set default residence if provided
if needsResidenceSelection && selectedResidence == nil, let residences = residences, !residences.isEmpty {
selectedResidence = residences.first
@@ -452,11 +441,6 @@ struct TaskFormView: View {
isValid = false
}
if selectedStatus == nil {
viewModel.errorMessage = "Please select a status"
isValid = false
}
return isValid
}
@@ -465,8 +449,7 @@ struct TaskFormView: View {
guard let category = selectedCategory,
let frequency = selectedFrequency,
let priority = selectedPriority,
let status = selectedStatus else {
let priority = selectedPriority else {
return
}
@@ -483,7 +466,7 @@ struct TaskFormView: View {
description: description.isEmpty ? nil : description,
categoryId: KotlinInt(int: Int32(category.id)),
priorityId: KotlinInt(int: Int32(priority.id)),
statusId: KotlinInt(int: Int32(status.id)),
inProgress: inProgress,
frequencyId: KotlinInt(int: Int32(frequency.id)),
assignedToId: nil,
dueDate: dueDateString,
@@ -514,7 +497,7 @@ struct TaskFormView: View {
description: description.isEmpty ? nil : description,
categoryId: KotlinInt(int: Int32(category.id)),
priorityId: KotlinInt(int: Int32(priority.id)),
statusId: selectedStatus.map { KotlinInt(int: Int32($0.id)) },
inProgress: inProgress,
frequencyId: KotlinInt(int: Int32(frequency.id)),
assignedToId: nil,
dueDate: dueDateString,