Modularize CustomTileProviderRepository (#3181)

This commit is contained in:
Phil Oliver
2025-09-24 10:20:35 -04:00
committed by GitHub
parent 84d1888bae
commit 5bb3f73e0d
7 changed files with 96 additions and 64 deletions

View File

@@ -17,9 +17,6 @@
package com.geeksville.mesh.di
import com.geeksville.mesh.repository.map.CustomTileProviderRepository
import com.geeksville.mesh.repository.map.SharedPreferencesCustomTileProviderRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -35,14 +32,3 @@ object MapModule {
@Provides @Singleton
fun provideJson(): Json = Json { prettyPrint = false }
}
@Module
@InstallIn(SingletonComponent::class)
abstract class MapRepositoryModule {
@Binds
@Singleton
abstract fun bindCustomTileProviderRepository(
impl: SharedPreferencesCustomTileProviderRepository,
): CustomTileProviderRepository
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.repository.map
import com.geeksville.mesh.ui.map.CustomTileProviderConfig
import kotlinx.coroutines.flow.Flow
interface CustomTileProviderRepository {
fun getCustomTileProviders(): Flow<List<CustomTileProviderConfig>>
suspend fun addCustomTileProvider(config: CustomTileProviderConfig)
suspend fun updateCustomTileProvider(config: CustomTileProviderConfig)
suspend fun deleteCustomTileProvider(configId: String)
suspend fun getCustomTileProviderById(configId: String): CustomTileProviderConfig?
}

View File

@@ -1,97 +0,0 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.repository.map
import com.geeksville.mesh.ui.map.CustomTileProviderConfig
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import org.meshtastic.core.di.annotation.IoDispatcher
import org.meshtastic.core.prefs.map.MapTileProviderPrefs
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SharedPreferencesCustomTileProviderRepository
@Inject
constructor(
private val json: Json,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
private val mapTileProviderPrefs: MapTileProviderPrefs,
) : CustomTileProviderRepository {
private val customTileProvidersStateFlow = MutableStateFlow<List<CustomTileProviderConfig>>(emptyList())
init {
loadDataFromPrefs()
}
private fun loadDataFromPrefs() {
val jsonString = mapTileProviderPrefs.customTileProviders
if (jsonString != null) {
try {
customTileProvidersStateFlow.value = json.decodeFromString<List<CustomTileProviderConfig>>(jsonString)
} catch (e: SerializationException) {
Timber.tag("TileRepo").e(e, "Error deserializing tile providers")
customTileProvidersStateFlow.value = emptyList()
}
} else {
customTileProvidersStateFlow.value = emptyList()
}
}
private suspend fun saveDataToPrefs(providers: List<CustomTileProviderConfig>) {
withContext(ioDispatcher) {
try {
val jsonString = json.encodeToString(providers)
mapTileProviderPrefs.customTileProviders = jsonString
} catch (e: SerializationException) {
Timber.tag("TileRepo").e(e, "Error serializing tile providers")
}
}
}
override fun getCustomTileProviders(): Flow<List<CustomTileProviderConfig>> =
customTileProvidersStateFlow.asStateFlow()
override suspend fun addCustomTileProvider(config: CustomTileProviderConfig) {
val newList = customTileProvidersStateFlow.value + config
customTileProvidersStateFlow.value = newList
saveDataToPrefs(newList)
}
override suspend fun updateCustomTileProvider(config: CustomTileProviderConfig) {
val newList = customTileProvidersStateFlow.value.map { if (it.id == config.id) config else it }
customTileProvidersStateFlow.value = newList
saveDataToPrefs(newList)
}
override suspend fun deleteCustomTileProvider(configId: String) {
val newList = customTileProvidersStateFlow.value.filterNot { it.id == configId }
customTileProvidersStateFlow.value = newList
saveDataToPrefs(newList)
}
override suspend fun getCustomTileProviderById(configId: String): CustomTileProviderConfig? =
customTileProvidersStateFlow.value.find { it.id == configId }
}

View File

@@ -26,7 +26,6 @@ import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import com.geeksville.mesh.repository.map.CustomTileProviderRepository
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.TileProvider
import com.google.android.gms.maps.model.UrlTileProvider
@@ -50,6 +49,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import org.json.JSONObject
import org.meshtastic.core.data.model.CustomTileProviderConfig
import org.meshtastic.core.data.repository.CustomTileProviderRepository
import org.meshtastic.core.prefs.map.GoogleMapsPrefs
import org.meshtastic.core.prefs.map.MapPrefs
import timber.log.Timber
@@ -510,10 +511,3 @@ data class MapLayerItem(
var geoJsonLayerData: GeoJsonLayer? = null,
val layerType: LayerType,
)
@Serializable
data class CustomTileProviderConfig(
val id: String = UUID.randomUUID().toString(),
val name: String,
val urlTemplate: String,
)

View File

@@ -51,9 +51,9 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ui.map.CustomTileProviderConfig
import com.geeksville.mesh.ui.map.MapViewModel
import kotlinx.coroutines.flow.collectLatest
import org.meshtastic.core.data.model.CustomTileProviderConfig
import org.meshtastic.core.strings.R
@Suppress("LongMethod")