I have a form which lets the user create a project. In this form, I want to automatically change the project's deadline DatePicker based on the user's input such as start date, daily count, and target count. If the DatePicker's date is changed, then the other views should update also.
For example if the user has a start date of Sep 6, 2022, a target of 1000, and a daily count of 500, then the deadline is 1000 / 500 = 2 days and should show Sep 8, 2022.
Looking at solutions like this one and this one, I thought maybe I should use a computed property to calculate the deadline. I can display the deadline in a Text view, but how do I do this in a DatePicker? If I directly put the deadline targetDate
in the picker:
DatePicker("Deadline", selection: $createdProject.targetDate)
Then I get a build error:
Cannot assign to property: 'targetDate' is a get-only property
Maybe something I don't understand, or there's a simple solution but I can't think of it.
ContentView.swift:
import SwiftUI
struct ContentView: View {
@StateObject var createdProject:ProjectItem = ProjectItem()
var body: some View {
Form {
Section {
DatePicker("Start", selection: $createdProject.startDate)
}
Section {
VStack {
HStack {
Text("Starting word count:").fixedSize(horizontal: false, vertical: true)
TextField("0", value: $createdProject.startWordCount, formatter: NumberFormatter()).textFieldStyle(.roundedBorder)
}.padding(.bottom, 10)
HStack {
Text("Target word count").fixedSize(horizontal: false, vertical: true)
TextField("85000", value: $createdProject.targetWordCount, formatter: NumberFormatter())
.textFieldStyle(.roundedBorder)
}
}
}
Section {
VStack {
HStack {
Text("Daily word count").fixedSize(horizontal: false, vertical: true)
TextField("0", value: $createdProject.dailyWordCount, formatter: NumberFormatter()).textFieldStyle(.roundedBorder)
}
}
// This changes to show the updated deadline
// Text("Deadline is \(createdProject.targetDate)")
// But DatePicker has build error
DatePicker("Deadline", selection: $createdProject.targetDate)
}
} // end Form
}
}
ProjectItem.swift
import SwiftUI
class ProjectItem: Identifiable, ObservableObject {
@Published var id: UUID = UUID()
@Published var startDate:Date = Date()
var targetDate:Date {
if (dailyWordCount == 0) {
return Date()
} else {
// Given start date, starting word count,
// daily word count, and target word count,
// calculate the new target date
let daysNeeded = (targetWordCount - startWordCount) / dailyWordCount
print("Need \(daysNeeded) days to reach the target")
var dateComponent = DateComponents()
dateComponent.day = daysNeeded
let nextDate = Calendar.current.date(byAdding: dateComponent, to: startDate) ?? startDate
print("The target date will be \(nextDate)")
return nextDate
}
}
@Published var startWordCount:Int = 0
@Published var targetWordCount:Int = 85000
@Published var dailyWordCount:Int = 0
}
Example image: