diff --git a/BeeKit/Daystamp.swift b/BeeKit/Daystamp.swift index 2e2b91ad..1eed6673 100644 --- a/BeeKit/Daystamp.swift +++ b/BeeKit/Daystamp.swift @@ -40,8 +40,13 @@ public struct Daystamp: CustomStringConvertible, Strideable, Comparable, Equatab self.init(year: year, month: month, day: day) } - - init(fromDate date: Date, deadline: Int) { + + /// Creates a Daystamp of having submitted a datapoint on a particular date given the goal's deadline + /// + /// - Parameters: + /// - date: a calendar date + /// - deadline: a ``Goal/deadline`` + public init(fromDate date: Date, deadline: Int) { let secondsAfterMidnight = Daystamp.calendar.component(.hour, from: date) * 60 * 60 + Daystamp.calendar.component(.minute, from: date) * 60 @@ -104,12 +109,16 @@ public struct Daystamp: CustomStringConvertible, Strideable, Comparable, Equatab // Trait: CustomStringConvertible + /// Daystamp formatted as a YYYYMMdd string public var description: String { return String(format: "%04d%02d%02d", year, month, day) } // Trait: Strideable + /// how many days apart two daystamps are + /// - Parameter other: another daystamp + /// - Returns: number of days as distance between the daystamps public func distance(to other: Daystamp) -> Int { let selfDate = Daystamp.calendar.date(from: DateComponents(calendar: Daystamp.calendar, year: year, month: month, day: day))! let otherDate = Daystamp.calendar.date(from: DateComponents(calendar: Daystamp.calendar, year: other.year, month: other.month, day: other.day))! @@ -147,4 +156,20 @@ public struct Daystamp: CustomStringConvertible, Strideable, Comparable, Equatab // Trait: Hashable // This is generated automatically for structs by the compiler + + + /// generates the daystamp as a string for use in urtext, considering both the submission date and goal's deadline + /// - Parameters: + /// - submissionDate: calendar date on which the datapoint would be submitted + /// - goal: the goal for which the urtext is to be created + /// - Returns: string of the daystamp, suitable for use in urtext + public static func makeUrtextDaystamp(submissionDate: Date = Date(), goal: Goal) -> String { + let daystamp = Daystamp(fromDate: submissionDate, + deadline: goal.deadline) + + return String(format: "%04d %02d %02d", + daystamp.year, + daystamp.month, + daystamp.day) + } } diff --git a/BeeSwift/GoalViewController.swift b/BeeSwift/GoalViewController.swift index 2da1f19d..baa5b049 100644 --- a/BeeSwift/GoalViewController.swift +++ b/BeeSwift/GoalViewController.swift @@ -209,30 +209,7 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl self.dateStepper.tintColor = UIColor.Beeminder.gray dataEntryView.addSubview(self.dateStepper) self.dateStepper.addTarget(self, action: #selector(GoalViewController.dateStepperValueChanged), for: .valueChanged) - self.dateStepper.value = 0 - - // if the goal's deadline is after midnight, and it's after midnight, - // but before the deadline, - // default to entering data for the "previous" day. - let now = Date() - let calendar = Calendar.current - let components = (calendar as NSCalendar).components([.hour, .minute], from: now) - let currentHour = components.hour - if self.goal.deadline > 0 && currentHour! < 6 && currentHour! < self.goal.deadline/3600 { - self.dateStepper.value = -1 - } - - // if the goal's deadline is before midnight and has already passed for this calendar day, default to entering data for the "next" day - if self.goal.deadline < 0 { - let deadlineSecondsAfterMidnight = 24*3600 + self.goal.deadline - let deadlineHour = deadlineSecondsAfterMidnight/3600 - let deadlineMinute = (deadlineSecondsAfterMidnight % 3600)/60 - let currentMinute = components.minute - if deadlineHour < currentHour! || - (deadlineHour == currentHour! && deadlineMinute < currentMinute!) { - self.dateStepper.value = 1 - } - } + self.dateStepper.value = Self.makeInitialDateStepperValue(for: goal) self.dateStepper.snp.makeConstraints { (make) -> Void in make.top.equalTo(self.dateTextField.snp.bottom).offset(elementSpacing) @@ -513,6 +490,15 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl func viewForZooming(in scrollView: UIScrollView) -> UIView? { return self.goalImageView } + + private static func makeInitialDateStepperValue(date: Date = Date(), for goal: Goal) -> Double { + let daystampAccountingForTheGoalsDeadline = Daystamp(fromDate: date, + deadline: goal.deadline) + let daystampAssumingMidnightDeadline = Daystamp(fromDate: date, + deadline: 0) + + return Double(daystampAccountingForTheGoalsDeadline.distance(to: daystampAssumingMidnightDeadline)) + } // MARK: - SFSafariViewControllerDelegate diff --git a/BeeSwift/TimerViewController.swift b/BeeSwift/TimerViewController.swift index aa824b55..85ca53f6 100644 --- a/BeeSwift/TimerViewController.swift +++ b/BeeSwift/TimerViewController.swift @@ -143,33 +143,7 @@ class TimerViewController: UIViewController { } func urtext() -> String { - // if the goal's deadline is after midnight, and it's after midnight, - // but before the deadline, - // default to entering data for the "previous" day. - let now = Date() - var offset: Double = 0 - let calendar = Calendar.current - let components = (calendar as NSCalendar).components([.hour, .minute], from: now) - let currentHour = components.hour - if self.goal.deadline > 0 && currentHour! < 6 && self.goal.deadline/3600 < currentHour! { - offset = -1 - } - - // if the goal's deadline is before midnight and has already passed for this calendar day, default to entering data for the "next" day - if self.goal.deadline < 0 { - let deadlineSecondsAfterMidnight = 24*3600 + self.goal.deadline - let deadlineHour = deadlineSecondsAfterMidnight/3600 - let deadlineMinute = (deadlineSecondsAfterMidnight % 3600)/60 - let currentMinute = components.minute - if deadlineHour < currentHour! || - (deadlineHour == currentHour! && deadlineMinute < currentMinute!) { - offset = 1 - } - } - - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US") - formatter.dateFormat = "d" + let urtextDaystamp = Daystamp.makeUrtextDaystamp(submissionDate: Date(), goal: goal) let value: Double @@ -182,7 +156,7 @@ class TimerViewController: UIViewController { let comment = "Automatically entered from iOS timer interface" - return "\(formatter.string(from: Date(timeIntervalSinceNow: offset*24*3600))) \(value) \"\(comment)\"" + return "\(urtextDaystamp) \(value) \"\(comment)\"" } @objc func addDatapointButtonPressed() { diff --git a/BeeSwiftToday/TodayTableViewCell.swift b/BeeSwiftToday/TodayTableViewCell.swift index 5df44da5..d335e6fc 100644 --- a/BeeSwiftToday/TodayTableViewCell.swift +++ b/BeeSwiftToday/TodayTableViewCell.swift @@ -125,36 +125,11 @@ class TodayTableViewCell: UITableViewCell { hud.mode = .indeterminate self.addDataButton.isUserInteractionEnabled = false - // if the goal's deadline is after midnight, and it's after midnight, - // but before the deadline, - // default to entering data for the "previous" day. - let now = Date() - var offset: Double = 0 - let calendar = Calendar.current - let components = (calendar as NSCalendar).components([.hour, .minute], from: now) - let currentHour = components.hour - let goalDeadline = goal.deadline - if goalDeadline > 0 && currentHour! < 6 && goalDeadline/3600 < currentHour! { - offset = -1 - } - - // if the goal's deadline is before midnight and has already passed for this calendar day, default to entering data for the "next" day - if goalDeadline < 0 { - let deadlineSecondsAfterMidnight = 24*3600 + goalDeadline - let deadlineHour = deadlineSecondsAfterMidnight/3600 - let deadlineMinute = (deadlineSecondsAfterMidnight % 3600)/60 - let currentMinute = components.minute - if deadlineHour < currentHour! || - (deadlineHour == currentHour! && deadlineMinute < currentMinute!) { - offset = 1 - } - } - - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US") - formatter.dateFormat = "d" + let urtextDaystamp = Daystamp.makeUrtextDaystamp(submissionDate: Date(), goal: goal) + let value = Int(self.valueStepper.value) + let comment = "Added via iOS widget" - let params = ["urtext": "\(formatter.string(from: Date(timeIntervalSinceNow: offset*24*3600))) \(Int(self.valueStepper.value)) \"Added via iOS widget\"", "requestid": UUID().uuidString] + let params = ["urtext": "\(urtextDaystamp) \(value) \"\(comment)\"", "requestid": UUID().uuidString] let slug = goal.slug Task { @MainActor in