Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hide schedules on subway #103

Merged
merged 3 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions iosApp/iosApp/Pages/NearbyTransit/NearbyTransitView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ struct NearbyTransitView_Previews: PreviewProvider {
stop: busStop,
patternsByHeadsign: [
PatternsByHeadsign(
route: busRoute,
headsign: "Houghs Neck",
patterns: [busPattern],
upcomingTrips: [
Expand All @@ -266,6 +267,7 @@ struct NearbyTransitView_Previews: PreviewProvider {
stop: crStop,
patternsByHeadsign: [
PatternsByHeadsign(
route: crRoute,
headsign: "Houghs Neck",
patterns: [crPattern],
upcomingTrips: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import com.mbta.tid.mbta_app.model.response.StopAndRoutePatternResponse
* route pattern.
*/
data class NearbyStaticData(val data: List<RouteWithStops>) {
data class HeadsignWithPatterns(val headsign: String, val patterns: List<RoutePattern>) :
Comparable<HeadsignWithPatterns> {
data class HeadsignWithPatterns(
val route: Route,
val headsign: String,
val patterns: List<RoutePattern>
) : Comparable<HeadsignWithPatterns> {
override fun compareTo(other: HeadsignWithPatterns): Int =
patterns.first().compareTo(other.patterns.first())
}
Expand Down Expand Up @@ -93,6 +96,7 @@ data class NearbyStaticData(val data: List<RouteWithStops>) {
}
.map { (headsign, routePatterns) ->
HeadsignWithPatterns(
route,
headsign,
routePatterns.sorted()
)
Expand All @@ -119,20 +123,20 @@ class NearbyStaticDataBuilder {
val data = mutableListOf<NearbyStaticData.RouteWithStops>()

fun route(route: Route, block: PatternsByStopBuilder.() -> Unit) {
val builder = PatternsByStopBuilder()
val builder = PatternsByStopBuilder(route)
builder.block()
data.add(NearbyStaticData.RouteWithStops(route, builder.data))
}

class PatternsByHeadsignBuilder {
class PatternsByHeadsignBuilder(val route: Route) {
val data = mutableListOf<NearbyStaticData.HeadsignWithPatterns>()

fun headsign(headsign: String, patterns: List<RoutePattern>) {
data.add(NearbyStaticData.HeadsignWithPatterns(headsign, patterns))
data.add(NearbyStaticData.HeadsignWithPatterns(route, headsign, patterns))
}
}

class PatternsByStopBuilder {
class PatternsByStopBuilder(val route: Route) {
val data = mutableListOf<NearbyStaticData.StopWithPatterns>()

@DefaultArgumentInterop.Enabled
Expand All @@ -141,7 +145,7 @@ class NearbyStaticDataBuilder {
childStopIds: List<String> = emptyList(),
block: PatternsByHeadsignBuilder.() -> Unit
) {
val builder = PatternsByHeadsignBuilder()
val builder = PatternsByHeadsignBuilder(route)
builder.block()
data.add(
NearbyStaticData.StopWithPatterns(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ typealias UpcomingTripsMap = Map<UpcomingTripKey, List<UpcomingTrip>>
* for any of these [patterns]
*/
data class PatternsByHeadsign(
val route: Route,
val headsign: String,
val patterns: List<RoutePattern>,
val upcomingTrips: List<UpcomingTrip>? = null,
val alertsHere: List<Alert>? = null,
) : Comparable<PatternsByHeadsign> {
constructor(
staticData: NearbyStaticData.HeadsignWithPatterns,
routeId: String,
upcomingTripsMap: UpcomingTripsMap?,
stopIds: Set<String>,
alerts: Collection<Alert>?,
) : this(
staticData.route,
staticData.headsign,
staticData.patterns,
if (upcomingTripsMap != null) {
stopIds
.mapNotNull { stopId ->
upcomingTripsMap[UpcomingTripKey(routeId, staticData.headsign, stopId)]
upcomingTripsMap[
UpcomingTripKey(staticData.route.id, staticData.headsign, stopId)]
}
.flatten()
.sorted()
Expand All @@ -47,7 +49,7 @@ data class PatternsByHeadsign(
stopIds.flatMap { stopId ->
alerts.filter { alert ->
alert.anyInformedEntity {
it.appliesTo(routeId = routeId, stopId = stopId) &&
it.appliesTo(routeId = staticData.route.id, stopId = stopId) &&
it.activities.contains(Alert.InformedEntity.Activity.Board)
}
}
Expand Down Expand Up @@ -117,7 +119,10 @@ data class PatternsByHeadsign(
val tripsToShow =
upcomingTrips
.map { Format.Some.FormatWithId(it, now) }
.filterNot { it.format is UpcomingTrip.Format.Hidden }
.filterNot {
it.format is UpcomingTrip.Format.Hidden ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to add a small comment here for context on why we're hiding subway schedules?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May as well, yeah.

(this.route.type.isSubway() && it.format is UpcomingTrip.Format.Schedule)
}
.take(2)
if (tripsToShow.isEmpty()) {
this.alertsHere?.firstOrNull()?.let {
Expand All @@ -138,16 +143,13 @@ data class PatternsByStop(val stop: Stop, val patternsByHeadsign: List<PatternsB

constructor(
staticData: NearbyStaticData.StopWithPatterns,
routeId: String,
upcomingTripsMap: UpcomingTripsMap?,
cutoffTime: Instant,
alerts: Collection<Alert>?,
) : this(
staticData.stop,
staticData.patternsByHeadsign
.map {
PatternsByHeadsign(it, routeId, upcomingTripsMap, staticData.allStopIds, alerts)
}
.map { PatternsByHeadsign(it, upcomingTripsMap, staticData.allStopIds, alerts) }
.filter { (it.isTypical() || it.isUpcomingBefore(cutoffTime)) && !it.isArrivalOnly() }
.sorted()
)
Expand All @@ -172,7 +174,7 @@ data class StopAssociatedRoute(
) : this(
staticData.route,
staticData.patternsByStop
.map { PatternsByStop(it, staticData.route.id, upcomingTripsMap, cutoffTime, alerts) }
.map { PatternsByStop(it, upcomingTripsMap, cutoffTime, alerts) }
.filterNot { it.patternsByHeadsign.isEmpty() }
.sortedWith(
compareBy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ class NearbyResponseTest {
stop1,
listOf(
PatternsByHeadsign(
route1,
"Harvard",
listOf(pattern1, pattern2),
listOf(
Expand All @@ -463,6 +464,7 @@ class NearbyResponseTest {
stop2,
listOf(
PatternsByHeadsign(
route1,
"Nubian",
listOf(pattern3),
listOf(UpcomingTrip(stop2Pattern3Prediction))
Expand Down Expand Up @@ -593,21 +595,25 @@ class NearbyResponseTest {
stop1,
listOf(
PatternsByHeadsign(
route1,
"Typical Out",
listOf(typicalOutbound),
listOf(UpcomingTrip(typicalOutboundPrediction))
),
PatternsByHeadsign(
route1,
"Typical In",
listOf(typicalInbound),
emptyList()
),
PatternsByHeadsign(
route1,
"Deviation Out",
listOf(deviationOutbound),
listOf(UpcomingTrip(deviationOutboundPrediction))
),
PatternsByHeadsign(
route1,
"Atypical In",
listOf(atypicalInbound),
listOf(UpcomingTrip(atypicalInboundPrediction))
Expand Down Expand Up @@ -708,8 +714,18 @@ class NearbyResponseTest {
PatternsByStop(
stop1,
listOf(
PatternsByHeadsign("Typical Out", listOf(typicalOutbound), null),
PatternsByHeadsign("Typical In", listOf(typicalInbound), null),
PatternsByHeadsign(
route1,
"Typical Out",
listOf(typicalOutbound),
null
),
PatternsByHeadsign(
route1,
"Typical In",
listOf(typicalInbound),
null
),
)
)
)
Expand Down Expand Up @@ -874,6 +890,7 @@ class NearbyResponseTest {
parentStop,
listOf(
PatternsByHeadsign(
route1,
"Harvard",
listOf(pattern1),
listOf(UpcomingTrip(prediction1))
Expand Down Expand Up @@ -936,6 +953,7 @@ class NearbyResponseTest {
stop,
listOf(
PatternsByHeadsign(
route,
"A",
listOf(routePattern),
listOf(UpcomingTrip(sched1, pred1), UpcomingTrip(sched2, pred2))
Expand Down Expand Up @@ -1002,6 +1020,7 @@ class NearbyResponseTest {
stop,
listOf(
PatternsByHeadsign(
route1,
"A",
listOf(routePattern1),
listOf(UpcomingTrip(sched1, pred1))
Expand All @@ -1017,6 +1036,7 @@ class NearbyResponseTest {
stop,
listOf(
PatternsByHeadsign(
route2,
"A",
listOf(routePattern2),
listOf(UpcomingTrip(sched2, pred2))
Expand Down Expand Up @@ -1082,6 +1102,7 @@ class NearbyResponseTest {
stop,
listOf(
PatternsByHeadsign(
route,
"A",
listOf(routePattern),
emptyList(),
Expand Down Expand Up @@ -1151,6 +1172,7 @@ class NearbyResponseTest {
stop,
listOf(
PatternsByHeadsign(
route,
"A",
listOf(routePattern1),
listOf(UpcomingTrip(sched1))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mbta.tid.mbta_app.model

import com.mbta.tid.mbta_app.model.ObjectCollectionBuilder.Single.alert
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.minutes
Expand All @@ -11,31 +10,40 @@ class PatternsByHeadsignTest {
fun `formats as loading when null trips`() {
val now = Clock.System.now()

val objects = ObjectCollectionBuilder()
val route = objects.route()

assertEquals(
PatternsByHeadsign.Format.Loading,
PatternsByHeadsign("", emptyList(), null, null).format(now)
PatternsByHeadsign(route, "", emptyList(), null, null).format(now)
)
}

@Test
fun `formats as alert with no trips and alert`() {
val now = Clock.System.now()

val alert = alert {}
val objects = ObjectCollectionBuilder()
val route = objects.route()

val alert = objects.alert {}

assertEquals(
PatternsByHeadsign.Format.NoService(alert),
PatternsByHeadsign("", emptyList(), emptyList(), listOf(alert)).format(now)
PatternsByHeadsign(route, "", emptyList(), emptyList(), listOf(alert)).format(now)
)
}

@Test
fun `formats as none with no trips and no alert`() {
val now = Clock.System.now()

val objects = ObjectCollectionBuilder()
val route = objects.route()

assertEquals(
PatternsByHeadsign.Format.None,
PatternsByHeadsign("", emptyList(), emptyList(), emptyList()).format(now)
PatternsByHeadsign(route, "", emptyList(), emptyList(), emptyList()).format(now)
)
}

Expand All @@ -44,6 +52,7 @@ class PatternsByHeadsignTest {
val now = Clock.System.now()

val objects = ObjectCollectionBuilder()
val route = objects.route()

val trip1 = objects.trip()
val trip2 = objects.trip()
Expand Down Expand Up @@ -71,7 +80,63 @@ class PatternsByHeadsignTest {
)
)
),
PatternsByHeadsign("", emptyList(), listOf(upcomingTrip1, upcomingTrip2)).format(now)
PatternsByHeadsign(route, "", emptyList(), listOf(upcomingTrip1, upcomingTrip2))
.format(now)
)
}

@Test
fun `format skips schedules on subway but keeps on non-subway`() {
val now = Clock.System.now()

val objects = ObjectCollectionBuilder()
val subwayRoute = objects.route { type = RouteType.LIGHT_RAIL }
val busRoute = objects.route { type = RouteType.BUS }

val trip1 = objects.trip()
val trip2 = objects.trip()

val schedule1 =
objects.schedule {
trip = trip1
departureTime = now + 5.minutes
}
val prediction2 =
objects.prediction {
trip = trip2
departureTime = now + 5.minutes
}

val upcomingTrip1 = UpcomingTrip(schedule1)
val upcomingTrip2 = UpcomingTrip(prediction2)

assertEquals(
PatternsByHeadsign.Format.Some(
listOf(
PatternsByHeadsign.Format.Some.FormatWithId(
trip2.id,
UpcomingTrip.Format.Minutes(5)
)
)
),
PatternsByHeadsign(subwayRoute, "", emptyList(), listOf(upcomingTrip1, upcomingTrip2))
.format(now)
)
assertEquals(
PatternsByHeadsign.Format.Some(
listOf(
PatternsByHeadsign.Format.Some.FormatWithId(
trip1.id,
UpcomingTrip.Format.Schedule(now + 5.minutes)
),
PatternsByHeadsign.Format.Some.FormatWithId(
trip2.id,
UpcomingTrip.Format.Minutes(5)
)
)
),
PatternsByHeadsign(busRoute, "", emptyList(), listOf(upcomingTrip1, upcomingTrip2))
.format(now)
)
}
}