Move osm settings to its own settings page

This commit is contained in:
MM20 2024-06-30 14:38:33 +02:00
parent 429025e5ac
commit e96a382b00
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
10 changed files with 145 additions and 62 deletions

View File

@ -243,5 +243,6 @@ class SearchableItemVM : ListItemViewModel(), KoinComponent {
.stateIn(viewModelScope, SharingStarted.Lazily, false) .stateIn(viewModelScope, SharingStarted.Lazily, false)
val mapTileServerUrl = locationSearchSettings.tileServer val mapTileServerUrl = locationSearchSettings.tileServer
.map { it ?: LocationSearchSettings.DefaultTileServerUrl }
.stateIn(viewModelScope, SharingStarted.Lazily, "") .stateIn(viewModelScope, SharingStarted.Lazily, "")
} }

View File

@ -55,6 +55,7 @@ import de.mm20.launcher2.ui.settings.log.LogScreen
import de.mm20.launcher2.ui.settings.main.MainSettingsScreen import de.mm20.launcher2.ui.settings.main.MainSettingsScreen
import de.mm20.launcher2.ui.settings.media.MediaIntegrationSettingsScreen import de.mm20.launcher2.ui.settings.media.MediaIntegrationSettingsScreen
import de.mm20.launcher2.ui.settings.nextcloud.NextcloudSettingsScreen import de.mm20.launcher2.ui.settings.nextcloud.NextcloudSettingsScreen
import de.mm20.launcher2.ui.settings.osm.OsmSettingsScreen
import de.mm20.launcher2.ui.settings.owncloud.OwncloudSettingsScreen import de.mm20.launcher2.ui.settings.owncloud.OwncloudSettingsScreen
import de.mm20.launcher2.ui.settings.plugins.PluginSettingsScreen import de.mm20.launcher2.ui.settings.plugins.PluginSettingsScreen
import de.mm20.launcher2.ui.settings.plugins.PluginsSettingsScreen import de.mm20.launcher2.ui.settings.plugins.PluginsSettingsScreen
@ -106,7 +107,7 @@ class SettingsActivity : BaseActivity() {
navController = navController, navController = navController,
startDestination = "settings", startDestination = "settings",
exitTransition = { exitTransition = {
slideOutHorizontally { it / 4 } slideOutHorizontally {-it / 4 }
}, },
enterTransition = { enterTransition = {
slideInHorizontally { it / 2 } + scaleIn(initialScale = 0.9f) + fadeIn() slideInHorizontally { it / 2 } + scaleIn(initialScale = 0.9f) + fadeIn()
@ -162,6 +163,9 @@ class SettingsActivity : BaseActivity() {
composable("settings/search/locations") { composable("settings/search/locations") {
LocationsSettingsScreen() LocationsSettingsScreen()
} }
composable("settings/search/locations/osm") {
OsmSettingsScreen()
}
composable("settings/search/files") { composable("settings/search/files") {
FileSearchSettingsScreen() FileSearchSettingsScreen()
} }

View File

@ -29,20 +29,22 @@ import de.mm20.launcher2.ui.component.Banner
import de.mm20.launcher2.ui.component.preferences.ListPreference import de.mm20.launcher2.ui.component.preferences.ListPreference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.PreferenceWithSwitch
import de.mm20.launcher2.ui.component.preferences.SliderPreference import de.mm20.launcher2.ui.component.preferences.SliderPreference
import de.mm20.launcher2.ui.component.preferences.SwitchPreference import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.component.preferences.TextPreference import de.mm20.launcher2.ui.component.preferences.TextPreference
import de.mm20.launcher2.ui.ktx.metersToLocalizedString import de.mm20.launcher2.ui.ktx.metersToLocalizedString
import de.mm20.launcher2.ui.locals.LocalNavController
@Composable @Composable
fun LocationsSettingsScreen() { fun LocationsSettingsScreen() {
val viewModel: LocationsSettingsScreenVM = viewModel() val viewModel: LocationsSettingsScreenVM = viewModel()
val navController = LocalNavController.current
val osmLocations by viewModel.osmLocations.collectAsState() val osmLocations by viewModel.osmLocations.collectAsState()
val imperialUnits by viewModel.imperialUnits.collectAsState() val imperialUnits by viewModel.imperialUnits.collectAsState()
val hideUncategorized by viewModel.hideUncategorized.collectAsState()
val radius by viewModel.radius.collectAsState() val radius by viewModel.radius.collectAsState()
val customOverpassUrl by viewModel.customOverpassUrl.collectAsState()
val showMap by viewModel.showMap.collectAsState() val showMap by viewModel.showMap.collectAsState()
val themeMap by viewModel.themeMap.collectAsState() val themeMap by viewModel.themeMap.collectAsState()
val customTileServerUrl by viewModel.customTileServerUrl.collectAsState() val customTileServerUrl by viewModel.customTileServerUrl.collectAsState()
@ -59,12 +61,15 @@ fun LocationsSettingsScreen() {
PreferenceScreen(title = stringResource(R.string.preference_search_locations)) { PreferenceScreen(title = stringResource(R.string.preference_search_locations)) {
item { item {
PreferenceCategory { PreferenceCategory {
SwitchPreference( PreferenceWithSwitch(
title = stringResource(R.string.preference_search_osm_locations), title = stringResource(R.string.preference_search_osm_locations),
summary = stringResource(R.string.preference_search_osm_locations_summary), summary = stringResource(R.string.preference_search_osm_locations_summary),
value = osmLocations == true, switchValue = osmLocations == true,
onValueChanged = { onSwitchChanged = {
viewModel.setOsmLocations(it) viewModel.setOsmLocations(it)
},
onClick = {
navController?.navigate("settings/search/locations/osm")
} }
) )
AnimatedVisibility(plugins.isNotEmpty()) { AnimatedVisibility(plugins.isNotEmpty()) {
@ -150,15 +155,6 @@ fun LocationsSettingsScreen() {
.metersToLocalizedString(LocalContext.current, imperialUnits) .metersToLocalizedString(LocalContext.current, imperialUnits)
} }
) )
SwitchPreference(
title = stringResource(R.string.preference_search_locations_hide_uncategorized),
summary = stringResource(R.string.preference_search_locations_hide_uncategorized_summary),
value = hideUncategorized == true,
enabled = anyLocationProviderEnabled,
onValueChanged = {
viewModel.setHideUncategorized(it)
}
)
} }
} }
item { item {
@ -186,22 +182,11 @@ fun LocationsSettingsScreen() {
} }
item { item {
PreferenceCategory(stringResource(R.string.preference_category_advanced)) { PreferenceCategory(stringResource(R.string.preference_category_advanced)) {
TextPreference(
title = stringResource(R.string.preference_search_location_custom_overpass_url),
value = customOverpassUrl,
placeholder = LocationSearchSettings.DefaultOverpassUrl,
summary = customOverpassUrl.takeIf { it.isNotBlank() }
?: LocationSearchSettings.DefaultOverpassUrl,
onValueChanged = {
viewModel.setCustomOverpassUrl(it)
},
enabled = osmLocations == true,
)
TextPreference( TextPreference(
title = stringResource(R.string.preference_search_location_custom_tile_server_url), title = stringResource(R.string.preference_search_location_custom_tile_server_url),
value = customTileServerUrl ?: "", value = customTileServerUrl ?: "",
placeholder = LocationSearchSettings.DefaultTileServerUrl, placeholder = LocationSearchSettings.DefaultTileServerUrl,
summary = customTileServerUrl.takeIf { !it.isNullOrBlank() } summary = customTileServerUrl?.takeIf { it.isNotBlank() }
?: LocationSearchSettings.DefaultTileServerUrl, ?: LocationSearchSettings.DefaultTileServerUrl,
onValueChanged = { onValueChanged = {
viewModel.setCustomTileServerUrl(it) viewModel.setCustomTileServerUrl(it)

View File

@ -42,21 +42,6 @@ class LocationsSettingsScreenVM : ViewModel(), KoinComponent {
settings.setSearchRadius(radius) settings.setSearchRadius(radius)
} }
val customOverpassUrl = settings.overpassUrl
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
fun setCustomOverpassUrl(customUrl: String) {
var url = customUrl
if (url.endsWith('/')) {
url = url.substringBeforeLast('/')
}
if (url.endsWith("/api/interpreter")) {
url = url.substringBeforeLast("/api/interpreter")
}
settings.setOverpassUrl(url)
}
val showMap = settings.showMap val showMap = settings.showMap
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
@ -68,14 +53,7 @@ class LocationsSettingsScreenVM : ViewModel(), KoinComponent {
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setCustomTileServerUrl(customTileServerUrl: String) { fun setCustomTileServerUrl(customTileServerUrl: String) {
settings.setTileServer(customTileServerUrl) settings.setTileServer(customTileServerUrl.takeIf { it.isNotBlank() })
}
val hideUncategorized = settings.hideUncategorized
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setHideUncategorized(hideUncategorized: Boolean) {
settings.setHideUncategorized(hideUncategorized)
} }
val themeMap = settings.themeMap val themeMap = settings.themeMap

View File

@ -6,14 +6,12 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.Login import androidx.compose.material.icons.automirrored.rounded.Login
import androidx.compose.material.icons.automirrored.rounded.Logout import androidx.compose.material.icons.automirrored.rounded.Logout
import androidx.compose.material.icons.rounded.Logout
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider

View File

@ -0,0 +1,61 @@
package de.mm20.launcher2.ui.settings.osm
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.search.LocationSearchSettings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.component.preferences.TextPreference
@Composable
fun OsmSettingsScreen() {
val viewModel: OsmSettingsScreenVM = viewModel()
val osmLocations by viewModel.osmLocations.collectAsState()
val hideUncategorized by viewModel.hideUncategorized.collectAsState()
val customOverpassUrl by viewModel.customOverpassUrl.collectAsState()
PreferenceScreen(title = stringResource(R.string.preference_search_osm_locations)) {
item {
PreferenceCategory {
SwitchPreference(
title = stringResource(R.string.preference_search_osm_locations),
summary = stringResource(R.string.preference_search_osm_locations_summary),
value = osmLocations == true,
onValueChanged = {
viewModel.setOsmLocations(it)
},
)
SwitchPreference(
title = stringResource(R.string.preference_search_locations_hide_uncategorized),
summary = stringResource(R.string.preference_search_locations_hide_uncategorized_summary),
value = hideUncategorized == true,
enabled = osmLocations == true,
onValueChanged = {
viewModel.setHideUncategorized(it)
}
)
}
}
item {
PreferenceCategory(stringResource(R.string.preference_category_advanced)) {
TextPreference(
title = stringResource(R.string.preference_search_location_custom_overpass_url),
value = customOverpassUrl ?: "",
placeholder = LocationSearchSettings.DefaultOverpassUrl,
summary = customOverpassUrl?.takeIf { it.isNotBlank() }
?: LocationSearchSettings.DefaultOverpassUrl,
onValueChanged = {
viewModel.setCustomOverpassUrl(it)
},
enabled = osmLocations == true,
)
}
}
}
}

View File

@ -0,0 +1,36 @@
package de.mm20.launcher2.ui.settings.osm
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.plugins.PluginService
import de.mm20.launcher2.preferences.search.LocationSearchSettings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class OsmSettingsScreenVM: ViewModel(), KoinComponent {
private val settings: LocationSearchSettings by inject()
private val pluginService: PluginService by inject()
val osmLocations = settings.osmLocations
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setOsmLocations(osmLocations: Boolean) {
settings.setOsmLocations(osmLocations)
}
val hideUncategorized = settings.hideUncategorized
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setHideUncategorized(hideUncategorized: Boolean) {
settings.setHideUncategorized(hideUncategorized)
}
val customOverpassUrl = settings.overpassUrl
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
fun setCustomOverpassUrl(customUrl: String) {
settings.setOverpassUrl(customUrl)
}
}

View File

@ -141,8 +141,8 @@ data class LauncherSettingsData internal constructor(
val locationSearchImperialUnits: Boolean = false, val locationSearchImperialUnits: Boolean = false,
val locationSearchRadius: Int = 1500, val locationSearchRadius: Int = 1500,
val locationSearchHideUncategorized: Boolean = true, val locationSearchHideUncategorized: Boolean = true,
val locationSearchOverpassUrl: String = LocationSearchSettings.DefaultOverpassUrl, val locationSearchOverpassUrl: String? = null,
val locationSearchTileServer: String = LocationSearchSettings.DefaultTileServerUrl, val locationSearchTileServer: String? = null,
val locationSearchShowMap: Boolean = true, val locationSearchShowMap: Boolean = true,
val locationSearchShowPositionOnMap: Boolean = false, val locationSearchShowPositionOnMap: Boolean = false,
val locationSearchThemeMap: Boolean = true, val locationSearchThemeMap: Boolean = true,

View File

@ -72,18 +72,39 @@ class LocationSearchSettings internal constructor(
val overpassUrl val overpassUrl
get() = launcherDataStore.data.map { it.locationSearchOverpassUrl } get() = launcherDataStore.data.map { it.locationSearchOverpassUrl }
fun setOverpassUrl(overpassUrl: String) { fun setOverpassUrl(overpassUrl: String?) {
var url = overpassUrl
if (url != null) {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "https://$url"
}
if (url.endsWith('/')) {
url = url.substringBeforeLast('/')
}
if (url.endsWith("/api/interpreter")) {
url = url.substringBeforeLast("/api/interpreter")
}
}
launcherDataStore.update { launcherDataStore.update {
it.copy(locationSearchOverpassUrl = overpassUrl) it.copy(locationSearchOverpassUrl = url)
} }
} }
val tileServer val tileServer
get() = launcherDataStore.data.map { it.locationSearchTileServer } get() = launcherDataStore.data.map { it.locationSearchTileServer }
fun setTileServer(tileServer: String) { fun setTileServer(tileServer: String?) {
var url = tileServer
if (url != null) {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "https://$url"
}
if (!url.contains("\${z}") || !url.contains("\${x}") || !url.contains("\${y}")) {
url = "$url/\${z}/\${x}/\${y}.png"
}
}
launcherDataStore.update { launcherDataStore.update {
it.copy(locationSearchTileServer = tileServer) it.copy(locationSearchTileServer = url)
} }
} }
@ -125,8 +146,8 @@ data class LocationSearchSettingsData(
val providers: Set<String> = setOf("openstreetmaps"), val providers: Set<String> = setOf("openstreetmaps"),
val searchRadius: Int = 1500, val searchRadius: Int = 1500,
val hideUncategorized: Boolean = true, val hideUncategorized: Boolean = true,
val overpassUrl: String = LocationSearchSettings.DefaultOverpassUrl, val overpassUrl: String? = null,
val tileServer: String = LocationSearchSettings.DefaultTileServerUrl, val tileServer: String? = null,
val imperialUnits: Boolean = false, val imperialUnits: Boolean = false,
val showMap: Boolean = false, val showMap: Boolean = false,
val showPositionOnMap: Boolean = false, val showPositionOnMap: Boolean = false,

View File

@ -38,8 +38,7 @@ internal class OsmLocationProvider(
try { try {
Retrofit.Builder() Retrofit.Builder()
.client(HttpClient) .client(HttpClient)
.baseUrl(it.takeIf { it.isNotBlank() } .baseUrl(it?.takeIf { it.isNotBlank() } ?: LocationSearchSettings.DefaultOverpassUrl)
?: LocationSearchSettings.DefaultOverpassUrl)
.addConverterFactory(OverpassQueryConverterFactory()) .addConverterFactory(OverpassQueryConverterFactory())
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()