Skip to content

Commit

Permalink
fix: Changes based on PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
EmmaSimon committed Apr 4, 2024
1 parent 00d2205 commit f71b68b
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 109 deletions.
8 changes: 4 additions & 4 deletions iosApp/iosApp/Pages/Map/StopIcons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ enum StopIcons {
.expression(
Exp(.match) {
Exp(.get) { StopSourceGenerator.propServiceStatusKey }
String(describing: StopSourceServiceStatus.noService)
String(describing: StopServiceStatus.noService)
stationIconNoServiceId
String(describing: StopSourceServiceStatus.disrupted)
String(describing: StopServiceStatus.partialService)
stationIconIssuesId
stationIconId
}
Expand All @@ -46,9 +46,9 @@ enum StopIcons {
tombstoneZoomThreshold
Exp(.match) {
Exp(.get) { StopSourceGenerator.propServiceStatusKey }
String(describing: StopSourceServiceStatus.noService)
String(describing: StopServiceStatus.noService)
stopIconNoServiceId
String(describing: StopSourceServiceStatus.disrupted)
String(describing: StopServiceStatus.partialService)
stopIconIssuesId
stopIconId
}
Expand Down
16 changes: 2 additions & 14 deletions iosApp/iosApp/Pages/Map/StopSourceGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ struct StopFeatureData {
let feature: Feature
}

enum StopSourceServiceStatus {
case normal
case disrupted
case noService
}

class StopSourceGenerator {
let stops: [String: Stop]
let routeSourceDetails: [RouteSourceData]?
Expand Down Expand Up @@ -105,13 +99,7 @@ class StopSourceGenerator {
}
}

func getServiceStatus(stop: Stop) -> StopSourceServiceStatus {
guard let alertsAtStop = alertsByStop[stop.id] else { return StopSourceServiceStatus.normal }
if alertsAtStop.hasNoService {
return StopSourceServiceStatus.noService
} else if alertsAtStop.hasSomeDisruptedService {
return StopSourceServiceStatus.disrupted
}
return StopSourceServiceStatus.normal
func getServiceStatus(stop: Stop) -> StopServiceStatus {
alertsByStop[stop.id]?.serviceStatus ?? StopServiceStatus.normal
}
}
Original file line number Diff line number Diff line change
@@ -1,48 +1,103 @@
package com.mbta.tid.mbta_app.model

private val disruptableStopTypes: List<LocationType> =
listOf(LocationType.STOP, LocationType.STATION)

class AlertAssociatedStop(
val stop: Stop,
val relevantAlerts: Set<Alert>,
val routePatterns: List<RoutePattern>,
val childStops: Map<String, Stop>,
val relevantAlerts: List<Alert>,
val serviceAlerts: List<Alert>,
val childAlerts: Map<String, AlertAssociatedStop>,
val serviceStatus: StopServiceStatus
) {
val serviceAlerts = relevantAlerts.filter { Alert.serviceDisruptionEffects.contains(it.effect) }
constructor(
stop: Stop,
relevantAlerts: List<Alert>,
routePatterns: List<RoutePattern>,
childStops: Map<String, Stop>,
childAlerts: Map<String, AlertAssociatedStop>
) : this(
stop,
relevantAlerts,
getServiceAlerts(relevantAlerts),
childAlerts,
getServiceStatus(
stop,
getServiceAlerts(relevantAlerts),
routePatterns,
childStops,
childAlerts
)
)
}

enum class StopServiceStatus {
NORMAL,
NO_SERVICE,
PARTIAL_SERVICE
}

private fun entityMatcher(
entity: Alert.InformedEntity,
stop: Stop,
pattern: RoutePattern
): Boolean {
return entity.appliesTo(
stopId = stop.id,
routeId = pattern.routeId,
directionId = pattern.directionId
)
}

private fun getDisruptableChildren(childStops: Map<String, Stop>): List<Stop> {
return childStops.values.filter {
listOf(LocationType.STOP, LocationType.STATION).contains(it.locationType)
}
}

var hasNoService: Boolean =
private fun getServiceAlerts(alerts: List<Alert>): List<Alert> {
return alerts.filter { Alert.serviceDisruptionEffects.contains(it.effect) }
}

private fun getServiceStatus(
stop: Stop,
serviceAlerts: List<Alert>,
routePatterns: List<RoutePattern>,
childStops: Map<String, Stop>,
childAlerts: Map<String, AlertAssociatedStop>
): StopServiceStatus {
val children = getDisruptableChildren(childStops)

val hasNoService =
if (routePatterns.isEmpty()) {
// No route patterns and every child station/stop has no service
childStops.isNotEmpty() &&
childStops.values
.filter { disruptableStopTypes.contains(it.locationType) }
.all { childAlerts[it.id]?.hasNoService == true }
childStops.isNotEmpty() && children.all { hasNoService(it, childAlerts) }
} else {
// All route patterns and child stations/stops have no service
routePatterns.all { pattern ->
serviceAlerts.any { alert ->
alert.anyInformedEntity { entityMatcher(it, stop, pattern) }
}
} &&
childStops.values
.filter { disruptableStopTypes.contains(it.locationType) }
.all { childAlerts[it.id]?.hasNoService == true }
routePatterns.all { isDisruptedPattern(it, stop, serviceAlerts) } &&
children.all { hasNoService(it, childAlerts) }
}
if (hasNoService) {
return StopServiceStatus.NO_SERVICE
}

val hasSomeDisruptedService: Boolean =
routePatterns.any { isDisruptedPattern(it, stop, serviceAlerts) } ||
children.any { hasNoService(it, childAlerts) }
if (hasSomeDisruptedService) {
return StopServiceStatus.PARTIAL_SERVICE
}

var hasSomeDisruptedService: Boolean =
routePatterns.any { pattern ->
serviceAlerts.any { alert ->
alert.anyInformedEntity { entityMatcher(it, stop, pattern) }
}
} || stop.childStopIds?.any { childAlerts[it]?.hasSomeDisruptedService == true } == true
return StopServiceStatus.NORMAL
}

private fun entityMatcher(
entity: Alert.InformedEntity,
stop: Stop,
pattern: RoutePattern
): Boolean {
return entity.appliesTo(stopId = stop.id, routeId = pattern.routeId)
private fun hasNoService(stop: Stop, alerts: Map<String, AlertAssociatedStop>): Boolean {
return alerts[stop.id]?.serviceStatus == StopServiceStatus.NO_SERVICE
}

private fun isDisruptedPattern(
pattern: RoutePattern,
stop: Stop,
serviceAlerts: List<Alert>
): Boolean {
return serviceAlerts.any { alert ->
alert.anyInformedEntity { entityMatcher(it, stop, pattern) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import com.mbta.tid.mbta_app.model.response.GlobalResponse
import kotlinx.datetime.Instant

data class GlobalStaticData(val globalData: GlobalResponse) {

/*
Only stops that don't have a parent stop (stations and isolated stops) are returned in the map.
Each AlertAssociatedStop will have entries in childAlerts if there are any active alerts on
their children, but those child alerts aren't included in the map returned by this function.
*/
fun withRealtimeAlertsByStop(
alerts: AlertsStreamDataResponse?,
filterAtTime: Instant
Expand Down Expand Up @@ -45,20 +51,18 @@ data class GlobalStaticData(val globalData: GlobalResponse) {
val alertingStop =
AlertAssociatedStop(
stop = stop,
relevantAlerts = alertsByStop[stop.id]?.toSet() ?: emptySet(),
relevantAlerts = alertsByStop[stop.id]?.toList() ?: emptyList(),
routePatterns = getRoutePatternsFor(stop.id),
childStops =
stop.childStopIds
?.mapNotNull { childId -> globalData.stops[childId] }
?.associateBy { it.id }
?: emptyMap(),
.mapNotNull { childId -> globalData.stops[childId] }
.associateBy { it.id },
childAlerts =
stop.childStopIds
?.mapNotNull { childId ->
.mapNotNull { childId ->
generateAlertingStopFor(globalData.stops[childId], alertsByStop)
}
?.associateBy { it.stop.id }
?: emptyMap()
.associateBy { it.stop.id }
)

// Return null for any stops without alerts or child alerts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class ObjectCollectionBuilder {
var name = ""
var locationType = LocationType.STOP
var parentStationId: String? = null
var childStopIds: List<String>? = emptyList()
var childStopIds: List<String> = emptyList()

override fun built() =
Stop(id, latitude, longitude, name, locationType, parentStationId, childStopIds)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ data class Stop(
val name: String,
@SerialName("location_type") val locationType: LocationType,
@SerialName("parent_station_id") val parentStationId: String? = null,
@SerialName("child_stop_ids") val childStopIds: List<String>? = null
@SerialName("child_stop_ids") val childStopIds: List<String> = emptyList()
) : BackendObject {
val position = Position(latitude = latitude, longitude = longitude)
}
Loading

0 comments on commit f71b68b

Please sign in to comment.