diff --git a/iosApp/iosApp/ComponentViews/DebugView.swift b/iosApp/iosApp/ComponentViews/DebugView.swift index adb4b77a..905c9d41 100644 --- a/iosApp/iosApp/ComponentViews/DebugView.swift +++ b/iosApp/iosApp/ComponentViews/DebugView.swift @@ -17,7 +17,9 @@ struct DebugView: View { .strokeBorder(Color(.text), style: .init(lineWidth: 2, dash: [10])) VStack(alignment: .leading) { content() + .font(Typography.footnote) }.padding(4) } + .fixedSize(horizontal: false, vertical: true) } } diff --git a/iosApp/iosApp/ComponentViews/ErrorBanner.swift b/iosApp/iosApp/ComponentViews/ErrorBanner.swift index 77082e20..f579586a 100644 --- a/iosApp/iosApp/ComponentViews/ErrorBanner.swift +++ b/iosApp/iosApp/ComponentViews/ErrorBanner.swift @@ -34,7 +34,7 @@ struct ErrorBanner: View { DebugView { ForEach(state.messages.sorted(), id: \.self) { errorName in Text(errorName) - }.font(Typography.footnote) + } } } } diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift index f7ba19a5..ff00e6dc 100644 --- a/iosApp/iosApp/ContentView.swift +++ b/iosApp/iosApp/ContentView.swift @@ -51,6 +51,7 @@ struct ContentView: View { .onReceive(inspection.notice) { inspection.visit(self, $0) } .onAppear { Task { await contentVM.loadOnboardingScreens() } + Task { await nearbyVM.loadDebugSetting() } } .task { // We can't set stale caches in ResponseCache on init because of our Koin setup, diff --git a/iosApp/iosApp/Localizable.xcstrings b/iosApp/iosApp/Localizable.xcstrings index 3b5197b2..435e2887 100644 --- a/iosApp/iosApp/Localizable.xcstrings +++ b/iosApp/iosApp/Localizable.xcstrings @@ -4368,6 +4368,7 @@ }, "Map Debug" : { "comment" : "A setting on the More page to display map debug information (only visible for developers)", + "extractionState" : "stale", "localizations" : { "es" : { "stringUnit" : { diff --git a/iosApp/iosApp/Pages/StopDetails/StopDetailsView.swift b/iosApp/iosApp/Pages/StopDetails/StopDetailsView.swift index bbb9ede8..60d55740 100644 --- a/iosApp/iosApp/Pages/StopDetails/StopDetailsView.swift +++ b/iosApp/iosApp/Pages/StopDetails/StopDetailsView.swift @@ -78,6 +78,11 @@ struct StopDetailsView: View { onBack: nearbyVM.navigationStack.count > 1 ? { nearbyVM.goBack() } : nil, onClose: { nearbyVM.navigationStack.removeAll() } ) + if nearbyVM.showDebugMessages { + DebugView { + Text(verbatim: "stop id: \(stop.id)") + } + } ErrorBanner(errorBannerVM).padding(.horizontal, 16) if servedRoutes.count > 1 { StopDetailsFilterPills( diff --git a/iosApp/iosApp/Pages/TripDetails/TripDetailsPage.swift b/iosApp/iosApp/Pages/TripDetails/TripDetailsPage.swift index 386e1554..0294a228 100644 --- a/iosApp/iosApp/Pages/TripDetails/TripDetailsPage.swift +++ b/iosApp/iosApp/Pages/TripDetails/TripDetailsPage.swift @@ -72,6 +72,14 @@ struct TripDetailsPage: View { var body: some View { VStack(spacing: 16) { header + if nearbyVM.showDebugMessages { + DebugView { + VStack { + Text(verbatim: "trip id \(tripId)") + Text(verbatim: "vehicle id: \(vehicleId)") + } + } + } if tripPredictionsLoaded, let globalResponse, let vehicle = vehicleResponse?.vehicle, let stops = TripDetailsStopList.companion.fromPieces( tripId: tripId, diff --git a/iosApp/iosApp/ViewModels/NearbyViewModel.swift b/iosApp/iosApp/ViewModels/NearbyViewModel.swift index a4659fae..60ac9631 100644 --- a/iosApp/iosApp/ViewModels/NearbyViewModel.swift +++ b/iosApp/iosApp/ViewModels/NearbyViewModel.swift @@ -37,32 +37,47 @@ class NearbyViewModel: ObservableObject { }} } + @Published + var showDebugMessages: Bool = false + @Published var alerts: AlertsStreamDataResponse? @Published var nearbyState = NearbyTransitState() @Published var selectingLocation = false + private let alertsRepository: IAlertsRepository private let errorBannerRepository: IErrorBannerStateRepository private let nearbyRepository: INearbyRepository private let visitHistoryUsecase: VisitHistoryUsecase private var fetchNearbyTask: Task? private var analytics: NearbyTransitAnalytics + private let settingsRepository: ISettingsRepository init( departures: StopDetailsDepartures? = nil, navigationStack: [SheetNavigationStackEntry] = [], + showDebugMessages: Bool = false, alertsRepository: IAlertsRepository = RepositoryDI().alerts, errorBannerRepository: IErrorBannerStateRepository = RepositoryDI().errorBanner, nearbyRepository: INearbyRepository = RepositoryDI().nearby, visitHistoryUsecase: VisitHistoryUsecase = UsecaseDI().visitHistoryUsecase, - analytics: NearbyTransitAnalytics = AnalyticsProvider.shared + analytics: NearbyTransitAnalytics = AnalyticsProvider.shared, + settingsRepository: ISettingsRepository = RepositoryDI().settings ) { self.departures = departures self.navigationStack = navigationStack + self.showDebugMessages = showDebugMessages + self.alertsRepository = alertsRepository self.errorBannerRepository = errorBannerRepository self.nearbyRepository = nearbyRepository self.visitHistoryUsecase = visitHistoryUsecase self.analytics = analytics + self.settingsRepository = settingsRepository + } + + @MainActor + func loadDebugSetting() async { + showDebugMessages = await (try? settingsRepository.getSettings()[.devDebugMode]?.boolValue) ?? false } /** diff --git a/iosApp/iosAppTests/Pages/StopDetails/StopDetailsViewTests.swift b/iosApp/iosAppTests/Pages/StopDetails/StopDetailsViewTests.swift index eaa32997..6c42a30f 100644 --- a/iosApp/iosAppTests/Pages/StopDetails/StopDetailsViewTests.swift +++ b/iosApp/iosAppTests/Pages/StopDetails/StopDetailsViewTests.swift @@ -140,4 +140,48 @@ final class StopDetailsViewTests: XCTestCase { ViewHosting.host(view: sut) XCTAssertNil(try? sut.inspect().find(viewWithAccessibilityLabel: "Back")) } + + func testDebugModeNotShownByDefault() throws { + let objects = ObjectCollectionBuilder() + let stop = objects.stop { stop in + stop.id = "FAKE_STOP_ID" + } + + let nearbyVM: NearbyViewModel = .init(navigationStack: [.stopDetails(stop, nil)], showDebugMessages: false) + let sut = StopDetailsView( + stop: stop, + filter: nil, + setFilter: { _ in }, + departures: nil, + errorBannerVM: .init(), + nearbyVM: nearbyVM, + now: Date.now, + pinnedRoutes: [], togglePinnedRoute: { _ in } + ) + + ViewHosting.host(view: sut) + XCTAssertThrowsError(try sut.inspect().find(text: "stop id: FAKE_STOP_ID")) + } + + func testDebugModeShown() throws { + let objects = ObjectCollectionBuilder() + let stop = objects.stop { stop in + stop.id = "FAKE_STOP_ID" + } + + let nearbyVM: NearbyViewModel = .init(navigationStack: [.stopDetails(stop, nil)], showDebugMessages: true) + let sut = StopDetailsView( + stop: stop, + filter: nil, + setFilter: { _ in }, + departures: nil, + errorBannerVM: .init(), + nearbyVM: nearbyVM, + now: Date.now, + pinnedRoutes: [], togglePinnedRoute: { _ in } + ) + + ViewHosting.host(view: sut) + XCTAssertNotNil(try sut.inspect().find(text: "stop id: FAKE_STOP_ID")) + } } diff --git a/iosApp/iosAppTests/Pages/TripDetails/TripDetailsPageTests.swift b/iosApp/iosAppTests/Pages/TripDetails/TripDetailsPageTests.swift index c9e5add5..21496765 100644 --- a/iosApp/iosAppTests/Pages/TripDetails/TripDetailsPageTests.swift +++ b/iosApp/iosAppTests/Pages/TripDetails/TripDetailsPageTests.swift @@ -603,6 +603,58 @@ final class TripDetailsPageTests: XCTestCase { wait(for: [vehicleLeaveExp, vehicleJoinExp], timeout: 2) } + func testDebugModeNotShownByDefault() throws { + let objects = ObjectCollectionBuilder() + objects.stop { _ in } + let sut = TripDetailsPage( + tripId: "tripId", + vehicleId: "vehicleId", + routeId: "routeId", + target: nil, + errorBannerVM: .init(), + nearbyVM: .init(), + mapVM: .init(), + tripPredictionsRepository: FakeTripPredictionsRepository(response: .init(objects: objects)), + tripRepository: FakeTripRepository( + tripResponse: .init(trip: objects.trip { _ in }), + scheduleResponse: TripSchedulesResponse.StopIds(stopIds: []) + ), + vehicleRepository: FakeVehicleRepository( + response: .init(vehicle: nil), + onConnect: {}, + onDisconnect: {} + ) + ) + ViewHosting.host(view: sut) + XCTAssertThrowsError(try sut.inspect().find(text: "trip id: tripId")) + } + + func testDebugModeShown() throws { + let objects = ObjectCollectionBuilder() + objects.stop { _ in } + let sut = TripDetailsPage( + tripId: "tripId", + vehicleId: "vehicleId", + routeId: "routeId", + target: nil, + errorBannerVM: .init(), + nearbyVM: .init(showDebugMessages: true), + mapVM: .init(), + tripPredictionsRepository: FakeTripPredictionsRepository(response: .init(objects: objects)), + tripRepository: FakeTripRepository( + tripResponse: .init(trip: objects.trip { _ in }), + scheduleResponse: TripSchedulesResponse.StopIds(stopIds: []) + ), + vehicleRepository: FakeVehicleRepository( + response: .init(vehicle: nil), + onConnect: {}, + onDisconnect: {} + ) + ) + ViewHosting.host(view: sut) + XCTAssertNotNil(try sut.inspect().find(text: "trip id: tripId")) + } + class FakeTripRepository: IdleTripRepository { let tripResponse: ApiResult let scheduleResponse: TripSchedulesResponse