Skip to content

Commit 1d99189

Browse files
authored
Merge pull request #886 from vector-im/feature/cjs/location-api-key
2 parents b6e35de + 9ef8b36 commit 1d99189

File tree

9 files changed

+128
-218
lines changed

9 files changed

+128
-218
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
with:
3939
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
4040
- name: Assemble debug APK
41+
env:
42+
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
4143
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
4244
- name: Upload debug APKs
4345
uses: actions/upload-artifact@v3

.github/workflows/nightly.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
run: |
3636
./gradlew assembleNightly appDistributionUploadNightly $CI_GRADLE_ARG_PROPERTIES
3737
env:
38+
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
3839
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
3940
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
4041
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}

docs/maps.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Use of maps
2+
3+
<!--- TOC -->
4+
5+
* [Overview](#overview)
6+
* [Local development with MapTiler](#local-development-with-maptiler)
7+
* [Making releasable builds with MapTiler](#making-releasable-builds-with-maptiler)
8+
* [Using other map sources or MapTiler styles](#using-other-map-sources-or-maptiler-styles)
9+
10+
<!--- END -->
11+
12+
## Overview
13+
14+
Element Android uses [MapTiler](https://www.maptiler.com/) to provide map
15+
imagery where required. MapTiler requires an API key, which we bake in to
16+
the app at release time.
17+
18+
## Local development with MapTiler
19+
20+
If you're developing the application and want maps to render properly you can
21+
sign up for the [MapTiler free tier](https://www.maptiler.com/cloud/pricing/).
22+
23+
Place your API key in `local.properties` with the key
24+
`services.maptiler.apikey`, e.g.:
25+
26+
```properties
27+
services.maptiler.apikey=abCd3fGhijK1mN0pQr5t
28+
```
29+
30+
## Making releasable builds with MapTiler
31+
32+
To insert the MapTiler API key when building an APK, set the
33+
`ELEMENT_ANDROID_MAPTILER_API_KEY` environment variable in your build
34+
environment.
35+
36+
## Using other map sources or MapTiler styles
37+
38+
If you wish to use an alternative map provider, or custom MapTiler styles,
39+
you can customise the functions in
40+
`features/location/api/src/main/kotlin/io/element/android/features/location/api/internal/MapUrls.kt`.
41+
We've kept this file small and self contained to minimise the chances of merge
42+
collisions in forks.

features/location/api/build.gradle.kts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,33 @@
1414
* limitations under the License.
1515
*/
1616

17+
import java.util.Properties
18+
1719
plugins {
1820
id("io.element.android-compose-library")
1921
alias(libs.plugins.ksp)
2022
id("kotlin-parcelize")
2123
}
2224

25+
fun readLocalProperty(name: String) = Properties().apply {
26+
try {
27+
load(rootProject.file("local.properties").reader())
28+
} catch (ignored: java.io.IOException) {
29+
}
30+
}[name]
31+
2332
android {
2433
namespace = "io.element.android.features.location.api"
34+
35+
defaultConfig {
36+
resValue(
37+
type = "string",
38+
name = "maptiler_api_key",
39+
value = System.getenv("ELEMENT_ANDROID_MAPTILER_API_KEY")
40+
?: readLocalProperty("services.maptiler.apikey") as? String
41+
?: ""
42+
)
43+
}
2544
}
2645

2746
dependencies {

features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ import androidx.compose.ui.unit.dp
3434
import coil.compose.AsyncImagePainter
3535
import coil.compose.rememberAsyncImagePainter
3636
import coil.request.ImageRequest
37-
import io.element.android.features.location.api.internal.AttributionPlacement
3837
import io.element.android.features.location.api.internal.StaticMapPlaceholder
39-
import io.element.android.features.location.api.internal.buildStaticMapsApiUrl
38+
import io.element.android.features.location.api.internal.staticMapUrl
4039
import io.element.android.libraries.designsystem.preview.DayNightPreviews
4140
import io.element.android.libraries.designsystem.preview.ElementPreview
4241
import io.element.android.libraries.designsystem.text.toDp
@@ -64,6 +63,7 @@ fun StaticMapView(
6463
modifier = modifier,
6564
contentAlignment = Alignment.Center
6665
) {
66+
val context = LocalContext.current
6767
var retryHash by remember { mutableStateOf(0) }
6868
val painter = rememberAsyncImagePainter(
6969
model = if (constraints.isZero) {
@@ -72,17 +72,16 @@ fun StaticMapView(
7272
} else {
7373
ImageRequest.Builder(LocalContext.current)
7474
.data(
75-
buildStaticMapsApiUrl(
75+
staticMapUrl(
76+
context = context,
7677
lat = lat,
7778
lon = lon,
78-
desiredZoom = zoom,
79+
zoom = zoom,
7980
darkMode = darkMode,
80-
attributionPlacement = AttributionPlacement.BottomLeft,
8181
// Size the map based on DP rather than pixels, as otherwise the features and attribution
8282
// end up being illegibly tiny on high density displays.
83-
desiredWidth = constraints.maxWidth.toDp().value.toInt(),
84-
desiredHeight = constraints.maxHeight.toDp().value.toInt(),
85-
doubleScale = true,
83+
width = constraints.maxWidth.toDp().value.toInt(),
84+
height = constraints.maxHeight.toDp().value.toInt(),
8685
)
8786
)
8887
.size(width = constraints.maxWidth, height = constraints.maxHeight)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.location.api.internal
18+
19+
import android.content.Context
20+
import io.element.android.features.location.api.R
21+
22+
/**
23+
* Provides the URL to an image that contains a statically-generated map of the given location.
24+
*/
25+
fun staticMapUrl(
26+
context: Context,
27+
lat: Double,
28+
lon: Double,
29+
zoom: Double,
30+
width: Int,
31+
height: Int,
32+
darkMode: Boolean,
33+
): String {
34+
return "${baseUrl(darkMode)}/static/${lon},${lat},${zoom}/${width}x${height}@2x.webp?key=${context.apiKey}&attribution=bottomleft"
35+
}
36+
37+
/**
38+
* Provides the URL to a MapLibre style document, used for rendering dynamic maps.
39+
*/
40+
fun tileStyleUrl(
41+
context: Context,
42+
darkMode: Boolean,
43+
): String {
44+
return "${baseUrl(darkMode)}/style.json?key=${context.apiKey}"
45+
}
46+
47+
private fun baseUrl(darkMode: Boolean) =
48+
"https://api.maptiler.com/maps/" +
49+
if (darkMode)
50+
"dea61faf-292b-4774-9660-58fcef89a7f3"
51+
else
52+
"9bc819c8-e627-474a-a348-ec144fe3d810"
53+
54+
private val Context.apiKey: String
55+
get() = getString(R.string.maptiler_api_key)

features/location/api/src/main/kotlin/io/element/android/features/location/api/internal/MapsUtils.kt

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)