From 37ffba7dd854db6d83b20ddcc1098934327f1d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20S=C3=B8rensen?= Date: Wed, 12 Oct 2022 19:14:01 +0200 Subject: [PATCH] Use Foundation.TimeInterval for durations --- .../FitWorkoutDecoder/FitWorkoutDecoder.swift | 6 +++--- .../WorkoutDecoderBase/WorkoutDecoding.swift | 16 +++++++-------- .../ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift | 20 +++++++++---------- .../Resources/workout1.zwo | 2 +- .../WorkoutDecodersTests.swift | 12 +++++------ 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Sources/FitWorkoutDecoder/FitWorkoutDecoder.swift b/Sources/FitWorkoutDecoder/FitWorkoutDecoder.swift index 360f058..99df2dc 100644 --- a/Sources/FitWorkoutDecoder/FitWorkoutDecoder.swift +++ b/Sources/FitWorkoutDecoder/FitWorkoutDecoder.swift @@ -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 diff --git a/Sources/WorkoutDecoderBase/WorkoutDecoding.swift b/Sources/WorkoutDecoderBase/WorkoutDecoding.swift index a0bb4ca..d8a06c3 100644 --- a/Sources/WorkoutDecoderBase/WorkoutDecoding.swift +++ b/Sources/WorkoutDecoderBase/WorkoutDecoding.swift @@ -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 { @@ -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 @@ -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 } @@ -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]) { diff --git a/Sources/ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift b/Sources/ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift index 9640bd1..cde534b 100644 --- a/Sources/ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift +++ b/Sources/ZwoWorkoutDecoder/ZwoWorkoutDecoder.swift @@ -23,23 +23,23 @@ 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) @@ -47,15 +47,15 @@ public final class ZwoWorkoutDecoder: WorkoutDecoding { } ?? [] // 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) } @@ -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) diff --git a/Tests/WorkoutDecodersTests/Resources/workout1.zwo b/Tests/WorkoutDecodersTests/Resources/workout1.zwo index 5e34235..e05de4f 100644 --- a/Tests/WorkoutDecodersTests/Resources/workout1.zwo +++ b/Tests/WorkoutDecodersTests/Resources/workout1.zwo @@ -8,7 +8,7 @@ - + diff --git a/Tests/WorkoutDecodersTests/WorkoutDecodersTests.swift b/Tests/WorkoutDecodersTests/WorkoutDecodersTests.swift index 1fe6406..e8245e8 100644 --- a/Tests/WorkoutDecodersTests/WorkoutDecodersTests.swift +++ b/Tests/WorkoutDecodersTests/WorkoutDecodersTests.swift @@ -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 @@ -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") ]) }