diff --git a/Sources/TripKit/Model/Stop.swift b/Sources/TripKit/Model/Stop.swift index 24aab90..0fb2e2c 100644 --- a/Sources/TripKit/Model/Stop.swift +++ b/Sources/TripKit/Model/Stop.swift @@ -78,7 +78,8 @@ public class Stop: NSObject, NSSecureCoding { predictedTime: aDecoder.decodeObject(of: NSDate.self, forKey: PropertyKey.predictedDepartureTime) as Date?, plannedPlatform: aDecoder.decodeObject(of: NSString.self, forKey: PropertyKey.plannedDeparturePlatform) as String?, predictedPlatform: aDecoder.decodeObject(of: NSString.self, forKey: PropertyKey.predictedDeparturePlatform) as String?, - cancelled: aDecoder.decodeBool(forKey: PropertyKey.departureCancelled) + cancelled: aDecoder.decodeBool(forKey: PropertyKey.departureCancelled), + undefinedDelay: aDecoder.decodeBool(forKey: PropertyKey.departureUndefinedDelay) ) } else { departure = nil @@ -92,7 +93,8 @@ public class Stop: NSObject, NSSecureCoding { predictedTime: aDecoder.decodeObject(of: NSDate.self, forKey: PropertyKey.predictedArrivalTime) as Date?, plannedPlatform: aDecoder.decodeObject(of: NSString.self, forKey: PropertyKey.plannedArrivalPlatform) as String?, predictedPlatform: aDecoder.decodeObject(of: NSString.self, forKey: PropertyKey.predictedArrivalPlatform) as String?, - cancelled: aDecoder.decodeBool(forKey: PropertyKey.arrivalCancelled) + cancelled: aDecoder.decodeBool(forKey: PropertyKey.arrivalCancelled), + undefinedDelay: aDecoder.decodeBool(forKey: PropertyKey.arrivalUndefinedDelay) ) } else { arrival = nil @@ -110,6 +112,7 @@ public class Stop: NSObject, NSSecureCoding { aCoder.encode(departure.plannedPlatform, forKey: PropertyKey.plannedDeparturePlatform) aCoder.encode(departure.predictedPlatform, forKey: PropertyKey.predictedDeparturePlatform) aCoder.encode(departure.cancelled, forKey: PropertyKey.departureCancelled) + aCoder.encode(departure.undefinedDelay, forKey: PropertyKey.departureUndefinedDelay) } if let arrival = arrival { @@ -118,6 +121,7 @@ public class Stop: NSObject, NSSecureCoding { aCoder.encode(arrival.plannedPlatform, forKey: PropertyKey.plannedArrivalPlatform) aCoder.encode(arrival.predictedPlatform, forKey: PropertyKey.predictedArrivalPlatform) aCoder.encode(arrival.cancelled, forKey: PropertyKey.arrivalCancelled) + aCoder.encode(arriva.undefinedDelay, forKey: PropertyKey.arrivalUndefinedDelay) } aCoder.encode(message, forKey: PropertyKey.message) @@ -140,11 +144,13 @@ public class Stop: NSObject, NSSecureCoding { static let plannedArrivalPlatform = "plannedArrivalPlatform" static let predictedArrivalPlatform = "predictedArrivalPlatform" static let arrivalCancelled = "arrivalCancelled" + static let arrivalUndefinedDelay = "arrivalUndefinedDelay" static let plannedDepartureTime = "plannedDepartureTime" static let predictedDepartureTime = "predictedDepartureTime" static let plannedDeparturePlatform = "plannedDeparturePlatform" static let predictedDeparturePlatform = "predictedDeparturePlatform" static let departureCancelled = "departureCancelled" + static let departureUndefinedDelay = "departureUndefinedDelay" static let message = "message" } diff --git a/Sources/TripKit/Model/StopEvent.swift b/Sources/TripKit/Model/StopEvent.swift index b00cefb..6e93b98 100644 --- a/Sources/TripKit/Model/StopEvent.swift +++ b/Sources/TripKit/Model/StopEvent.swift @@ -17,6 +17,8 @@ public class StopEvent: NSObject { public let predictedPlatform: String? /// True if the stop has been planned originally, but is now skipped. public var cancelled: Bool + /// True if the actual delay is unknown. + public var undefinedDelay: Bool /// Predicted time if available, otherwise the planned time. public var time: Date { predictedTime ?? plannedTime } @@ -42,13 +44,14 @@ public class StopEvent: NSObject { return max(plannedTime, predictedTime) } - public init(location: Location, plannedTime: Date, predictedTime: Date?, plannedPlatform: String?, predictedPlatform: String?, cancelled: Bool) { + public init(location: Location, plannedTime: Date, predictedTime: Date?, plannedPlatform: String?, predictedPlatform: String?, cancelled: Bool, undefinedDelay: Bool = false) { self.location = location self.plannedTime = plannedTime self.predictedTime = predictedTime self.plannedPlatform = plannedPlatform self.predictedPlatform = predictedPlatform self.cancelled = cancelled + self.undefinedDelay = undefinedDelay } public override func isEqual(_ other: Any?) -> Bool { diff --git a/Sources/TripKit/Model/Trip.swift b/Sources/TripKit/Model/Trip.swift index 9b94a8a..345c6fd 100644 --- a/Sources/TripKit/Model/Trip.swift +++ b/Sources/TripKit/Model/Trip.swift @@ -71,6 +71,11 @@ public class Trip: NSObject, NSSecureCoding { return Int(predictedArrival.timeIntervalSince(leg.arrivalStop.plannedTime) / 60) != 0 } + /// Returns true if any of the legs have an unknown delay. + public var hasUndefinedDelay: Bool { + return legs.compactMap({$0 as? PublicLeg}).contains(where: {$0.departureStop.undefinedDelay || $0.arrivalStop.undefinedDelay}) + } + /// Returns the earliest departure time. /// /// This may be either the predicted or the planned time, depending on what is smaller. diff --git a/Sources/TripKit/Provider/Implementations/SbbProvider.swift b/Sources/TripKit/Provider/Implementations/SbbProvider.swift index 0f2193f..3c3bcc0 100644 --- a/Sources/TripKit/Provider/Implementations/SbbProvider.swift +++ b/Sources/TripKit/Provider/Implementations/SbbProvider.swift @@ -682,7 +682,7 @@ public class SbbProvider: AbstractNetworkProvider { return Location(type: .station, id: id, coord: coord, place: place, name: name) } - private func gql_parseStop(location: Location, json: JSON, cancelled: Bool) -> StopEvent? { + private func gql_parseStop(location: Location, json: JSON, cancelled: Bool, delayUndefined: Bool) -> StopEvent? { let plannedTime = parseTime(from: json["time"]) let delay = json["delay"].intValue let predictedTime = plannedTime?.addingTimeInterval(TimeInterval(delay * 60)) @@ -693,7 +693,7 @@ public class SbbProvider: AbstractNetworkProvider { let stopEvent: StopEvent? if let plannedTime = plannedTime { - stopEvent = StopEvent(location: location, plannedTime: plannedTime, predictedTime: predictedTime, plannedPlatform: plannedPosition, predictedPlatform: predictedPosition, cancelled: cancelled) + stopEvent = StopEvent(location: location, plannedTime: plannedTime, predictedTime: predictedTime, plannedPlatform: plannedPosition, predictedPlatform: predictedPosition, cancelled: cancelled, undefinedDelay: delayUndefined) } else { stopEvent = nil } @@ -929,11 +929,12 @@ public class SbbProvider: AbstractNetworkProvider { guard let location = gql_parsePlace(json: stopJson["place"]) else { continue } let status = stopJson["stopStatus"].string - let statusMessage = stopJson["stopStatusFormatted"].string + let statusMessage = Set([stopJson["stopStatusFormatted"].string, stopJson["departure", "delayText"].string, stopJson["arrival", "delayText"].string].compactMap({$0})).joined(separator: ". ") let forBoarding = stopJson["forBoarding"].boolValue let forAlighting = stopJson["forAlighting"].boolValue let isFirst = index == 0 let isLast = index == jsonStopPoints.count - 1 + let delayUndefined = stopJson["delayUndefined"].boolValue var cancelled = status == "CANCELLED" || status == "NOT_SERVICED" if (status == "END_PARTIAL_CANCELLATION" || !forAlighting) && isLast { cancelled = true @@ -943,8 +944,8 @@ public class SbbProvider: AbstractNetworkProvider { cancelled = true } - let departure = gql_parseStop(location: location, json: stopJson["departure"], cancelled: cancelled) - let arrival = gql_parseStop(location: location, json: stopJson["arrival"], cancelled: cancelled) + let departure = gql_parseStop(location: location, json: stopJson["departure"], cancelled: cancelled, delayUndefined: delayUndefined) + let arrival = gql_parseStop(location: location, json: stopJson["arrival"], cancelled: cancelled, delayUndefined: delayUndefined) let loadFactor = parseLoadFactor(from: stopJson["occupancy", "\(occupancyClass)Class"]) if let loadFactor = loadFactor, maxOccupancy == nil || loadFactor.rawValue < maxOccupancy!.rawValue {