Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 64 additions & 12 deletions BeeSwift/GoalViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
fileprivate let headerWidth = Double(1.0/3.0)
fileprivate let viewGoalActivityType = "com.beeminder.viewGoal"

// date corresponding to the datapoint to be created
private var date: Date = Date()

init(goal: Goal) {
self.goal = goal
super.init(nibName: nil, bundle: nil)
Expand Down Expand Up @@ -272,7 +275,7 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
}

self.navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.actionButtonPressed))]
if (!self.goal.hideDataEntry) {
if !self.goal.hideDataEntry {
self.navigationItem.rightBarButtonItems?.append(UIBarButtonItem(image: UIImage(named: "Timer"), style: .plain, target: self, action: #selector(self.timerButtonPressed)))
}

Expand Down Expand Up @@ -368,12 +371,14 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
var components = DateComponents()
components.day = Int(self.dateStepper.value)

let newDate = (calendar as NSCalendar?)?.date(byAdding: components, to: Date(), options: [])
let now = Date()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does surprising things if you have the view open and midnight rolls around. But this PR doesn't change that weird behavior, it was always there.

Copy link
Copy Markdown
Contributor Author

@krugerk krugerk Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. The app will work with the data it has from the time it last fetched it. One can use other means to adjust the deadline and the one client might not know about it while it is at the timer screen, add data screen, or edit data screen. (See #26)

Is the server posting to the app via remote notification that a goal has been updated? Does the app still need to fetch (pull) to find out?

guard let newDate = calendar.date(byAdding: components, to: now) else { return }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This seems like the return here should never happen. I like logging a warning in these cases.

self.date = newDate

let isDifferentYear = calendar.component(.year, from: now) != calendar.component(.year, from: date)
let isDifferentMonth = calendar.component(.month, from: now) != calendar.component(.month, from: date)

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.dateFormat = "d"
self.dateTextField.text = formatter.string(from: newDate!)
self.dateTextField.text = DateFormatter.dateTextFieldString(from: self.date, isDifferentYear: isDifferentYear, isDifferentMonth: isDifferentMonth)
}

func setValueTextField() {
Expand Down Expand Up @@ -417,12 +422,12 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.isEqual(self.valueTextField)) {
if textField.isEqual(self.valueTextField) {
// Only allow a single decimal separator (, or .)
if textField.text!.components(separatedBy: ".").count > 1 {
if string == "." || string == "," { return false }
}
if (string == ",") {
if string == "," {
textField.text = textField.text! + "."
return false
}
Expand All @@ -436,9 +441,9 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
}
return true
}

func urtextFromTextFields() -> String {
return "\(self.dateTextField.text!) \(self.valueTextField.text!) \"\(self.commentTextField.text!)\""
private var urtext: String {
return "\(DateFormatter.urtextDateString(from: self.date)) \(self.valueTextField.text!) \"\(self.commentTextField.text!)\""
}

@objc func submitDatapoint() {
Expand All @@ -450,7 +455,7 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
self.scrollView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 0, height: 0), animated: true)

do {
let _ = try await ServiceLocator.requestManager.addDatapoint(urtext: self.urtextFromTextFields(), slug: self.goal.slug)
let _ = try await ServiceLocator.requestManager.addDatapoint(urtext: self.urtext, slug: self.goal.slug)
self.commentTextField.text = ""

try await updateGoalAndInterface()
Expand Down Expand Up @@ -506,3 +511,50 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
controller.dismiss(animated: true, completion: nil)
}
}


private extension DateFormatter {
private static let urtextDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.dateFormat = "yyyy MM dd"
return formatter
}()

static func urtextDateString(from date: Date) -> String {
urtextDateFormatter.string(from: date)
}
}

private extension DateFormatter {
private static let newDatapointDateDifferentYearDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()

private static let newDatapointDateDifferentMonthDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.dateFormat = "MMM d"
return formatter
}()

private static let newDatapointDateWithinSameMonthDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.dateFormat = "d"
return formatter
}()

static func dateTextFieldString(from date: Date, isDifferentYear: Bool, isDifferentMonth: Bool) -> String {
if isDifferentYear {
return newDatapointDateDifferentYearDateFormatter.string(from: date)
} else if isDifferentMonth {
return newDatapointDateDifferentMonthDateFormatter.string(from: date)
} else {
return newDatapointDateWithinSameMonthDateFormatter.string(from: date)
}
}
}