From 8723045e5e10b032f1b78ef0716a6c4209fcba6c Mon Sep 17 00:00:00 2001
From: KaylaBrady <31781298+KaylaBrady@users.noreply.github.com>
Date: Thu, 17 Oct 2024 16:16:57 -0400
Subject: [PATCH 1/2] feat(ErrorBanner): offline banner
---
androidApp/src/main/AndroidManifest.xml | 2 +
iosApp/iosApp.xcodeproj/project.pbxproj | 4 ++
.../iosApp/ComponentViews/ErrorBanner.swift | 6 +++
iosApp/iosApp/ComponentViews/ErrorCard.swift | 8 ++--
iosApp/iosApp/Localizable.xcstrings | 6 +++
.../ViewModels/ErrorBannerViewModel.swift | 15 +++++--
iosApp/iosAppTests/Utils/FetchApiTests.swift | 7 ++-
.../ErrorBannerViewModelTests.swift | 26 +++++++++++
.../iosAppTests/Views/ErrorBannerTests.swift | 8 ++++
.../kotlin/com/mbta/tid/mbta_app/Helpers.kt | 2 +-
.../com/mbta/tid/mbta_app/PlatformModule.kt | 5 ++-
.../network/NetworkConnectivityMonitor.kt | 30 +++++++++++++
.../dependencyInjection/RepositoryDI.kt | 1 +
.../tid/mbta_app/model/ErrorBannerState.kt | 4 +-
.../network/NetworkConnectivityMonitor.kt | 6 +++
.../ErrorBannerStateRepository.kt | 43 +++++++++++++++++--
.../ErrorBannerStateRepositoryTest.kt | 25 +++++++++++
.../kotlin/com/mbta/tid/mbta_app/Helpers.kt | 2 +-
.../com/mbta/tid/mbta_app/PlatformModule.kt | 5 ++-
.../network/NetworkConnectivityMonitor.kt | 23 ++++++++++
20 files changed, 211 insertions(+), 17 deletions(-)
create mode 100644 iosApp/iosAppTests/ViewModels/ErrorBannerViewModelTests.swift
create mode 100644 shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
create mode 100644 shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
create mode 100644 shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
diff --git a/androidApp/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml
index 9ff6a44b5..0e4f58869 100644
--- a/androidApp/src/main/AndroidManifest.xml
+++ b/androidApp/src/main/AndroidManifest.xml
@@ -3,6 +3,8 @@
+
+
: View {
+ @ViewBuilder let details: Content
var button: (() -> AnyView)?
- init(_ details: () -> Text) {
+ init(_ details: () -> Content) {
self.details = details()
button = nil
}
- init(details: Text, button: (() -> AnyView)? = nil) {
+ init(details: Content, button: (() -> AnyView)? = nil) {
self.details = details
self.button = button
}
diff --git a/iosApp/iosApp/Localizable.xcstrings b/iosApp/iosApp/Localizable.xcstrings
index 65b59f597..0e3197784 100644
--- a/iosApp/iosApp/Localizable.xcstrings
+++ b/iosApp/iosApp/Localizable.xcstrings
@@ -178,6 +178,9 @@
},
"Crossing Malfunction" : {
"comment" : "Possible alert cause"
+ },
+ "Custom message" : {
+
},
"Demonstration" : {
"comment" : "Possible alert cause"
@@ -425,6 +428,9 @@
},
"trains" : {
"comment" : "trains"
+ },
+ "Unable to connect" : {
+
},
"Unruly Passenger" : {
"comment" : "Possible alert cause"
diff --git a/iosApp/iosApp/ViewModels/ErrorBannerViewModel.swift b/iosApp/iosApp/ViewModels/ErrorBannerViewModel.swift
index 2ba130fac..f25e491c6 100644
--- a/iosApp/iosApp/ViewModels/ErrorBannerViewModel.swift
+++ b/iosApp/iosApp/ViewModels/ErrorBannerViewModel.swift
@@ -18,19 +18,28 @@ class ErrorBannerViewModel: ObservableObject {
@Published
var loadingWhenPredictionsStale: Bool
+ // option for testing
+ var skipListeningForStateChanges = false
+
init(
errorRepository: IErrorBannerStateRepository = RepositoryDI().errorBanner,
- initialLoadingWhenPredictionsStale: Bool = false
+ initialLoadingWhenPredictionsStale: Bool = false,
+ skipListeningForStateChanges: Bool = false
) {
self.errorRepository = errorRepository
loadingWhenPredictionsStale = initialLoadingWhenPredictionsStale
errorState = self.errorRepository.state.value
+ self.skipListeningForStateChanges = skipListeningForStateChanges
}
@MainActor
func activate() async {
- for await errorState in errorRepository.state {
- self.errorState = errorState
+ errorRepository.subscribeToNetworkStatusChanges()
+
+ if !skipListeningForStateChanges {
+ for await errorState in errorRepository.state {
+ self.errorState = errorState
+ }
}
}
diff --git a/iosApp/iosAppTests/Utils/FetchApiTests.swift b/iosApp/iosAppTests/Utils/FetchApiTests.swift
index cd4977b08..4776ff885 100644
--- a/iosApp/iosAppTests/Utils/FetchApiTests.swift
+++ b/iosApp/iosAppTests/Utils/FetchApiTests.swift
@@ -54,7 +54,12 @@ final class FetchApiTests: XCTestCase {
onRefreshAfterError: { expRefresh.fulfill() }
)
XCTAssertNotNil(errorBannerRepo.state.value)
- errorBannerRepo.state.value?.action()
+
+ if let action = errorBannerRepo.state.value?.action {
+ action()
+ } else {
+ XCTFail("data error missing action")
+ }
await fulfillment(of: [expRefresh], timeout: 1)
}
diff --git a/iosApp/iosAppTests/ViewModels/ErrorBannerViewModelTests.swift b/iosApp/iosAppTests/ViewModels/ErrorBannerViewModelTests.swift
new file mode 100644
index 000000000..60eb30919
--- /dev/null
+++ b/iosApp/iosAppTests/ViewModels/ErrorBannerViewModelTests.swift
@@ -0,0 +1,26 @@
+//
+// ErrorBannerViewModelTests.swift
+// iosAppTests
+//
+// Created by Kayla Brady on 10/18/24.
+// Copyright © 2024 MBTA. All rights reserved.
+//
+
+import Foundation
+@testable import iosApp
+import shared
+import XCTest
+
+final class ErrorBannerViewModelTests: XCTestCase {
+ func testActivateSubscribesToNetworkChanges() async {
+ let onSubscribeExp = XCTestExpectation(description: "onSubscribe called")
+ let repo = MockErrorBannerStateRepository(state: nil, onSubscribeToNetworkChanges: { onSubscribeExp.fulfill() })
+ let errorVM = ErrorBannerViewModel(
+ errorRepository: repo,
+ initialLoadingWhenPredictionsStale: false,
+ skipListeningForStateChanges: true
+ )
+ await errorVM.activate()
+ wait(for: [onSubscribeExp], timeout: 1)
+ }
+}
diff --git a/iosApp/iosAppTests/Views/ErrorBannerTests.swift b/iosApp/iosAppTests/Views/ErrorBannerTests.swift
index fd4c1ebb2..2b8176623 100644
--- a/iosApp/iosAppTests/Views/ErrorBannerTests.swift
+++ b/iosApp/iosAppTests/Views/ErrorBannerTests.swift
@@ -49,6 +49,14 @@ final class ErrorBannerTests: XCTestCase {
wait(for: [callsAction], timeout: 1)
}
+ @MainActor func testWhenNetworkError() throws {
+ let sut = ErrorBanner(.init(
+ errorRepository: MockErrorBannerStateRepository(state: .NetworkError()),
+ initialLoadingWhenPredictionsStale: true
+ ))
+ XCTAssertNotNil(try sut.inspect().find(text: "Unable to connect"))
+ }
+
@MainActor func testLoadingWhenPredictionsStale() throws {
let sut = ErrorBanner(.init(
errorRepository: MockErrorBannerStateRepository(state: .StalePredictions(
diff --git a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
index ad94fd6fc..7816bc272 100644
--- a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
+++ b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
@@ -14,6 +14,6 @@ internal fun createDataStore(context: Context): DataStore =
fun initKoin(appVariant: AppVariant, nativeModule: Module, context: Context) {
startKoin {
androidContext(context)
- modules(appModule(appVariant) + platformModule() + nativeModule)
+ modules(platformModule() + appModule(appVariant) + nativeModule)
}
}
diff --git a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
index 603327f5d..9a498d9e5 100644
--- a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
+++ b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
@@ -1,5 +1,7 @@
package com.mbta.tid.mbta_app
+import com.mbta.tid.mbta_app.network.INetworkConnectivityMonitor
+import com.mbta.tid.mbta_app.network.NetworkConnectivityMonitor
import com.mbta.tid.mbta_app.utils.AndroidSystemPaths
import com.mbta.tid.mbta_app.utils.SystemPaths
import org.koin.dsl.module
@@ -7,6 +9,7 @@ import org.koin.dsl.module
fun platformModule() = module {
includes(
module { single { createDataStore(get()) } },
- module { single { AndroidSystemPaths(get()) } }
+ module { single { AndroidSystemPaths(get()) } },
+ module { single { NetworkConnectivityMonitor(get()) } }
)
}
diff --git a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
new file mode 100644
index 000000000..09989a837
--- /dev/null
+++ b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
@@ -0,0 +1,30 @@
+package com.mbta.tid.mbta_app.network
+
+import android.content.Context
+import android.content.Context.CONNECTIVITY_SERVICE
+import android.net.ConnectivityManager
+import android.net.Network
+
+class NetworkConnectivityMonitor(context: Context) : INetworkConnectivityMonitor {
+ private var networkCallback: ConnectivityManager.NetworkCallback? = null
+ private val connectivityManager =
+ context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
+
+ override fun registerListener(onNetworkAvailable: () -> Unit, onNetworkLost: () -> Unit) {
+ networkCallback =
+ object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ onNetworkAvailable()
+ }
+
+ override fun onUnavailable() {
+ onNetworkLost()
+ }
+
+ override fun onLost(network: Network) {
+ onNetworkLost()
+ }
+ }
+ networkCallback?.let { connectivityManager.registerDefaultNetworkCallback(it) }
+ }
+}
diff --git a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/dependencyInjection/RepositoryDI.kt b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/dependencyInjection/RepositoryDI.kt
index ebfc85777..5f96a0cf5 100644
--- a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/dependencyInjection/RepositoryDI.kt
+++ b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/dependencyInjection/RepositoryDI.kt
@@ -93,6 +93,7 @@ class RepositoryDI : IRepositories, KoinComponent {
class RealRepositories : IRepositories {
// initialize repositories with platform-specific dependencies as null.
// instantiate the real repositories in makeNativeModule
+
override val alerts = null
override val appCheck = null
override val config = ConfigRepository()
diff --git a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/model/ErrorBannerState.kt b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/model/ErrorBannerState.kt
index 3f2176c75..f39c9c6c5 100644
--- a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/model/ErrorBannerState.kt
+++ b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/model/ErrorBannerState.kt
@@ -5,7 +5,7 @@ import kotlinx.datetime.Instant
sealed class ErrorBannerState {
/** What to do when the button in the error banner is pressed */
- abstract val action: () -> Unit
+ abstract val action: (() -> Unit)?
data class StalePredictions(val lastUpdated: Instant, override val action: () -> Unit) :
ErrorBannerState() {
@@ -13,4 +13,6 @@ sealed class ErrorBannerState {
}
data class DataError(override val action: () -> Unit) : ErrorBannerState()
+
+ data class NetworkError(override val action: (() -> Unit)?) : ErrorBannerState()
}
diff --git a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
new file mode 100644
index 000000000..152a61196
--- /dev/null
+++ b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
@@ -0,0 +1,6 @@
+package com.mbta.tid.mbta_app.network
+
+/** Observe changes in the device's network connectivity. */
+interface INetworkConnectivityMonitor {
+ fun registerListener(onNetworkAvailable: () -> Unit, onNetworkLost: () -> Unit)
+}
diff --git a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepository.kt b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepository.kt
index a251505da..9e2a277bf 100644
--- a/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepository.kt
+++ b/shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepository.kt
@@ -1,24 +1,47 @@
package com.mbta.tid.mbta_app.repositories
import com.mbta.tid.mbta_app.model.ErrorBannerState
+import com.mbta.tid.mbta_app.network.INetworkConnectivityMonitor
import kotlin.time.Duration.Companion.minutes
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+sealed class NetworkStatus {
+ data object Connected : NetworkStatus()
+
+ data object Disconnected : NetworkStatus()
+}
+
+abstract class IErrorBannerStateRepository(initialState: ErrorBannerState? = null) : KoinComponent {
+
+ private val networkConnectivityMonitor: INetworkConnectivityMonitor by inject()
+
+ /*
+ Registers platform-specific observer of network status changes.
+ */
+ open fun subscribeToNetworkStatusChanges() {
+ this.networkConnectivityMonitor.registerListener(
+ onNetworkAvailable = { setNetworkStatus(NetworkStatus.Connected) },
+ onNetworkLost = { setNetworkStatus(NetworkStatus.Disconnected) }
+ )
+ }
-abstract class IErrorBannerStateRepository
-protected constructor(initialState: ErrorBannerState? = null) {
protected val flow = MutableStateFlow(initialState)
val state = flow.asStateFlow()
+ private var networkStatus: NetworkStatus? = null
+
private var predictionsStale: ErrorBannerState.StalePredictions? = null
private val dataErrors = mutableMapOf()
protected open fun updateState() {
flow.value =
when {
+ networkStatus == NetworkStatus.Disconnected -> ErrorBannerState.NetworkError(null)
dataErrors.isNotEmpty() ->
// encapsulate all the different error actions within one error
ErrorBannerState.DataError { dataErrors.values.forEach { it.action() } }
@@ -41,6 +64,11 @@ protected constructor(initialState: ErrorBannerState? = null) {
updateState()
}
+ private fun setNetworkStatus(newStatus: NetworkStatus) {
+ networkStatus = newStatus
+ updateState()
+ }
+
fun setDataError(key: String, action: () -> Unit) {
dataErrors[key] = ErrorBannerState.DataError(action)
updateState()
@@ -60,8 +88,15 @@ protected constructor(initialState: ErrorBannerState? = null) {
class ErrorBannerStateRepository : IErrorBannerStateRepository(), KoinComponent
-class MockErrorBannerStateRepository(state: ErrorBannerState? = null) :
- IErrorBannerStateRepository(state) {
+class MockErrorBannerStateRepository(
+ state: ErrorBannerState? = null,
+ onSubscribeToNetworkChanges: (() -> Unit)? = null
+) : IErrorBannerStateRepository(state) {
+ private val onSubscribeToNetworkChanges = onSubscribeToNetworkChanges
val mutableFlow
get() = flow
+
+ override fun subscribeToNetworkStatusChanges() {
+ onSubscribeToNetworkChanges?.invoke()
+ }
}
diff --git a/shared/src/commonTest/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepositoryTest.kt b/shared/src/commonTest/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepositoryTest.kt
index 84c286daf..d87bc538a 100644
--- a/shared/src/commonTest/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepositoryTest.kt
+++ b/shared/src/commonTest/kotlin/com/mbta/tid/mbta_app/repositories/ErrorBannerStateRepositoryTest.kt
@@ -1,6 +1,12 @@
package com.mbta.tid.mbta_app.repositories
import com.mbta.tid.mbta_app.model.ErrorBannerState
+import com.mbta.tid.mbta_app.network.INetworkConnectivityMonitor
+import dev.mokkery.MockMode
+import dev.mokkery.matcher.any
+import dev.mokkery.mock
+import dev.mokkery.verify
+import kotlin.test.AfterTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
@@ -13,8 +19,13 @@ import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Clock
+import org.koin.core.context.startKoin
+import org.koin.core.context.stopKoin
+import org.koin.dsl.module
class ErrorBannerStateRepositoryTest {
+ @AfterTest fun `stop koin`() = run { stopKoin() }
+
@Test
fun `initial state is null`() = runBlocking {
val repo = ErrorBannerStateRepository()
@@ -112,4 +123,18 @@ class ErrorBannerStateRepositoryTest {
assertNull(channel.receive())
}
+
+ @Test
+ fun `subscribe to connectivity changes`() {
+
+ val mockNetworkMonitor = mock(MockMode.autofill)
+
+ startKoin { modules(module { single { mockNetworkMonitor } }) }
+
+ val repo = ErrorBannerStateRepository()
+
+ repo.subscribeToNetworkStatusChanges()
+
+ verify { mockNetworkMonitor.registerListener(any(), any()) }
+ }
}
diff --git a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
index df9d9d25a..55c0f679b 100644
--- a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
+++ b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
@@ -33,7 +33,7 @@ internal fun createDataStore(): DataStore =
)
fun initKoin(appVariant: AppVariant, nativeModule: Module) {
- startKoin { modules(appModule(appVariant) + platformModule() + nativeModule) }
+ startKoin { modules(platformModule() + appModule(appVariant) + nativeModule) }
}
/*
diff --git a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
index 659d2f3cd..6bd381b75 100644
--- a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
+++ b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/PlatformModule.kt
@@ -1,5 +1,7 @@
package com.mbta.tid.mbta_app
+import com.mbta.tid.mbta_app.network.INetworkConnectivityMonitor
+import com.mbta.tid.mbta_app.network.NetworkConnectivityMonitor
import com.mbta.tid.mbta_app.utils.IOSSystemPaths
import com.mbta.tid.mbta_app.utils.SystemPaths
import org.koin.dsl.module
@@ -7,6 +9,7 @@ import org.koin.dsl.module
fun platformModule() = module {
includes(
module { single { createDataStore() } },
- module { single { IOSSystemPaths() } }
+ module { single { IOSSystemPaths() } },
+ module { single { NetworkConnectivityMonitor() } }
)
}
diff --git a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
new file mode 100644
index 000000000..8ac906287
--- /dev/null
+++ b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
@@ -0,0 +1,23 @@
+package com.mbta.tid.mbta_app.network
+
+import platform.Network.*
+import platform.darwin.dispatch_get_main_queue
+
+class NetworkConnectivityMonitor : INetworkConnectivityMonitor {
+ private val monitor = nw_path_monitor_create()
+
+ override fun registerListener(onNetworkAvailable: () -> Unit, onNetworkLost: () -> Unit) {
+ nw_path_monitor_set_update_handler(monitor) { path ->
+ val pathStatus = nw_path_get_status(path)
+
+ if (pathStatus == nw_path_status_satisfied) {
+ onNetworkAvailable()
+ } else {
+ onNetworkLost()
+ }
+ }
+
+ nw_path_monitor_set_queue(monitor, dispatch_get_main_queue())
+ nw_path_monitor_start(monitor)
+ }
+}
From e8d189c04e2f29e51a3d3849a261df3627b5c9db Mon Sep 17 00:00:00 2001
From: KaylaBrady <31781298+KaylaBrady@users.noreply.github.com>
Date: Mon, 21 Oct 2024 10:24:15 -0400
Subject: [PATCH 2/2] address PR feedback
---
androidApp/src/main/AndroidManifest.xml | 2 +-
iosApp/iosApp/ComponentViews/ErrorBanner.swift | 4 ++--
.../src/androidMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt | 2 +-
.../mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt | 3 +++
shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt | 2 +-
5 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/androidApp/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml
index 0e4f58869..2d6374a46 100644
--- a/androidApp/src/main/AndroidManifest.xml
+++ b/androidApp/src/main/AndroidManifest.xml
@@ -4,7 +4,7 @@
-
+
=
fun initKoin(appVariant: AppVariant, nativeModule: Module, context: Context) {
startKoin {
androidContext(context)
- modules(platformModule() + appModule(appVariant) + nativeModule)
+ modules(appModule(appVariant) + platformModule() + nativeModule)
}
}
diff --git a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
index 09989a837..65d4d8ebe 100644
--- a/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
+++ b/shared/src/androidMain/kotlin/com/mbta/tid/mbta_app/network/NetworkConnectivityMonitor.kt
@@ -1,5 +1,6 @@
package com.mbta.tid.mbta_app.network
+import android.annotation.SuppressLint
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
@@ -10,6 +11,8 @@ class NetworkConnectivityMonitor(context: Context) : INetworkConnectivityMonitor
private val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
+ @SuppressLint("MissingPermission")
+ // Permission is included in AndroidManifest.xml
override fun registerListener(onNetworkAvailable: () -> Unit, onNetworkLost: () -> Unit) {
networkCallback =
object : ConnectivityManager.NetworkCallback() {
diff --git a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
index 55c0f679b..df9d9d25a 100644
--- a/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
+++ b/shared/src/iosMain/kotlin/com/mbta/tid/mbta_app/Helpers.kt
@@ -33,7 +33,7 @@ internal fun createDataStore(): DataStore =
)
fun initKoin(appVariant: AppVariant, nativeModule: Module) {
- startKoin { modules(platformModule() + appModule(appVariant) + nativeModule) }
+ startKoin { modules(appModule(appVariant) + platformModule() + nativeModule) }
}
/*