Skip to content

Commit

Permalink
feat(iOS): forget predictions if backgrounded for over ten minutes (#461
Browse files Browse the repository at this point in the history
)

* feat: forget predictions if backgrounded for over ten minutes

* fix the tests

* fix a test that was working locally

---------

Co-authored-by: Kayla Brady <31781298+KaylaBrady@users.noreply.github.com>
  • Loading branch information
boringcactus and KaylaBrady authored Oct 15, 2024
1 parent a297274 commit 32dd880
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ class NearbyTransitPageTest : KoinTest {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
/* no-op */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class NearbyTransitViewTest : KoinTest {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
/* no-op */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class StopDetailsViewTest {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
/* no-op */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class SubscribeToPredictionsTest {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
check(isConnected) { "called disconnect when not connected" }
isConnected = false
Expand Down
9 changes: 8 additions & 1 deletion iosApp/iosApp/Pages/NearbyTransit/NearbyTransitView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ struct NearbyTransitView: View {
}
}
.withScenePhaseHandlers(
onActive: { joinPredictions(state.nearbyByRouteAndStop?.stopIds()) },
onActive: {
if let predictionsByStop,
predictionsRepository
.shouldForgetPredictions(predictionCount: predictionsByStop.predictionQuantity()) {
self.predictionsByStop = nil
}
joinPredictions(state.nearbyByRouteAndStop?.stopIds())
},
onInactive: leavePredictions,
onBackground: {
leavePredictions()
Expand Down
19 changes: 14 additions & 5 deletions iosApp/iosApp/Pages/StopDetails/StopDetailsPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,20 @@ struct StopDetailsPage: View {
.onDisappear {
leavePredictions()
}
.withScenePhaseHandlers(onActive: { joinPredictions(stop) },
onInactive: leavePredictions,
onBackground: { leavePredictions()
isReturningFromBackground = true
})
.withScenePhaseHandlers(
onActive: {
if let predictionsByStop,
predictionsRepository
.shouldForgetPredictions(predictionCount: predictionsByStop.predictionQuantity()) {
self.predictionsByStop = nil
}
joinPredictions(stop)
},
onInactive: leavePredictions,
onBackground: { leavePredictions()
isReturningFromBackground = true
}
)
}
}

Expand Down
21 changes: 15 additions & 6 deletions iosApp/iosApp/Pages/TripDetails/TripDetailsPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,21 @@ struct TripDetailsPage: View {
joinVehicle(vehicleId: vehicleId)
}
.onReceive(inspection.notice) { inspection.visit(self, $0) }
.withScenePhaseHandlers(onActive: joinRealtime,
onInactive: leaveRealtime,
onBackground: {
leaveRealtime()
isReturningFromBackground = true
})
.withScenePhaseHandlers(
onActive: {
if let tripPredictions,
tripPredictionsRepository
.shouldForgetPredictions(predictionCount: tripPredictions.predictionQuantity()) {
self.tripPredictions = nil
}
joinRealtime()
},
onInactive: leaveRealtime,
onBackground: {
leaveRealtime()
isReturningFromBackground = true
}
)
}

private func loadEverything() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,10 @@ final class TripDetailsPageTests: XCTestCase {

var lastUpdated: Instant?

func shouldForgetPredictions(predictionCount _: Int32) -> Bool {
false
}

func disconnect() {
onDisconnect?()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ fun endToEndModule(): Module {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun connectV2(
stopIds: List<String>,
onJoin: (ApiResult<PredictionsByStopJoinResponse>) -> Unit,
Expand Down Expand Up @@ -199,6 +201,8 @@ fun endToEndModule(): Module {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
TODO("Not yet implemented")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.mbta.tid.mbta_app.network.PhoenixMessage
import com.mbta.tid.mbta_app.network.PhoenixPushStatus
import com.mbta.tid.mbta_app.network.PhoenixSocket
import com.mbta.tid.mbta_app.phoenix.PredictionsForStopsChannel
import kotlin.time.Duration.Companion.minutes
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.koin.core.component.KoinComponent
Expand All @@ -28,6 +29,8 @@ interface IPredictionsRepository {

var lastUpdated: Instant?

fun shouldForgetPredictions(predictionCount: Int): Boolean

fun disconnect()
}

Expand All @@ -38,6 +41,10 @@ class PredictionsRepository(private val socket: PhoenixSocket) :

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) =
(Clock.System.now() - (lastUpdated ?: Instant.DISTANT_FUTURE)) > 10.minutes &&
predictionCount > 0

override fun connect(
stopIds: List<String>,
onReceive: (ApiResult<PredictionsStreamDataResponse>) -> Unit
Expand Down Expand Up @@ -221,6 +228,8 @@ class MockPredictionsRepository(

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
onDisconnect()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.mbta.tid.mbta_app.network.PhoenixMessage
import com.mbta.tid.mbta_app.network.PhoenixPushStatus
import com.mbta.tid.mbta_app.network.PhoenixSocket
import com.mbta.tid.mbta_app.phoenix.PredictionsForStopsChannel
import kotlin.time.Duration.Companion.minutes
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.koin.core.component.KoinComponent
Expand All @@ -17,6 +18,8 @@ interface ITripPredictionsRepository {

var lastUpdated: Instant?

fun shouldForgetPredictions(predictionCount: Int): Boolean

fun disconnect()
}

Expand All @@ -27,6 +30,10 @@ class TripPredictionsRepository(private val socket: PhoenixSocket) :

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) =
(Clock.System.now() - (lastUpdated ?: Instant.DISTANT_FUTURE)) > 10.minutes &&
predictionCount > 0

override fun connect(
tripId: String,
onReceive: (ApiResult<PredictionsStreamDataResponse>) -> Unit
Expand Down Expand Up @@ -89,6 +96,8 @@ class MockTripPredictionsRepository : ITripPredictionsRepository {

override var lastUpdated: Instant? = null

override fun shouldForgetPredictions(predictionCount: Int) = false

override fun disconnect() {
/* no-op */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ import dev.mokkery.mock
import dev.mokkery.verify
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.minutes
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.koin.test.KoinTest

class PredictionsRepositoryTests : KoinTest {
Expand Down Expand Up @@ -416,4 +421,33 @@ class PredictionsRepositoryTests : KoinTest {
}
)
}

@Test
fun `shouldForgetPredictions false when never updated`() {
val predictionsRepo = PredictionsRepository(mock(MockMode.autofill))
predictionsRepo.lastUpdated = null
// there will not, in practice, be ten predictions and no last updated time
assertFalse(predictionsRepo.shouldForgetPredictions(10))
}

@Test
fun `shouldForgetPredictions false when no predictions`() {
val predictionsRepo = PredictionsRepository(mock(MockMode.autofill))
predictionsRepo.lastUpdated = Instant.DISTANT_PAST
assertFalse(predictionsRepo.shouldForgetPredictions(0))
}

@Test
fun `shouldForgetPredictions false when within ten minutes`() {
val predictionsRepo = PredictionsRepository(mock(MockMode.autofill))
predictionsRepo.lastUpdated = Clock.System.now() - 9.9.minutes
assertFalse(predictionsRepo.shouldForgetPredictions(10))
}

@Test
fun `shouldForgetPredictions true when old and nonempty`() {
val predictionsRepo = PredictionsRepository(mock(MockMode.autofill))
predictionsRepo.lastUpdated = Clock.System.now() - 10.1.minutes
assertTrue(predictionsRepo.shouldForgetPredictions(10))
}
}

0 comments on commit 32dd880

Please sign in to comment.