Let element enterprise be able to configure id for mapTiler. (#4446)

* Let element enterprise configure the ids for maptiler service.

* Disable location sharing and location viewer is the service is not available.

* Fix compilation issue on connected test

* Do not allow to reload the map if the mapId is not available.

* Update screenshots

* Rename file.

* Better to inject a string provider here, so we can unit test DefaultLocationService.

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Benoit Marty 2025-03-21 17:06:52 +01:00 committed by GitHub
parent 60f1c9500f
commit 2fd1c21df0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 198 additions and 36 deletions

View file

@ -0,0 +1,12 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.location.api
interface LocationService {
fun isServiceAvailable(): Boolean
}

View file

@ -103,6 +103,7 @@ fun StaticMapView(
} else {
StaticMapPlaceholder(
showProgress = collectedState.value.isLoading(),
canReload = builder.isServiceAvailable(),
contentDescription = contentDescription,
width = maxWidth,
height = maxHeight,

View file

@ -57,6 +57,8 @@ internal class MapTilerStaticMapUrlBuilder(
// to keep the perceived content size constant at the expense of sharpness.
return "$MAPTILER_BASE_URL/$mapId/static/$lon,$lat,$finalZoom/${finalWidth}x${finalHeight}$scale.webp?key=$apiKey&attribution=bottomleft"
}
override fun isServiceAvailable() = apiKey.isNotEmpty()
}
private fun coerceWidthAndHeight(width: Int, height: Int, is2x: Boolean): Pair<Int, Int> {

View file

@ -9,8 +9,10 @@ package io.element.android.features.location.api.internal
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -18,7 +20,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.compound.tokens.generated.CompoundIcons
@ -28,12 +29,12 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.BooleanProvider
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
internal fun StaticMapPlaceholder(
showProgress: Boolean,
canReload: Boolean,
contentDescription: String?,
width: Dp,
height: Dp,
@ -54,7 +55,7 @@ internal fun StaticMapPlaceholder(
)
if (showProgress) {
CircularProgressIndicator()
} else {
} else if (canReload) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -70,14 +71,24 @@ internal fun StaticMapPlaceholder(
@PreviewsDayNight
@Composable
internal fun StaticMapPlaceholderPreview(
@PreviewParameter(BooleanProvider::class) values: Boolean
) = ElementPreview {
StaticMapPlaceholder(
showProgress = values,
contentDescription = null,
width = 400.dp,
height = 400.dp,
onLoadMapClick = {},
)
internal fun StaticMapPlaceholderPreview() = ElementPreview {
Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
listOf(
true to false,
false to true,
false to false,
).forEach { (showProgress, canReload) ->
StaticMapPlaceholder(
showProgress = showProgress,
canReload = canReload,
contentDescription = null,
width = 400.dp,
height = 200.dp,
onLoadMapClick = {},
)
}
}
}

View file

@ -22,6 +22,8 @@ interface StaticMapUrlBuilder {
height: Int,
density: Float,
): String
fun isServiceAvailable(): Boolean
}
fun StaticMapUrlBuilder(context: Context): StaticMapUrlBuilder = MapTilerStaticMapUrlBuilder(context = context)

View file

@ -17,6 +17,21 @@ class MapTilerStaticMapUrlBuilderTest {
darkMapId = "aDarkMapId",
)
@Test
fun `isServiceAvailable returns true if api key is not empty`() {
assertThat(builder.isServiceAvailable()).isTrue()
}
@Test
fun `isServiceAvailable returns false if api key is empty`() {
val builderWithoutKey = MapTilerStaticMapUrlBuilder(
apiKey = "",
lightMapId = "aLightMapId",
darkMapId = "aDarkMapId",
)
assertThat(builderWithoutKey.isServiceAvailable()).isFalse()
}
@Test
fun `static map 1x density`() {
assertThat(