Skip to content

Commit

Permalink
a calculated rate can be found in mathishard
Browse files Browse the repository at this point in the history
  • Loading branch information
krugerk committed Jan 7, 2025
1 parent a1c049e commit f6f524f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
<attribute name="alertStart" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="autodata" optional="YES" attributeType="String"/>
<attribute name="deadline" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="goalDateRaw" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="goalRateRaw" optional="YES" attributeType="Double" usesScalarValueType="YES"/>
<attribute name="goalUnits" optional="YES" attributeType="String"/>
<attribute name="goalValueRaw" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="graphUrl" attributeType="String"/>
<attribute name="healthKitMetric" optional="YES" attributeType="String"/>
<attribute name="hhmmFormat" attributeType="Boolean" usesScalarValueType="YES"/>
Expand All @@ -26,7 +29,6 @@
<attribute name="limSum" attributeType="String"/>
<attribute name="pledge" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="queued" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="rate" optional="YES" attributeType="Double" usesScalarValueType="YES"/>
<attribute name="rateUnits" optional="YES" attributeType="String"/>
<attribute name="safeBuf" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="safeSum" attributeType="String"/>
Expand Down
44 changes: 39 additions & 5 deletions BeeKit/Model/Goal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,20 @@ public class Goal: NSManagedObject {
@NSManaged public var won: Bool
/// The label for the y-axis of the graph. E.g., "Cumulative total hours".
@NSManaged public var yAxis: String

/// Goal units, like "hours" or "pushups" or "pages".
@NSManaged public var goalUnits: String

/// Rate units. One of y, m, w, d, h indicating that the rate of the bright red line is yearly, monthly, weekly, daily, or hourly.
@NSManaged public var rateUnits: String

/// The slope of the (final section of the) bright red line. You must also consider runits to fully specify the rate. NOTE: this may be null
@NSManaged public var rate: Double

/// The slope of the (final section of the) bright red line. You must also consider runits to fully specify the rate.
@NSManaged public var goalRateRaw: NSNumber?
/// Unix timestamp (in seconds) of the goal date.
@NSManaged public var goalDateRaw: NSNumber?
/// Goal value — the number the bright red line will eventually reach. E.g., 70 kilograms.
@NSManaged public var goalValueRaw: NSNumber?

@NSManaged public var recentData: Set<DataPoint>

@objc(addRecentDataObject:)
Expand Down Expand Up @@ -183,7 +187,19 @@ public class Goal: NSManagedObject {

self.goalUnits = json["gunits"].stringValue
self.rateUnits = json["runits"].stringValue
self.rate = json["rate"].doubleValue

// mathishard (array of 3 numbers): The goaldate, goalval, and rate — all filled in. (The commitment dial specifies 2 out of 3 and you can check this if you want Beeminder to do the math for you on inferring the third one.) Note: this field may be null if the goal is in an error state such that the graph image can't be generated.
let calculatedGoalDateGoalValueAndGoalRate = json["mathishard"].array
if let calculatedGoalDateGoalValueAndGoalRate, calculatedGoalDateGoalValueAndGoalRate.count == 3 {
self.goalDate = calculatedGoalDateGoalValueAndGoalRate[0].doubleValue
self.goalValue = calculatedGoalDateGoalValueAndGoalRate[1].doubleValue
self.goalRate = calculatedGoalDateGoalValueAndGoalRate[2].doubleValue
} else {
// logger.debug("mathishard array expected to have have 3 elements")
self.goalDateRaw = json["goaldate"].number
self.goalValueRaw = json["goalval"].number
self.goalRateRaw = json["rate"].number
}

// Replace recent data with results from server
// Note at present this leaks data points in the main db. This is probably fine for now
Expand All @@ -197,3 +213,21 @@ public class Goal: NSManagedObject {
lastModifiedLocal = Date()
}
}

public extension Goal {
var goalDate: Double? {
get { goalDateRaw?.doubleValue }
set { goalDateRaw = newValue as NSNumber? }
}

var goalValue: Double? {
get { goalValueRaw?.doubleValue }
set { goalValueRaw = newValue as NSNumber? }
}

var goalRate: Double? {
get { goalRateRaw?.doubleValue }
set { goalRateRaw = newValue as NSNumber? }
}
}

19 changes: 18 additions & 1 deletion BeeSwift/GoalViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -506,12 +506,29 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
try await ServiceLocator.goalManager.refreshGoal(self.goal.objectID)
updateInterfaceToMatchGoal()
}

private static var goalRateNumberFormatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 3
return formatter
}

private var formattedGoalRate: String? {
guard let rate = goal.goalRate as NSNumber? else { return nil }

return Self.goalRateNumberFormatter.string(from: rate)
}

func updateInterfaceToMatchGoal() {
self.datapointTableController.hhmmformat = goal.hhmmFormat
self.datapointTableController.datapoints = goal.recentData.sorted(by: {$0.updatedAt < $1.updatedAt})

self.goalRateLabel.text = "\(goal.rate) \(goal.goalUnits) / \(goal.rateUnits)"
self.goalRateLabel.isHidden = formattedGoalRate == nil
self.goalRateLabel.text = {
guard let formattedGoalRate else { return nil }
return "\(formattedGoalRate) \(goal.goalUnits) / \(goal.rateUnits)"
}()

self.refreshCountdown()
self.updateLastUpdatedLabel()
Expand Down

0 comments on commit f6f524f

Please sign in to comment.