Skip to content
Draft
Show file tree
Hide file tree
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
20 changes: 20 additions & 0 deletions BeeKit/GoalExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,23 @@ extension Goal {
return candidateDatapoints.first?.value
}
}

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

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

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

var currentRate: String? {
guard let formattedGoalRate else { return nil }
return "\(formattedGoalRate) \(goalUnits) / \(rateUnits)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +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 @@ -25,6 +29,7 @@
<attribute name="limSum" attributeType="String"/>
<attribute name="pledge" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="queued" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="rateUnits" optional="YES" attributeType="String"/>
<attribute name="safeBuf" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="safeSum" attributeType="String"/>
<attribute name="slug" attributeType="String" spotlightIndexingEnabled="YES"/>
Expand Down
51 changes: 49 additions & 2 deletions BeeKit/Model/Goal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +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.
@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 @@ -171,7 +184,23 @@ public class Goal: NSManagedObject {
self.useDefaults = json["use_defaults"].boolValue
self.won = json["won"].boolValue
self.yAxis = json["yaxis"].stringValue


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

// 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
let newRecentData = Set<DataPoint>(json["recent_data"].arrayValue.map {
Expand All @@ -184,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? }
}
}

14 changes: 13 additions & 1 deletion BeeSwift/GoalCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class GoalCollectionViewCell: UICollectionViewCell {
let todaytaLabel :BSLabel = BSLabel()
let thumbnailImageView = GoalImageView(isThumbnail: true)
let safesumLabel :BSLabel = BSLabel()
let rateLabel = BSLabel()
let margin = 8

var goal: Goal? {
Expand All @@ -27,6 +28,7 @@ class GoalCollectionViewCell: UICollectionViewCell {
self.todaytaLabel.text = goal?.todayta == true ? "✓" : ""
self.safesumLabel.text = goal?.capitalSafesum()
self.safesumLabel.textColor = goal?.countdownColor ?? UIColor.Beeminder.gray
self.rateLabel.text = goal?.currentRate
}
}

Expand All @@ -38,6 +40,7 @@ class GoalCollectionViewCell: UICollectionViewCell {
self.contentView.addSubview(self.todaytaLabel)
self.contentView.addSubview(self.thumbnailImageView)
self.contentView.addSubview(self.safesumLabel)
self.contentView.addSubview(self.rateLabel)
self.contentView.backgroundColor = .systemBackground

self.slugLabel.font = UIFont.beeminder.defaultFontHeavy
Expand Down Expand Up @@ -78,7 +81,16 @@ class GoalCollectionViewCell: UICollectionViewCell {
self.safesumLabel.numberOfLines = 0
self.safesumLabel.snp.makeConstraints { (make) -> Void in
make.left.equalTo(self.thumbnailImageView.snp.right).offset(5)
make.centerY.equalTo(self.thumbnailImageView.snp.centerY)
make.centerY.equalTo(self.thumbnailImageView.snp.centerY).offset(-8)
make.right.equalTo(-self.margin)
}

self.rateLabel.textAlignment = .center
self.rateLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
self.rateLabel.numberOfLines = 0
self.rateLabel.snp.makeConstraints { make in
make.left.equalTo(self.thumbnailImageView.snp.right).offset(5)
make.centerY.equalTo(self.thumbnailImageView.snp.centerY).offset(8)
make.right.equalTo(-self.margin)
}
}
Expand Down
18 changes: 17 additions & 1 deletion BeeSwift/GoalViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
fileprivate var submitButton = BSButton()
fileprivate let headerWidth = Double(1.0/3.0)
fileprivate let viewGoalActivityType = "com.beeminder.viewGoal"
private let goalRateLabel = BSLabel()

// date corresponding to the datapoint to be created
private var date: Date = Date()
Expand Down Expand Up @@ -136,12 +137,24 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
make.right.equalTo(self.goalImageScrollView)
}
self.goalImageView.goal = self.goal

self.scrollView.addSubview(goalRateLabel)
self.goalRateLabel.snp.makeConstraints { make in
make.top.equalTo(self.goalImageScrollView.snp.bottom).offset(elementSpacing)
make.height.equalTo(Constants.defaultFontSize)
make.left.equalTo(self.goalImageScrollView).offset(sideMargin)
make.right.equalTo(self.goalImageScrollView).offset(-sideMargin)
}
self.goalRateLabel.textAlignment = .center
self.goalRateLabel.font = UIFont.preferredFont(forTextStyle: .footnote).withSize(Constants.defaultFontSize * 0.9)
self.goalRateLabel.textColor = .label.withAlphaComponent(0.8)


self.addChild(self.datapointTableController)
self.scrollView.addSubview(self.datapointTableController.view)
self.datapointTableController.delegate = self
self.datapointTableController.view.snp.makeConstraints { (make) -> Void in
make.top.equalTo(self.goalImageScrollView.snp.bottom).offset(elementSpacing)
make.top.equalTo(self.goalRateLabel.snp.bottom).offset(elementSpacing)
make.left.equalTo(self.goalImageScrollView).offset(sideMargin)
make.right.equalTo(self.goalImageScrollView).offset(-sideMargin)
}
Expand Down Expand Up @@ -499,6 +512,9 @@ class GoalViewController: UIViewController, UIScrollViewDelegate, DatapointTabl
self.datapointTableController.hhmmformat = goal.hhmmFormat
self.datapointTableController.datapoints = goal.recentData.sorted(by: {$0.updatedAt < $1.updatedAt})

self.goalRateLabel.isHidden = goal.currentRate == nil
self.goalRateLabel.text = goal.currentRate

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