Skip to content
Open
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
6 changes: 3 additions & 3 deletions Sources/FitWorkoutDecoder/FitWorkoutDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ public final class FitWorkoutDecoder: WorkoutDecoding {
switch stepsDistance {
case 0:
let workoutStep = workoutSteps[repeatStep.range.lowerBound]
return WorkoutPart.steady(duration: workoutStep.duration, power: workoutStep.power(for: userFtp),
return WorkoutPart.steady(duration: TimeInterval(workoutStep.duration), power: workoutStep.power(for: userFtp),
cadence: nil)
case 1:
let firstWorkoutStep = workoutSteps[repeatStep.range.lowerBound]
let secondWorkoutStep = workoutSteps[repeatStep.range.upperBound]
return WorkoutPart.intervals(repeat: repeatStep.repeatCount,
onDuration: firstWorkoutStep.duration, onPower: firstWorkoutStep.power(for: userFtp),
offDuration: secondWorkoutStep.duration, offPower: secondWorkoutStep.power(for: userFtp),
onDuration: TimeInterval(firstWorkoutStep.duration), onPower: firstWorkoutStep.power(for: userFtp),
offDuration: TimeInterval(secondWorkoutStep.duration), offPower: secondWorkoutStep.power(for: userFtp),
cadence: nil)
default:
throw FitDecodeError.notSupportedRange
Expand Down
16 changes: 8 additions & 8 deletions Sources/WorkoutDecoderBase/WorkoutDecoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public protocol WorkoutDecoding {
}

public enum WorkoutPart {
case steady(duration: Int, power: Double, cadence: String?)
case intervals(repeat: Int, onDuration: Int, onPower: Double, offDuration: Int, offPower: Double, cadence: String?)
case ramp(duration: Int, powerLow: Double, powerHigh: Double, cadence: String?)
case freeRide(duration: Int, cadence: String?)
case steady(duration: TimeInterval, power: Double, cadence: String?)
case intervals(repeat: Int, onDuration: TimeInterval, onPower: Double, offDuration: TimeInterval, offPower: Double, cadence: String?)
case ramp(duration: TimeInterval, powerLow: Double, powerHigh: Double, cadence: String?)
case freeRide(duration: TimeInterval, cadence: String?)

public func toSegments(startIndex: Int) -> [WorkoutSegment] {
switch self {
Expand Down Expand Up @@ -44,7 +44,7 @@ public enum WorkoutPart {
}

public struct WorkoutSegment: Codable, Equatable {
public let duration: Int
public let duration: TimeInterval
public let index: Int
public let intervalIndex: Int?
public let powerStart: Double // negative power means free ride
Expand All @@ -63,10 +63,10 @@ public struct WorkoutSegment: Codable, Equatable {
}

public struct WorkoutMessage: Codable, Equatable {
public let timeOffset: Int
public let timeOffset: TimeInterval
public let message: String

public init(timeOffset: Int, message: String) {
public init(timeOffset: TimeInterval, message: String) {
self.timeOffset = timeOffset
self.message = message
}
Expand All @@ -75,7 +75,7 @@ public struct WorkoutMessage: Codable, Equatable {
public struct Workout: Codable {
public let name: String
public let segments: [WorkoutSegment]
public let duration: Int
public let duration: TimeInterval
public let messages: [WorkoutMessage]

public init(name: String, parts: [WorkoutPart], messages: [WorkoutMessage]) {
Expand Down
20 changes: 10 additions & 10 deletions Sources/ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,39 @@ public final class ZwoWorkoutDecoder: WorkoutDecoding {
let cadence = attributes["Cadence"]
switch part.name {
case "SteadyState":
return WorkoutPart.steady(duration: attributes.int("Duration"),
return WorkoutPart.steady(duration: attributes.double("Duration"),
power: attributes.double("Power"),
cadence: cadence)
case "IntervalsT":
return WorkoutPart.intervals(repeat: attributes.int("Repeat"),
onDuration: attributes.int("OnDuration"),
onDuration: attributes.double("OnDuration"),
onPower: attributes.double("OnPower"),
offDuration: attributes.int("OffDuration"),
offDuration: attributes.double("OffDuration"),
offPower: attributes.double("OffPower"),
cadence: cadence)
case "Warmup", "Cooldown", "Ramp":
return WorkoutPart.ramp(duration: attributes.int("Duration"),
return WorkoutPart.ramp(duration: attributes.double("Duration"),
powerLow: attributes.double("PowerLow"),
powerHigh: attributes.double("PowerHigh"),
cadence: cadence)
case "FreeRide":
return WorkoutPart.freeRide(duration: attributes.int("Duration"),
return WorkoutPart.freeRide(duration: attributes.double("Duration"),
cadence: cadence)
default:
throw WorkoutDecodeError.unknownElement(name: part.name)
}
} ?? []

// each part duration and messages with time offset per WorkoutPart
let messages = try workout["workout"].element?.childElements.map { part -> (Int, [WorkoutMessage]) in
let messages = try workout["workout"].element?.childElements.map { part -> (TimeInterval, [WorkoutMessage]) in
let attributes = part.attributes

let duration: Int
let duration: TimeInterval
switch part.name {
case "SteadyState", "Warmup", "Cooldown", "Ramp", "FreeRide":
duration = attributes.int("Duration")
duration = attributes.double("Duration")
case "IntervalsT":
duration = (attributes.int("OnDuration") + attributes.int("OffDuration")) * attributes.int("Repeat")
duration = (attributes.double("OnDuration") + attributes.double("OffDuration")) * Double(attributes.int("Repeat"))
default:
throw WorkoutDecodeError.unknownElement(name: part.name)
}
Expand All @@ -64,7 +64,7 @@ public final class ZwoWorkoutDecoder: WorkoutDecoding {
$0.name == "textevent"
}.map { message -> WorkoutMessage in
let attributes = message.attributes
return WorkoutMessage(timeOffset: attributes.int("timeoffset"), message: attributes["message"] ?? "")
return WorkoutMessage(timeOffset: attributes.double("timeoffset"), message: attributes["message"] ?? "")
}

return (duration, messages)
Expand Down
2 changes: 1 addition & 1 deletion Tests/WorkoutDecodersTests/Resources/workout1.zwo
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Warmup Duration="10" PowerLow="0.5" PowerHigh="0.55">
<textevent timeoffset="0" message="Starting message"/>
</Warmup>
<SteadyState Duration="5" Power="0.4" Cadence="100"/>
<SteadyState Duration="5.00002" Power="0.4" Cadence="100"/>
<FreeRide Duration="100" Cadence="90"/>
<SteadyState Duration="10" Power="0.5">
<textevent timeoffset="5" message="Should be at offset 120"/>
Expand Down
12 changes: 6 additions & 6 deletions Tests/WorkoutDecodersTests/WorkoutDecodersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class WorkoutDecodersTests: XCTestCase {

XCTAssertEqual(workout.segments, [
WorkoutSegment(duration: 10, index: 0, intervalIndex: nil, powerStart: 0.5, powerEnd: 0.55, cadence: nil),
WorkoutSegment(duration: 5, index: 1, intervalIndex: nil, powerStart: 0.4, powerEnd: nil, cadence: "100"),
WorkoutSegment(duration: 5.00002, index: 1, intervalIndex: nil, powerStart: 0.4, powerEnd: nil, cadence: "100"),
WorkoutSegment(duration: 100, index: 2, intervalIndex: nil, powerStart: -1, powerEnd: nil, cadence: "90"), // free ride
WorkoutSegment(duration: 10, index: 3, intervalIndex: nil, powerStart: 0.5, powerEnd: nil, cadence: nil),
// interval start, repeat 3
Expand All @@ -37,11 +37,11 @@ final class WorkoutDecodersTests: XCTestCase {
let workout = decodedWorkout()

XCTAssertEqual(workout.messages, [
WorkoutMessage(timeOffset: 0, message: "Starting message"),
WorkoutMessage(timeOffset: 120, message: "Should be at offset 120"),
WorkoutMessage(timeOffset: 125, message: "Start interval message"),
WorkoutMessage(timeOffset: 175, message: "Near end interval message"),
WorkoutMessage(timeOffset: 187, message: "Last segment message")
WorkoutMessage(timeOffset: 0.0, message: "Starting message"),
WorkoutMessage(timeOffset: 120.00002, message: "Should be at offset 120"),
WorkoutMessage(timeOffset: 125.00002, message: "Start interval message"),
WorkoutMessage(timeOffset: 175.00002, message: "Near end interval message"),
WorkoutMessage(timeOffset: 187.00002, message: "Last segment message")
])
}

Expand Down