Skip to content

Commit 57c7e59

Browse files
committed
- Display and export weather data: temperature and humidity (fixes #20)
1 parent f0ae89f commit 57c7e59

File tree

9 files changed

+140
-68
lines changed

9 files changed

+140
-68
lines changed

Podfile.lock

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
11
PODS:
2-
- Google-Mobile-Ads-SDK (7.53.1):
2+
- Google-Mobile-Ads-SDK (7.60.0):
33
- GoogleAppMeasurement (~> 6.0)
4-
- GoogleAppMeasurement (6.1.7):
4+
- GoogleAppMeasurement (6.5.1):
55
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
66
- GoogleUtilities/MethodSwizzler (~> 6.0)
77
- GoogleUtilities/Network (~> 6.0)
88
- "GoogleUtilities/NSData+zlib (~> 6.0)"
9-
- nanopb (= 0.3.9011)
10-
- GoogleUtilities/AppDelegateSwizzler (6.4.0):
9+
- nanopb (~> 1.30905.0)
10+
- GoogleUtilities/AppDelegateSwizzler (6.6.0):
1111
- GoogleUtilities/Environment
1212
- GoogleUtilities/Logger
1313
- GoogleUtilities/Network
14-
- GoogleUtilities/Environment (6.4.0)
15-
- GoogleUtilities/Logger (6.4.0):
14+
- GoogleUtilities/Environment (6.6.0):
15+
- PromisesObjC (~> 1.2)
16+
- GoogleUtilities/Logger (6.6.0):
1617
- GoogleUtilities/Environment
17-
- GoogleUtilities/MethodSwizzler (6.4.0):
18+
- GoogleUtilities/MethodSwizzler (6.6.0):
1819
- GoogleUtilities/Logger
19-
- GoogleUtilities/Network (6.4.0):
20+
- GoogleUtilities/Network (6.6.0):
2021
- GoogleUtilities/Logger
2122
- "GoogleUtilities/NSData+zlib"
2223
- GoogleUtilities/Reachability
23-
- "GoogleUtilities/NSData+zlib (6.4.0)"
24-
- GoogleUtilities/Reachability (6.4.0):
24+
- "GoogleUtilities/NSData+zlib (6.6.0)"
25+
- GoogleUtilities/Reachability (6.6.0):
2526
- GoogleUtilities/Logger
26-
- nanopb (0.3.9011):
27-
- nanopb/decode (= 0.3.9011)
28-
- nanopb/encode (= 0.3.9011)
29-
- nanopb/decode (0.3.9011)
30-
- nanopb/encode (0.3.9011)
31-
- PersonalizedAdConsent (1.0.4)
27+
- nanopb (1.30905.0):
28+
- nanopb/decode (= 1.30905.0)
29+
- nanopb/encode (= 1.30905.0)
30+
- nanopb/decode (1.30905.0)
31+
- nanopb/encode (1.30905.0)
32+
- PersonalizedAdConsent (1.0.5)
33+
- PromisesObjC (1.2.8)
3234

3335
DEPENDENCIES:
3436
- Google-Mobile-Ads-SDK
@@ -41,14 +43,16 @@ SPEC REPOS:
4143
- GoogleUtilities
4244
- nanopb
4345
- PersonalizedAdConsent
46+
- PromisesObjC
4447

4548
SPEC CHECKSUMS:
46-
Google-Mobile-Ads-SDK: fac081606dbd438d8db57198b83ba8b5f875a601
47-
GoogleAppMeasurement: db118eb61a97dd8c4f7014e368d3c335cbbcf80a
48-
GoogleUtilities: 29bd0d8f850efbd28cff6d99e8b7da1f8d236bcf
49-
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
50-
PersonalizedAdConsent: 4b87320b7a0f22576bec530ae3b7adba88a24c78
49+
Google-Mobile-Ads-SDK: d70efb31e7ea19fe99d466dc5d4788966b6914f8
50+
GoogleAppMeasurement: 137afe68bfa406c3f4221b9395253d9e5d4654cf
51+
GoogleUtilities: 39530bc0ad980530298e9c4af8549e991fd033b1
52+
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
53+
PersonalizedAdConsent: dbecabb3467df967c16d9cebc2ef4a8890e4bbd8
54+
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
5155

5256
PODFILE CHECKSUM: 0a3ad6eec838428d85e01e854381b78b9d11267d
5357

54-
COCOAPODS: 1.8.4
58+
COCOAPODS: 1.9.2

Workout Core/Model/Support/WorkoutUnit.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class WorkoutUnit {
3333
}
3434

3535
func `is`(compatibleWith unit: HKUnit) -> Bool {
36-
return HKQuantity(unit: self.default, doubleValue: 1).is(compatibleWith: unit)
36+
return self.default.is(compatibleWith: unit)
3737
}
3838

3939
func `is`(compatibleWith unit: WorkoutUnit) -> Bool {
@@ -65,14 +65,15 @@ public class WorkoutUnit {
6565
public static let meter = WorkoutUnit(.meter())
6666
public static let meterAndYard = WorkoutUnit(units: [.metric: .meter(), .imperial: .yard()])
6767
public static let kilometerAndMile = WorkoutUnit(units: [.metric: .meterUnit(with: .kilo), .imperial: .mile()])
68-
public static let elevation = WorkoutUnit(units: [.metric : .meter(), .imperial: .foot()])
68+
public static let elevation = WorkoutUnit(units: [.metric: .meter(), .imperial: .foot()])
6969

7070
public static let kilometerAndMilePerHour = kilometerAndMile.divided(by: HKUnit.hour())
7171

7272
public static let calories = WorkoutUnit(.kilocalorie())
73+
public static let temperature = WorkoutUnit(units: [.metric: .degreeCelsius(), .imperial: .degreeFahrenheit()])
74+
public static let percentage = WorkoutUnit(.percent())
7375

7476
public static let heartRate = WorkoutUnit(HKUnit.count().unitDivided(by: HKUnit.minute()))
75-
7677
public static let steps = WorkoutUnit(HKUnit.count())
7778
public static let strokes = WorkoutUnit(HKUnit.count())
7879

Workout Core/Model/Workout/Additional Data/Support/MinuteByMinuteBreakdown/WorkoutDetail.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class WorkoutDetail {
100100
})
101101

102102
/// Provides the average speed.
103-
static let speed = WorkoutDetail(name: "Speed", unitFormatter: { $0.speedUnit.unit(for: $1).description }, valueFormatter: { (m, s) in
103+
static let speed = WorkoutDetail(name: "Speed", unitFormatter: { $0.speedUnit.unit(for: $1).symbol }, valueFormatter: { (m, s) in
104104
guard let speed = m.speed else {
105105
return nil
106106
}

Workout Core/Model/Workout/Workout.swift

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,15 @@ public class Workout {
160160
}
161161
}
162162

163+
/// The weather temperature during the workout.
164+
public var weatherTemperature: HKQuantity? {
165+
raw.metadata?[HKMetadataKeyWeatherTemperature] as? HKQuantity
166+
}
167+
/// The weather humidity during the workout.
168+
public var weatherHumidity: HKQuantity? {
169+
raw.metadata?[HKMetadataKeyWeatherHumidity] as? HKQuantity
170+
}
171+
163172
private var rawStart: TimeInterval {
164173
return raw.startDate.timeIntervalSince1970
165174
}
@@ -432,7 +441,9 @@ public class Workout {
432441
activeEnergy?.formatAsEnergy(withUnit: WorkoutUnit.calories.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? "",
433442
totalEnergy?.formatAsEnergy(withUnit: WorkoutUnit.calories.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? "",
434443
elevationChange.ascended?.formatAsElevationChange(withUnit: WorkoutUnit.elevation.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? "",
435-
elevationChange.descended?.formatAsElevationChange(withUnit: WorkoutUnit.elevation.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? ""
444+
elevationChange.descended?.formatAsElevationChange(withUnit: WorkoutUnit.elevation.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? "",
445+
weatherTemperature?.formatAsTemperature(withUnit: WorkoutUnit.temperature.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? "",
446+
weatherHumidity?.formatAsPercentage(withUnit: WorkoutUnit.percentage.unit(for: systemOfUnits), rawFormat: true).toCSV() ?? ""
436447
]
437448
}
438449

@@ -472,15 +483,17 @@ public class Workout {
472483
try file.write("Start\(sep)" + genData[1] + "\n")
473484
try file.write("End\(sep)" + genData[2] + "\n")
474485
try file.write("Duration\(sep)" + genData[3] + "\n")
475-
try file.write("\("Distance \(self.distanceUnit.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[4] + "\n")
486+
try file.write("\("Distance \(self.distanceUnit.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[4] + "\n")
476487
try file.write("\("Average Heart Rate".toCSV())\(sep)" + genData[5] + "\n")
477488
try file.write("\("Max Heart Rate".toCSV())\(sep)" + genData[6] + "\n")
478-
try file.write("\("Average Pace time/\(self.paceUnit.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[7] + "\n")
479-
try file.write("\("Average Speed \(self.speedUnit.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[8] + "\n")
480-
try file.write("\("Active Energy \(WorkoutUnit.calories.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[9] + "\n")
481-
try file.write("\("Total Energy \(WorkoutUnit.calories.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[10] + "\n")
482-
try file.write("\("Elevation Ascended \(WorkoutUnit.elevation.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[11] + "\n")
483-
try file.write("\("Elevation Descended \(WorkoutUnit.elevation.unit(for: systemOfUnits).description)".toCSV())\(sep)" + genData[12] + "\n")
489+
try file.write("\("Average Pace time/\(self.paceUnit.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[7] + "\n")
490+
try file.write("\("Average Speed \(self.speedUnit.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[8] + "\n")
491+
try file.write("\("Active Energy \(WorkoutUnit.calories.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[9] + "\n")
492+
try file.write("\("Total Energy \(WorkoutUnit.calories.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[10] + "\n")
493+
try file.write("\("Elevation Ascended \(WorkoutUnit.elevation.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[11] + "\n")
494+
try file.write("\("Elevation Descended \(WorkoutUnit.elevation.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[12] + "\n")
495+
try file.write("\("Weather Temperature \(WorkoutUnit.temperature.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[13] + "\n")
496+
try file.write("\("Weather Humidity \(WorkoutUnit.percentage.unit(for: systemOfUnits).symbol)".toCSV())\(sep)" + genData[14] + "\n")
484497
} catch {
485498
callback(nil)
486499
return

Workout Core/Model/WorkoutBulkExporter.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public class WorkoutBulkExporter: WorkoutDelegate {
115115
// Prepare the file with the header
116116
do {
117117
let sep = CSVSeparator
118-
let header = "Type\(sep)Start\(sep)End\(sep)Duration\(sep)Distance\(sep)\("Average Heart Rate".toCSV())\(sep)\("Max Heart Rate".toCSV())\(sep)\("Average Pace".toCSV())\(sep)\("Average Speed".toCSV())\(sep)\("Active Energy".toCSV())\(sep)\("Total Energy".toCSV())\(sep)\("Elevation Ascended".toCSV())\(sep)\("Elevation Descended".toCSV())\n"
118+
let header = "Type\(sep)Start\(sep)End\(sep)Duration\(sep)Distance\(sep)\("Average Heart Rate".toCSV())\(sep)\("Max Heart Rate".toCSV())\(sep)\("Average Pace".toCSV())\(sep)\("Average Speed".toCSV())\(sep)\("Active Energy".toCSV())\(sep)\("Total Energy".toCSV())\(sep)\("Elevation Ascended".toCSV())\(sep)\("Elevation Descended".toCSV())\(sep)Weather Temperature\(sep)Weather Humidity\n"
119119

120120
try fileStream.write(header)
121121
} catch {
@@ -131,7 +131,7 @@ public class WorkoutBulkExporter: WorkoutDelegate {
131131
)
132132
toBeExported = Float(wrkts.count)
133133

134-
// Load firt batch
134+
// Load first batch
135135
loading = wrkts.prefix(maximumConcurrentLoad).map { w in
136136
// Avoid loading additional (and useless) detail
137137
w.load(quickly: true)

Workout Core/Support/Extensions.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ extension HKQuantity: Comparable {
7777
if rawFormat {
7878
return value.toString()
7979
} else {
80-
return distanceF.string(from: NSNumber(value: value))! + " \(unit.description)"
80+
return distanceF.string(from: NSNumber(value: value))! + " \(unit.symbol)"
8181
}
8282
}
8383

@@ -89,7 +89,7 @@ extension HKQuantity: Comparable {
8989
if rawFormat {
9090
return value.toString()
9191
} else {
92-
return integerF.string(from: NSNumber(value: value))! + " \(unit.description)"
92+
return integerF.string(from: NSNumber(value: value))! + " \(unit.symbol)"
9393
}
9494
}
9595

@@ -101,7 +101,7 @@ extension HKQuantity: Comparable {
101101
if rawFormat {
102102
return value.rawDuration()
103103
} else {
104-
return "\(value.formattedDuration)/\(lUnit.description)"
104+
return "\(value.formattedDuration)/\(lUnit.symbol)"
105105
}
106106
}
107107

@@ -125,7 +125,7 @@ extension HKQuantity: Comparable {
125125
if rawFormat {
126126
return value.toString()
127127
} else {
128-
return speedF.string(from: NSNumber(value: value))! + " \(unit.description)"
128+
return speedF.string(from: NSNumber(value: value))! + " \(unit.symbol)"
129129
}
130130
}
131131

@@ -137,14 +137,53 @@ extension HKQuantity: Comparable {
137137
if rawFormat {
138138
return value.toString()
139139
} else {
140-
return integerF.string(from: NSNumber(value: value))! + " \(unit.description)"
140+
return integerF.string(from: NSNumber(value: value))! + " \(unit.symbol)"
141+
}
142+
}
143+
144+
/// Considers the receiver a temperature and formats it accordingly.
145+
/// - parameter unit: The temperature unit to use in formatting.
146+
/// - returns: The formatted value.
147+
public func formatAsTemperature(withUnit unit: HKUnit, rawFormat: Bool = false) -> String {
148+
let value = self.doubleValue(for: unit)
149+
if rawFormat {
150+
return value.toString()
151+
} else {
152+
return integerF.string(from: NSNumber(value: value))! + "\(unit.symbol)"
153+
}
154+
}
155+
156+
/// Considers the receiver a percentage and formats it accordingly.
157+
/// - parameter unit: The percentage unit to use in formatting.
158+
/// - returns: The formatted value.
159+
public func formatAsPercentage(withUnit unit: HKUnit, rawFormat: Bool = false) -> String {
160+
let value = self.doubleValue(for: unit)
161+
if rawFormat {
162+
return value.toString()
163+
} else {
164+
return integerF.string(from: NSNumber(value: value))! + " \(unit.symbol)"
141165
}
142166
}
143167

144168
}
145169

146170
extension HKUnit {
147171

172+
func `is`(compatibleWith unit: HKUnit) -> Bool {
173+
return HKQuantity(unit: self, doubleValue: 1).is(compatibleWith: unit)
174+
}
175+
176+
/// A human readable symbol representing the unit.
177+
public var symbol: String {
178+
var symbol = self.description
179+
if self.is(compatibleWith: .degreeCelsius()) && symbol.starts(with: "deg") {
180+
// Simplify temperature symbols
181+
symbol = "°\(symbol[3...])"
182+
}
183+
184+
return symbol
185+
}
186+
148187
static let meterPerSecond = HKUnit.meter().unitDivided(by: .second())
149188

150189
static let secondPerMeter = HKUnit.second().unitDivided(by: .meter())

Workout.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,7 @@
991991
CLANG_WARN_UNREACHABLE_CODE = YES;
992992
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
993993
COPY_PHASE_STRIP = NO;
994-
CURRENT_PROJECT_VERSION = 24;
994+
CURRENT_PROJECT_VERSION = 25;
995995
DEBUG_INFORMATION_FORMAT = dwarf;
996996
ENABLE_STRICT_OBJC_MSGSEND = YES;
997997
ENABLE_TESTABILITY = YES;
@@ -1010,7 +1010,7 @@
10101010
GCC_WARN_UNUSED_FUNCTION = YES;
10111011
GCC_WARN_UNUSED_VARIABLE = YES;
10121012
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
1013-
MARKETING_VERSION = 1.8;
1013+
MARKETING_VERSION = 1.9;
10141014
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
10151015
MTL_FAST_MATH = YES;
10161016
ONLY_ACTIVE_ARCH = YES;
@@ -1055,7 +1055,7 @@
10551055
CLANG_WARN_UNREACHABLE_CODE = YES;
10561056
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
10571057
COPY_PHASE_STRIP = NO;
1058-
CURRENT_PROJECT_VERSION = 24;
1058+
CURRENT_PROJECT_VERSION = 25;
10591059
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
10601060
ENABLE_NS_ASSERTIONS = NO;
10611061
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -1068,7 +1068,7 @@
10681068
GCC_WARN_UNUSED_FUNCTION = YES;
10691069
GCC_WARN_UNUSED_VARIABLE = YES;
10701070
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
1071-
MARKETING_VERSION = 1.8;
1071+
MARKETING_VERSION = 1.9;
10721072
MTL_ENABLE_DEBUG_INFO = NO;
10731073
MTL_FAST_MATH = YES;
10741074
SDKROOT = iphoneos;

Workout/Base.lproj/Localizable.strings

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
"WRKT_AVG_SPEED" = "Average Speed";
5454
"WRKT_ENERGY" = "Energy";
5555
"WRKT_ELEVATION" = "Elevation Change";
56+
"WRKT_WEATHER_TEMPERATURE" = "Weather Temperature";
57+
"WRKT_WEATHER_HUMIDITY" = "Weather Humidity";
5658

5759
"WRKT_SPLIT_CAL_%@_TOTAL_%@" = "%@ (%@ total)";
5860

0 commit comments

Comments
 (0)