Files
GPS2Audio/app/src/main/kotlin/de/waypointaudio/data/MapProvider.kt
T
2026-05-30 05:42:44 +00:00

144 lines
5.8 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package de.waypointaudio.data
import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import org.osmdroid.tileprovider.tilesource.ITileSource
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.tileprovider.tilesource.XYTileSource
import org.osmdroid.util.MapTileIndex
/**
* Verfügbare Karten-Anbieter (Phase 1 von v2.0.0).
*
* Alle Provider werden via [org.osmdroid.tileprovider.tilesource.XYTileSource]
* angebunden — kein Library-Wechsel nötig. Die OSM-Attribution
* (siehe `osm_attribution_short`) bleibt für sämtliche Provider sichtbar.
*
* Hinweise zu Provider-spezifischen Bedingungen:
* - **CartoDB** Tiles dürfen für nicht-kommerzielle Nutzung frei verwendet
* werden (Attribution `© OpenStreetMap & CartoDB`).
* - **OpenTopoMap** ist für nicht-kommerzielle Nutzung frei.
* - **ESRI** Tiles sind für persönliche, nicht-kommerzielle Nutzung
* via Attribution `© Esri` erlaubt.
* - **Stadia Maps** verlangt einen API-Key für produktive Nutzung; der Default
* funktioniert für Tests; im Zweifel CartoDB/OSM verwenden.
*/
enum class MapProvider(
val key: String,
val displayNameRes: Int
) {
OSM("osm", de.waypointaudio.R.string.map_provider_osm),
CARTO_POSITRON("carto_positron", de.waypointaudio.R.string.map_provider_carto_positron),
CARTO_DARK("carto_dark", de.waypointaudio.R.string.map_provider_carto_dark),
OPEN_TOPO("open_topo", de.waypointaudio.R.string.map_provider_topo),
ESRI_SATELLITE("esri_satellite", de.waypointaudio.R.string.map_provider_esri_satellite),
ESRI_HYBRID("esri_hybrid", de.waypointaudio.R.string.map_provider_esri_hybrid),
STADIA_ALIDADE("stadia_alidade", de.waypointaudio.R.string.map_provider_stadia_alidade),
STADIA_OUTDOORS("stadia_outdoors", de.waypointaudio.R.string.map_provider_stadia_outdoors);
fun toTileSource(): ITileSource = when (this) {
OSM -> TileSourceFactory.MAPNIK
CARTO_POSITRON -> XYTileSource(
"CartoDB Positron", 1, 19, 256, ".png",
arrayOf(
"https://a.basemaps.cartocdn.com/light_all/",
"https://b.basemaps.cartocdn.com/light_all/",
"https://c.basemaps.cartocdn.com/light_all/"
),
"© OpenStreetMap-Mitwirkende, © CARTO"
)
CARTO_DARK -> XYTileSource(
"CartoDB Dark Matter", 1, 19, 256, ".png",
arrayOf(
"https://a.basemaps.cartocdn.com/dark_all/",
"https://b.basemaps.cartocdn.com/dark_all/",
"https://c.basemaps.cartocdn.com/dark_all/"
),
"© OpenStreetMap-Mitwirkende, © CARTO"
)
OPEN_TOPO -> XYTileSource(
"OpenTopoMap", 1, 17, 256, ".png",
arrayOf(
"https://a.tile.opentopomap.org/",
"https://b.tile.opentopomap.org/",
"https://c.tile.opentopomap.org/"
),
"Karte: © OpenTopoMap (CC-BY-SA)"
)
ESRI_SATELLITE -> object : XYTileSource(
"ESRI World Imagery", 1, 19, 256, "",
arrayOf("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/"),
"Tiles © Esri"
) {
override fun getTileURLString(pMapTileIndex: Long): String {
return baseUrl +
MapTileIndex.getZoom(pMapTileIndex) + "/" +
MapTileIndex.getY(pMapTileIndex) + "/" +
MapTileIndex.getX(pMapTileIndex)
}
}
ESRI_HYBRID -> object : XYTileSource(
"ESRI Hybrid Reference", 1, 19, 256, "",
arrayOf("https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/"),
"Tiles © Esri"
) {
override fun getTileURLString(pMapTileIndex: Long): String {
return baseUrl +
MapTileIndex.getZoom(pMapTileIndex) + "/" +
MapTileIndex.getY(pMapTileIndex) + "/" +
MapTileIndex.getX(pMapTileIndex)
}
}
STADIA_ALIDADE -> XYTileSource(
"Stadia Alidade Smooth", 1, 20, 256, ".png",
arrayOf("https://tiles.stadiamaps.com/tiles/alidade_smooth/"),
"© Stadia Maps, © OpenStreetMap-Mitwirkende"
)
STADIA_OUTDOORS -> XYTileSource(
"Stadia Outdoors", 1, 20, 256, ".png",
arrayOf("https://tiles.stadiamaps.com/tiles/outdoors/"),
"© Stadia Maps, © OpenStreetMap-Mitwirkende"
)
}
companion object {
val DEFAULT = OSM
fun fromKey(key: String?): MapProvider =
values().firstOrNull { it.key == key } ?: DEFAULT
}
}
private val Context.mapProviderDataStore by preferencesDataStore(name = "map_provider_settings")
/**
* Persistiert den ausgewählten Karten-Provider app-weit.
*
* Hinweis: Die Auswahl ist bewusst app-weit (nicht pro Tour) gehalten Touren
* verwalten bisher keine kartenspezifischen Einstellungen, und der Wechsel des
* Anbieters ist im Karten-Menü jederzeit erreichbar.
*/
class MapProviderStore(private val context: Context) {
private companion object {
val KEY_PROVIDER = stringPreferencesKey("selected_map_provider")
}
val provider: Flow<MapProvider> = context.mapProviderDataStore.data.map { prefs ->
MapProvider.fromKey(prefs[KEY_PROVIDER])
}
suspend fun currentProvider(): MapProvider = provider.first()
suspend fun setProvider(provider: MapProvider) {
context.mapProviderDataStore.edit { prefs ->
prefs[KEY_PROVIDER] = provider.key
}
}
}