Added cleartext traffic support for custom TLE URLs #227

This commit is contained in:
Arty Bishop committed 2026-07-30 17:15:02 +02:00
1 parent 4585332b1a
commit f585372594
4 files changed
+69 -6

No files matched your search

+1
View File
@@ -19,6 +19,7 @@
android:allowBackup="false" android:allowBackup="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"> android:roundIcon="@mipmap/ic_launcher_round">
<activity <activity
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
@@ -120,6 +120,7 @@ private fun TransceiversDialogPreview() {
useCustomTransceivers = true, useCustomTransceivers = true,
tleUrl = "https://example.com/tle.txt", tleUrl = "https://example.com/tle.txt",
transceiversUrl = "https://example.com/tx.json", transceiversUrl = "https://example.com/tx.json",
requestCustomSourcesPermission = { onGranted, _ -> onGranted() },
onImportTle = {}, onImportTle = {},
onImportTransceivers = {}, onImportTransceivers = {},
onDismiss = {}, onDismiss = {},
@@ -134,6 +135,7 @@ fun DataSourcesDialog(
useCustomTransceivers: Boolean, useCustomTransceivers: Boolean,
tleUrl: String, tleUrl: String,
transceiversUrl: String, transceiversUrl: String,
requestCustomSourcesPermission: (onGranted: () -> Unit, onDenied: () -> Unit) -> Unit,
onImportTle: () -> Unit, onImportTle: () -> Unit,
onImportTransceivers: () -> Unit, onImportTransceivers: () -> Unit,
onDismiss: () -> Unit, onDismiss: () -> Unit,
@@ -182,7 +184,16 @@ fun DataSourcesDialog(
Text(text = stringResource(id = R.string.prefs_data_sources_tle_switch)) Text(text = stringResource(id = R.string.prefs_data_sources_tle_switch))
Switch( Switch(
checked = isEnabledCustomTle.value, checked = isEnabledCustomTle.value,
onCheckedChange = { isEnabledCustomTle.value = it } onCheckedChange = { enabled ->
if (!enabled) {
isEnabledCustomTle.value = false
} else {
requestCustomSourcesPermission(
{ isEnabledCustomTle.value = true },
{ isEnabledCustomTle.value = false }
)
}
}
) )
} }
OutlinedTextField( OutlinedTextField(
@@ -202,7 +213,16 @@ fun DataSourcesDialog(
Text(text = stringResource(id = R.string.prefs_data_sources_transceivers_switch)) Text(text = stringResource(id = R.string.prefs_data_sources_transceivers_switch))
Switch( Switch(
checked = isEnabledCustomTransceivers.value, checked = isEnabledCustomTransceivers.value,
onCheckedChange = { isEnabledCustomTransceivers.value = it } onCheckedChange = { enabled ->
if (!enabled) {
isEnabledCustomTransceivers.value = false
} else {
requestCustomSourcesPermission(
{ isEnabledCustomTransceivers.value = true },
{ isEnabledCustomTransceivers.value = false }
)
}
}
) )
} }
OutlinedTextField( OutlinedTextField(
@@ -89,10 +89,22 @@ fun SettingsDestination() {
@Composable @Composable
private fun SettingsScreen(uiState: SettingsState, onAction: (SettingsAction) -> Unit) { private fun SettingsScreen(uiState: SettingsState, onAction: (SettingsAction) -> Unit) {
val dialogs = rememberDialogVisibility() val dialogs = rememberDialogVisibility()
val pendingCustomSourcesGrant = remember { mutableStateOf<(() -> Unit)?>(null) }
val pendingCustomSourcesDeny = remember { mutableStateOf<(() -> Unit)?>(null) }
val permissions = rememberSettingsPermissions( val permissions = rememberSettingsPermissions(
sendAction = onAction, sendAction = onAction,
onBluetoothGranted = { dialogs.bluetooth = true }, onBluetoothGranted = { dialogs.bluetooth = true },
onNetworkGranted = { dialogs.network = true } onNetworkGranted = { dialogs.network = true },
onCustomSourcesPermissionGranted = {
pendingCustomSourcesGrant.value?.invoke()
pendingCustomSourcesGrant.value = null
pendingCustomSourcesDeny.value = null
},
onCustomSourcesPermissionDenied = {
pendingCustomSourcesDeny.value?.invoke()
pendingCustomSourcesGrant.value = null
pendingCustomSourcesDeny.value = null
}
) )
// Dialogs // Dialogs
@@ -117,6 +129,11 @@ private fun SettingsScreen(uiState: SettingsState, onAction: (SettingsAction) ->
useCustomTransceivers = uiState.dataSourcesSettings.useCustomTransceivers, useCustomTransceivers = uiState.dataSourcesSettings.useCustomTransceivers,
tleUrl = uiState.dataSourcesSettings.tleUrl, tleUrl = uiState.dataSourcesSettings.tleUrl,
transceiversUrl = uiState.dataSourcesSettings.transceiversUrl, transceiversUrl = uiState.dataSourcesSettings.transceiversUrl,
requestCustomSourcesPermission = { onGranted, onDenied ->
pendingCustomSourcesGrant.value = onGranted
pendingCustomSourcesDeny.value = onDenied
permissions.launchCustomSourcesPermission()
},
onImportTle = { permissions.launchTleImport(); dialogs.dataSources = false }, onImportTle = { permissions.launchTleImport(); dialogs.dataSources = false },
onImportTransceivers = { permissions.launchTransceiverImport(); dialogs.dataSources = false }, onImportTransceivers = { permissions.launchTransceiverImport(); dialogs.dataSources = false },
onDismiss = { dialogs.dataSources = false }, onDismiss = { dialogs.dataSources = false },
@@ -129,7 +146,9 @@ private fun SettingsScreen(uiState: SettingsState, onAction: (SettingsAction) ->
transceiversUrl = if (!useCustomTransceivers || transceiversUrl.isNotBlank()) transceiversUrl else current.transceiversUrl transceiversUrl = if (!useCustomTransceivers || transceiversUrl.isNotBlank()) transceiversUrl else current.transceiversUrl
) )
if (newSettings != current) onAction(SettingsAction.UpdateDataSources(newSettings)) if (newSettings != current) onAction(SettingsAction.UpdateDataSources(newSettings))
if (useCustomTle || useCustomTransceivers) onAction(SettingsAction.UpdateFromWeb) if (newSettings.useCustomTLE || newSettings.useCustomTransceivers) {
onAction(SettingsAction.UpdateFromWeb)
}
} }
) )
} }
@@ -653,14 +672,17 @@ private class SettingsPermissions(
val launchTleImport: () -> Unit, val launchTleImport: () -> Unit,
val launchTransceiverImport: () -> Unit, val launchTransceiverImport: () -> Unit,
val launchBluetooth: () -> Unit, val launchBluetooth: () -> Unit,
val launchNetwork: () -> Unit val launchNetwork: () -> Unit,
val launchCustomSourcesPermission: () -> Unit
) )
@Composable @Composable
private fun rememberSettingsPermissions( private fun rememberSettingsPermissions(
sendAction: (SettingsAction) -> Unit, sendAction: (SettingsAction) -> Unit,
onBluetoothGranted: () -> Unit, onBluetoothGranted: () -> Unit,
onNetworkGranted: () -> Unit onNetworkGranted: () -> Unit,
onCustomSourcesPermissionGranted: () -> Unit,
onCustomSourcesPermissionDenied: () -> Unit
): SettingsPermissions { ): SettingsPermissions {
val locationError = stringResource(R.string.prefs_loc_gps_error) val locationError = stringResource(R.string.prefs_loc_gps_error)
val locationRequest = rememberLauncherForActivityResult( val locationRequest = rememberLauncherForActivityResult(
@@ -697,6 +719,15 @@ private fun rememberSettingsPermissions(
else sendAction(SettingsAction.ShowToast(networkError)) else sendAction(SettingsAction.ShowToast(networkError))
} }
val customSourcesRequest = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
onCustomSourcesPermissionGranted()
} else {
onCustomSourcesPermissionDenied()
sendAction(SettingsAction.ShowToast(networkError))
}
}
return remember { return remember {
SettingsPermissions( SettingsPermissions(
launchLocation = { launchLocation = {
@@ -713,6 +744,13 @@ private fun rememberSettingsPermissions(
} else { } else {
onNetworkGranted() onNetworkGranted()
} }
},
launchCustomSourcesPermission = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CINNAMON_BUN) {
customSourcesRequest.launch(Manifest.permission.ACCESS_LOCAL_NETWORK)
} else {
onCustomSourcesPermissionGranted()
}
} }
) )
} }