Disable location sharing when no MapTiler config is available

LocationService now exposes the MapTiler config to use: the one provided by the
homeserver takes precedence over the build time one, and null means that no map
provider is configured. It is now session scoped, and isServiceAvailable()
returns a StateFlow derived from this config.

When no config is available:
- the location sharing option is hidden from the composer, and location events
  cannot be opened in the location viewer;
- the "Location sharing" entry is hidden from the settings;
- location events in the timeline render a placeholder, without performing any
  request to MapTiler.

The show and share location screens now get the config from LocationService
rather than fetching the homeserver config by themselves.

Closes element-hq/element-android-enterprise#69

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benoit Marty
2026-10-13 17:15:37 +02:00
parent 5104e044ff
commit 4b97d6ab96
28 changed files with 212 additions and 106 deletions
@@ -8,14 +8,31 @@
package io.element.android.features.location.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.location.api.BuildConfig
import dev.zacsweers.metro.SingleIn
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
import io.element.android.features.location.api.LocationService
import io.element.android.features.location.api.buildTimeMapTilerConfig
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
@ContributesBinding(AppScope::class)
class DefaultLocationService : LocationService {
override fun isServiceAvailable(): Boolean {
return BuildConfig.MAPTILER_API_KEY.isNotEmpty()
}
@SingleIn(SessionScope::class)
@ContributesBinding(SessionScope::class)
class DefaultLocationService(
customMapTilerConfigProvider: CustomMapTilerConfigProvider,
@SessionCoroutineScope sessionCoroutineScope: CoroutineScope,
) : LocationService {
override val mapTilerConfig: StateFlow<MapTilerConfig?> = flow {
customMapTilerConfigProvider.get().getOrNull()?.let { emit(it) }
}.stateIn(
scope = sessionCoroutineScope,
started = SharingStarted.Eagerly,
initialValue = buildTimeMapTilerConfig(),
)
}
@@ -14,7 +14,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@@ -22,7 +21,7 @@ import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.Composer
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
import io.element.android.features.location.api.LocationService
import io.element.android.features.location.api.live.ActiveLiveLocationShareManager
import io.element.android.features.location.impl.common.LocationConstraintsCheck
import io.element.android.features.location.impl.common.MapDefaults
@@ -38,7 +37,6 @@ import io.element.android.features.location.impl.common.userlocation.UserLocatio
import io.element.android.features.location.impl.live.LiveLocationStore
import io.element.android.features.messages.api.MessageComposerContext
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.core.extensions.flatMap
@@ -73,7 +71,7 @@ class ShareLocationPresenter(
private val liveLocationShareManager: ActiveLiveLocationShareManager,
private val liveLocationStore: LiveLocationStore,
private val userLocationStateFactory: UserLocationState.Factory,
private val customMapTilerConfigProvider: CustomMapTilerConfigProvider,
private val locationService: LocationService,
) : Presenter<ShareLocationState> {
@AssistedFactory
fun interface Factory {
@@ -94,10 +92,7 @@ class ShareLocationPresenter(
var pendingLiveLocationShare by remember { mutableStateOf(false) }
val startLiveLocationAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
val currentUser by client.userProfile.collectAsState()
val customMapConfig by produceState(AsyncData.Loading()) {
// Ignore errors
value = AsyncData.Success(customMapTilerConfigProvider.get().getOrNull())
}
val mapTilerConfig by locationService.mapTilerConfig.collectAsState()
val sendLiveLocationPermissions by room.permissionsAsState(SendLiveLocationPermissions.DEFAULT) { perms ->
perms.sendLiveLocationPermissions()
}
@@ -201,7 +196,7 @@ class ShareLocationPresenter(
}
return ShareLocationState(
customMapTilerConfig = customMapConfig,
mapTilerConfig = mapTilerConfig,
currentUser = currentUser,
dialogState = dialogState,
trackUserLocation = trackUserPosition,
@@ -12,12 +12,11 @@ import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.userlocation.UserLocationState
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList
data class ShareLocationState(
val customMapTilerConfig: AsyncData<MapTilerConfig?>,
val mapTilerConfig: MapTilerConfig?,
val currentUser: MatrixUser,
val dialogState: Dialog,
val trackUserLocation: Boolean,
@@ -12,8 +12,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.userlocation.UserLocationState
import io.element.android.features.location.impl.show.aPreviewMapTilerConfig
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.persistentListOf
@@ -71,13 +71,13 @@ class ShareLocationStatePreviewParam : PreviewParameterProvider<ShareLocationSta
canShareLiveLocation = true,
),
aShareLocationState(
customMapTilerConfig = AsyncData.Loading(),
mapTilerConfig = null,
),
)
}
fun aShareLocationState(
customMapTilerConfig: AsyncData<MapTilerConfig?> = AsyncData.Success(null),
mapTilerConfig: MapTilerConfig? = aPreviewMapTilerConfig(),
currentUser: MatrixUser = MatrixUser(UserId("@user:matrix.org")),
dialogState: ShareLocationState.Dialog = ShareLocationState.Dialog.None,
trackUserPosition: Boolean = false,
@@ -88,7 +88,7 @@ fun aShareLocationState(
eventSink: (ShareLocationEvent) -> Unit = {},
): ShareLocationState {
return ShareLocationState(
customMapTilerConfig = customMapTilerConfig,
mapTilerConfig = mapTilerConfig,
currentUser = currentUser,
dialogState = dialogState,
trackUserLocation = trackUserPosition,
@@ -130,7 +130,7 @@ private fun ShareLocationViewContent(
navigateUp: () -> Unit,
modifier: Modifier = Modifier,
) {
val tileStyleUrl = rememberTileStyleUrl(state.customMapTilerConfig.dataOrNull())
val tileStyleUrl = rememberTileStyleUrl(state.mapTilerConfig)
val mapState = rememberMapState(
baseStyle = BaseStyle.Uri(tileStyleUrl),
initialCameraPosition = MapDefaults.defaultCameraPosition,
@@ -181,7 +181,7 @@ private fun ShareLocationScaffold(
)
)
MapBottomSheetScaffold(
isReady = state.customMapTilerConfig.isReady(),
isReady = state.mapTilerConfig != null,
mapState = mapState,
modifier = modifier,
scaffoldState = scaffoldState,
@@ -22,8 +22,8 @@ import androidx.compose.runtime.setValue
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
import io.element.android.features.location.api.Location
import io.element.android.features.location.api.LocationService
import io.element.android.features.location.api.ShowLocationMode
import io.element.android.features.location.api.live.ActiveLiveLocationShareManager
import io.element.android.features.location.api.live.isCurrentlySharing
@@ -39,7 +39,6 @@ import io.element.android.features.location.impl.common.toDialogState
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.userlocation.UserLocationState
import io.element.android.features.location.impl.common.userlocation.toLocationMeasurement
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.mapState
import io.element.android.libraries.core.meta.BuildMeta
@@ -68,7 +67,7 @@ class ShowLocationPresenter(
private val joinedRoom: JoinedRoom,
private val liveLocationShareManager: ActiveLiveLocationShareManager,
private val userLocationStateFactory: UserLocationState.Factory,
private val customMapTilerConfigProvider: CustomMapTilerConfigProvider,
private val locationService: LocationService,
) : Presenter<ShowLocationState> {
@AssistedFactory fun interface Factory {
fun create(mode: ShowLocationMode): ShowLocationPresenter
@@ -86,10 +85,7 @@ class ShowLocationPresenter(
mutableStateOf(LocationConstraintsDialogState.None)
}
val customMapTilerConfig by produceState(AsyncData.Loading()) {
// Ignore errors
value = AsyncData.Success(customMapTilerConfigProvider.get().getOrNull())
}
val mapTilerConfig by locationService.mapTilerConfig.collectAsState()
fun checkLocationConstraints() {
val locationConstraints = checkLocationConstraints(
@@ -221,7 +217,7 @@ class ShowLocationPresenter(
userLocationStateFactory.create(hasLocationPermission = permissionsState.isAnyGranted)
}
return ShowLocationState(
customMapTilerConfig = customMapTilerConfig,
mapTilerConfig = mapTilerConfig,
dialogState = dialogState,
locationShares = locationShares,
focusedLocation = focusedLocation,
@@ -13,7 +13,6 @@ import io.element.android.features.location.api.Location
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.ui.LocationMarkerData
import io.element.android.features.location.impl.common.userlocation.UserLocationState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.PinVariant
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.core.UserId
@@ -21,7 +20,7 @@ import io.element.android.libraries.matrix.api.room.location.AssetType
import kotlinx.collections.immutable.ImmutableList
data class ShowLocationState(
val customMapTilerConfig: AsyncData<MapTilerConfig?>,
val mapTilerConfig: MapTilerConfig?,
val isLive: Boolean,
val dialogState: LocationConstraintsDialogState,
val locationShares: ImmutableList<LocationShareItem>,
@@ -13,7 +13,6 @@ import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
import io.element.android.features.location.api.Location
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.userlocation.UserLocationState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.USER_NAME_ALICE
@@ -37,14 +36,21 @@ class ShowLocationStatePreviewParam : PreviewParameterProvider<ShowLocationState
constraintsDialogState = LocationConstraintsDialogState.LocationServiceDisabled,
),
aShowLocationState(isTrackMyLocation = true),
aShowLocationState(customMapTilerConfig = AsyncData.Loading()),
aShowLocationState(mapTilerConfig = null),
)
}
private const val APP_NAME = "ApplicationName"
internal fun aPreviewMapTilerConfig() = MapTilerConfig(
apiKey = "preview_api_key",
lightStyleId = null,
darkStyleId = null,
baseUrl = null,
)
fun aShowLocationState(
customMapTilerConfig: AsyncData<MapTilerConfig?> = AsyncData.Success(null),
mapTilerConfig: MapTilerConfig? = aPreviewMapTilerConfig(),
isLive: Boolean = false,
constraintsDialogState: LocationConstraintsDialogState = LocationConstraintsDialogState.None,
locationShares: List<LocationShareItem> = listOf(aLocationShareItem(isLive = isLive)),
@@ -56,7 +62,7 @@ fun aShowLocationState(
eventSink: (ShowLocationEvent) -> Unit = {},
): ShowLocationState {
return ShowLocationState(
customMapTilerConfig = customMapTilerConfig,
mapTilerConfig = mapTilerConfig,
dialogState = constraintsDialogState,
locationShares = locationShares.toImmutableList(),
focusedLocation = focusedLocation,
@@ -102,7 +102,7 @@ private fun ShowLocationViewContent(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val tileStyleUrl = rememberTileStyleUrl(state.customMapTilerConfig.dataOrNull())
val tileStyleUrl = rememberTileStyleUrl(state.mapTilerConfig)
val mapState = rememberMapState(
baseStyle = BaseStyle.Uri(tileStyleUrl),
initialCameraPosition = MapDefaults.defaultCameraPosition,
@@ -178,7 +178,7 @@ private fun ShowLocationScaffold(
}
}
MapBottomSheetScaffold(
isReady = state.customMapTilerConfig.isReady(),
isReady = state.mapTilerConfig != null,
sheetDragHandle = if (state.isSheetDraggable) {
{ BottomSheetDefaults.DragHandle() }
} else {
@@ -9,15 +9,56 @@
package io.element.android.features.location.impl
import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
import io.element.android.features.enterprise.test.remoteconfig.aMapTilerConfig
import io.element.android.features.location.api.BuildConfig
import io.element.android.features.location.api.buildTimeMapTilerConfig
import io.element.android.libraries.matrix.test.AN_EXCEPTION
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@OptIn(ExperimentalCoroutinesApi::class)
class DefaultLocationServiceTest {
@Test
fun `isServiceAvailable should return value depending on BuildConfig MAPTILER_API_KEY`() {
val locationService = DefaultLocationService()
assertThat(locationService.isServiceAvailable()).isEqualTo(
BuildConfig.MAPTILER_API_KEY.isNotEmpty()
fun `when the homeserver does not provide a config, the build time config is used`() = runTest {
val locationService = createDefaultLocationService(
customMapTilerConfigProvider = { Result.success(null) },
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(buildTimeMapTilerConfig())
assertThat(locationService.isServiceAvailable().value).isEqualTo(BuildConfig.MAPTILER_API_KEY.isNotEmpty())
}
@Test
fun `when the homeserver config cannot be retrieved, the build time config is used`() = runTest {
val locationService = createDefaultLocationService(
customMapTilerConfigProvider = { Result.failure(AN_EXCEPTION) },
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(buildTimeMapTilerConfig())
assertThat(locationService.isServiceAvailable().value).isEqualTo(BuildConfig.MAPTILER_API_KEY.isNotEmpty())
}
@Test
fun `when the homeserver provides a config, it is used and the service is available`() = runTest {
val config = aMapTilerConfig(apiKey = "homeserver_api_key")
val locationService = createDefaultLocationService(
customMapTilerConfigProvider = { Result.success(config) },
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(config)
assertThat(locationService.isServiceAvailable().value).isTrue()
}
private fun TestScope.createDefaultLocationService(
customMapTilerConfigProvider: CustomMapTilerConfigProvider,
sessionCoroutineScope: CoroutineScope = backgroundScope,
) = DefaultLocationService(
customMapTilerConfigProvider = customMapTilerConfigProvider,
sessionCoroutineScope = sessionCoroutineScope,
)
}
@@ -16,6 +16,7 @@ import io.element.android.features.location.impl.common.actions.FakeLocationActi
import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter
import io.element.android.features.location.impl.live.LiveLocationStore
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.location.test.FakeLocationService
import io.element.android.features.messages.test.FakeMessageComposerContext
import io.element.android.libraries.dateformatter.test.FakeDurationFormatter
import io.element.android.libraries.matrix.api.timeline.Timeline
@@ -58,7 +59,7 @@ class DefaultShareLocationEntryPointTest {
sessionId = room.sessionId,
),
userLocationStateFactory = FakeUserLocationStateFactory(),
customMapTilerConfigProvider = { Result.success(null) },
locationService = FakeLocationService(),
)
},
analyticsService = FakeAnalyticsService(),
@@ -19,9 +19,9 @@ import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.Composer
import io.element.android.features.enterprise.api.remoteconfig.MapTilerConfig
import io.element.android.features.enterprise.test.remoteconfig.aMapTilerConfig
import io.element.android.features.location.api.Location
import io.element.android.features.location.api.LocationService
import io.element.android.features.location.impl.aPermissionsState
import io.element.android.features.location.impl.common.FakeUserLocationStateFactory
import io.element.android.features.location.impl.common.actions.FakeLocationActions
@@ -31,6 +31,7 @@ import io.element.android.features.location.impl.common.permissions.PermissionsS
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.live.LiveLocationStore
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.location.test.FakeLocationService
import io.element.android.features.messages.test.FakeMessageComposerContext
import io.element.android.libraries.dateformatter.test.FakeDurationFormatter
import io.element.android.libraries.matrix.api.core.EventId
@@ -89,7 +90,7 @@ class ShareLocationPresenterTest {
liveLocationShareManager: FakeActiveLiveLocationShareManager = FakeActiveLiveLocationShareManager(),
liveLocationStore: LiveLocationStore = createLiveLocationStore(sessionId = joinedRoom.sessionId),
client: FakeMatrixClient = fakeMatrixClient,
customMapTilerConfigProvider: () -> Result<MapTilerConfig?> = { Result.success(null) },
locationService: LocationService = FakeLocationService(mapTilerConfig = aMapTilerConfig()),
): ShareLocationPresenter = ShareLocationPresenter(
permissionsPresenterFactory = { fakePermissionsPresenter },
room = joinedRoom,
@@ -103,7 +104,7 @@ class ShareLocationPresenterTest {
liveLocationShareManager = liveLocationShareManager,
liveLocationStore = liveLocationStore,
userLocationStateFactory = FakeUserLocationStateFactory(),
customMapTilerConfigProvider = customMapTilerConfigProvider,
locationService = locationService,
)
@Test
@@ -118,26 +119,24 @@ class ShareLocationPresenterTest {
val shareLocationPresenter = createShareLocationPresenter()
shareLocationPresenter.test {
val state = awaitFirstItem()
assertThat(state.customMapTilerConfig.isLoading()).isFalse()
assertThat(state.mapTilerConfig).isNotNull()
assertThat(state.trackUserLocation).isTrue()
assertThat(state.dialogState).isEqualTo(ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.None))
}
}
@Test
fun `present - non-null customMapStyleUrl`() = runTest {
fun `present - mapTilerConfig is provided by the location service`() = runTest {
val mapTilerConfig = aMapTilerConfig(apiKey = "A KEY")
val shareLocationPresenter = createShareLocationPresenter(
client = FakeMatrixClient(
sessionId = A_USER_ID,
),
customMapTilerConfigProvider = { Result.success(mapTilerConfig) }
locationService = FakeLocationService(mapTilerConfig = mapTilerConfig),
)
shareLocationPresenter.test {
val state = awaitItem()
assertThat(state.customMapTilerConfig.isLoading()).isTrue()
val finalState = awaitItem()
assertThat(finalState.customMapTilerConfig.dataOrNull()).isEqualTo(mapTilerConfig)
assertThat(awaitItem().mapTilerConfig).isEqualTo(mapTilerConfig)
cancelAndIgnoreRemainingEvents()
}
}
@@ -18,6 +18,7 @@ import io.element.android.features.location.impl.common.FakeUserLocationStateFac
import io.element.android.features.location.impl.common.actions.FakeLocationActions
import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.location.test.FakeLocationService
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.test.core.aBuildMeta
@@ -51,7 +52,7 @@ class DefaultShowLocationEntryPointTest {
joinedRoom = joinedRoom,
liveLocationShareManager = FakeActiveLiveLocationShareManager(),
userLocationStateFactory = FakeUserLocationStateFactory(),
customMapTilerConfigProvider = { Result.success(null) },
locationService = FakeLocationService(),
)
},
analyticsService = FakeAnalyticsService(),
@@ -12,9 +12,9 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.api.remoteconfig.CustomMapTilerConfigProvider
import io.element.android.features.enterprise.test.remoteconfig.aMapTilerConfig
import io.element.android.features.location.api.Location
import io.element.android.features.location.api.LocationService
import io.element.android.features.location.api.ShowLocationMode
import io.element.android.features.location.impl.aPermissionsState
import io.element.android.features.location.impl.common.FakeUserLocationStateFactory
@@ -24,6 +24,7 @@ import io.element.android.features.location.impl.common.permissions.PermissionsE
import io.element.android.features.location.impl.common.permissions.PermissionsState
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.test.FakeActiveLiveLocationShareManager
import io.element.android.features.location.test.FakeLocationService
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.JoinedRoom
@@ -66,7 +67,7 @@ class ShowLocationPresenterTest {
locationActions: FakeLocationActions = fakeLocationActions,
joinedRoom: JoinedRoom = FakeJoinedRoom(),
liveLocationShareManager: FakeActiveLiveLocationShareManager = FakeActiveLiveLocationShareManager(),
customMapTilerConfigProvider: CustomMapTilerConfigProvider = { Result.success(null) },
locationService: LocationService = FakeLocationService(mapTilerConfig = aMapTilerConfig()),
) = ShowLocationPresenter(
mode = mode,
permissionsPresenterFactory = { fakePermissionsPresenter },
@@ -77,18 +78,16 @@ class ShowLocationPresenterTest {
joinedRoom = joinedRoom,
liveLocationShareManager = liveLocationShareManager,
userLocationStateFactory = FakeUserLocationStateFactory(),
customMapTilerConfigProvider = customMapTilerConfigProvider,
locationService = locationService,
)
@Test
fun `present - non-null customMapStyleUrl`() = runTest {
fun `present - mapTilerConfig is provided by the location service`() = runTest {
val mapTilerConfig = aMapTilerConfig(apiKey = "A KEY")
val shareLocationPresenter = createShowLocationPresenter(customMapTilerConfigProvider = { Result.success(mapTilerConfig) })
shareLocationPresenter.test {
val state = awaitItem()
assertThat(state.customMapTilerConfig.isLoading()).isTrue()
val finalState = awaitItem()
assertThat(finalState.customMapTilerConfig.dataOrNull()).isEqualTo(mapTilerConfig)
val showLocationPresenter = createShowLocationPresenter(locationService = FakeLocationService(mapTilerConfig = mapTilerConfig))
showLocationPresenter.test {
assertThat(awaitItem().mapTilerConfig).isEqualTo(mapTilerConfig)
cancelAndIgnoreRemainingEvents()
}
}
@@ -120,7 +119,7 @@ class ShowLocationPresenterTest {
fun `centers on user location`() = runTest {
fakePermissionsPresenter.givenState(aPermissionsState(permissions = PermissionsState.Permissions.AllGranted))
val presenter = createShowLocationPresenter(customMapTilerConfigProvider = { Result.success(aMapTilerConfig()) })
val presenter = createShowLocationPresenter()
presenter.test {
val initialState = awaitItem()
@@ -407,9 +406,6 @@ class ShowLocationPresenterTest {
val initialState = awaitItem()
assertThat(initialState.locationShares).isEmpty()
// Wait until we receive the custom map style URL result
skipItems(1)
// Emit a new live share
liveSharesFlow.value = listOf(
aLiveLocationShare(userId = userId)