mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Implemented extended data output (#195)
This commit is contained in:
1 parent
7adbf951bc
commit
85ffe94266
19 files changed
+965
-322
No files matched your search
@@ -25,6 +25,7 @@ import androidx.compose.animation.core.rememberInfiniteTransition
|
|||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
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
|
||||||
@@ -33,8 +34,10 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
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.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material3.ElevatedCard
|
import androidx.compose.material3.ElevatedCard
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -55,6 +58,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
@@ -194,7 +198,15 @@ private fun RadarScreen(uiState: RadarState, navigateUp: () -> Unit) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
TransmittersList(transmitters = uiState.transmitters)
|
TransmittersList(
|
||||||
|
transmitters = uiState.transmitters,
|
||||||
|
selectedUuid = uiState.selectedTransmitterUuid,
|
||||||
|
onSelect = { uuid ->
|
||||||
|
if (uiState.selectedTransmitterUuid != null) {
|
||||||
|
uiState.sendAction(RadarAction.SelectTransmitter(uuid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
if (uiState.orbitalPos?.eclipsed == true) {
|
if (uiState.orbitalPos?.eclipsed == true) {
|
||||||
EclipsedIndicator()
|
EclipsedIndicator()
|
||||||
}
|
}
|
||||||
@@ -282,7 +294,15 @@ private fun RadarScreen(uiState: RadarState, navigateUp: () -> Unit) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
TransmittersList(transmitters = uiState.transmitters)
|
TransmittersList(
|
||||||
|
transmitters = uiState.transmitters,
|
||||||
|
selectedUuid = uiState.selectedTransmitterUuid,
|
||||||
|
onSelect = { uuid ->
|
||||||
|
if (uiState.selectedTransmitterUuid != null) {
|
||||||
|
uiState.sendAction(RadarAction.SelectTransmitter(uuid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
if (uiState.orbitalPos?.eclipsed == true) {
|
if (uiState.orbitalPos?.eclipsed == true) {
|
||||||
EclipsedIndicator()
|
EclipsedIndicator()
|
||||||
}
|
}
|
||||||
@@ -315,10 +335,19 @@ private fun RadarTextBottom(value: Double, text: String, isLeft: Boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TransmittersList(transmitters: List<SatRadio>) {
|
private fun TransmittersList(
|
||||||
|
transmitters: List<SatRadio>,
|
||||||
|
selectedUuid: String?,
|
||||||
|
onSelect: (String) -> Unit
|
||||||
|
) {
|
||||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||||
items(items = transmitters, key = { item -> item.uuid }) { radio ->
|
items(items = transmitters, key = { item -> item.uuid }) { radio ->
|
||||||
TransmitterItem(radio)
|
TransmitterItem(
|
||||||
|
radio,
|
||||||
|
(selectedUuid != null),
|
||||||
|
(radio.uuid == selectedUuid),
|
||||||
|
{ onSelect(radio.uuid) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,7 +359,7 @@ private fun TransmitterItemPreview() {
|
|||||||
"", "Extremely powerful transmitter", true, 10000000000L, 10000000000L,
|
"", "Extremely powerful transmitter", true, 10000000000L, 10000000000L,
|
||||||
null, 10000000000L, 10000000000L, "FSK AX.100 Mode 5", true, 0
|
null, 10000000000L, 10000000000L, "FSK AX.100 Mode 5", true, 0
|
||||||
)
|
)
|
||||||
MainTheme { TransmitterItem(transmitter) }
|
MainTheme { TransmitterItem(transmitter, true, true,{}) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -370,13 +399,24 @@ private fun EclipsedIndicator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TransmitterItem(radio: SatRadio) {
|
private fun TransmitterItem(
|
||||||
|
radio: SatRadio,
|
||||||
|
isClickable: Boolean,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
// LaunchedEffect(radio) {
|
// LaunchedEffect(radio) {
|
||||||
// BluetoothCIV.updateOnce(radio)
|
// BluetoothCIV.updateOnce(radio)
|
||||||
// }
|
// }
|
||||||
val title = if (radio.isInverted) "INVERTED: ${radio.info}" else radio.info
|
val title = if (radio.isInverted) "INVERTED: ${radio.info}" else radio.info
|
||||||
val fullTitle = "$title - (${radio.downlinkMode ?: "--"}/${radio.uplinkMode ?: "--"})"
|
val fullTitle = "$title - (${radio.downlinkMode ?: "--"}/${radio.uplinkMode ?: "--"})"
|
||||||
Surface(color = MaterialTheme.colorScheme.background,
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(
|
||||||
|
if (isClickable) Modifier.clickable { onClick() } else Modifier
|
||||||
|
)
|
||||||
// modifier = Modifier.clickable(onClick = {
|
// modifier = Modifier.clickable(onClick = {
|
||||||
// Log.d("BluetoothCivManager", radio.toString())
|
// Log.d("BluetoothCivManager", radio.toString())
|
||||||
// if(radio.uuid == BluetoothCIV.selected) BluetoothCIV.selected = "NONE" else
|
// if(radio.uuid == BluetoothCIV.selected) BluetoothCIV.selected = "NONE" else
|
||||||
@@ -387,21 +427,51 @@ private fun TransmitterItem(radio: SatRadio) {
|
|||||||
// })
|
// })
|
||||||
) {
|
) {
|
||||||
Surface(modifier = Modifier.padding(bottom = 2.dp)) {
|
Surface(modifier = Modifier.padding(bottom = 2.dp)) {
|
||||||
Column(
|
Box {
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
Column(
|
||||||
modifier = Modifier
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
.background(MaterialTheme.colorScheme.surface)
|
|
||||||
.padding(horizontal = 8.dp, vertical = 6.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = fullTitle,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.background(MaterialTheme.colorScheme.surface)
|
||||||
.infiniteMarquee()
|
.padding(horizontal = 8.dp, vertical = 6.dp)
|
||||||
)
|
) {
|
||||||
FrequencyRow(radio = radio, isDownlink = true)
|
Text(
|
||||||
FrequencyRow(radio = radio, isDownlink = false)
|
text = fullTitle,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.infiniteMarquee()
|
||||||
|
)
|
||||||
|
FrequencyRow(radio = radio, isDownlink = true)
|
||||||
|
FrequencyRow(radio = radio, isDownlink = false)
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.padding(start = 4.dp, top = 5.dp)
|
||||||
|
.background(
|
||||||
|
brush = Brush.radialGradient(
|
||||||
|
colors = listOf(
|
||||||
|
MaterialTheme.colorScheme.surface,
|
||||||
|
MaterialTheme.colorScheme.surface.copy(alpha = 0f)
|
||||||
|
),
|
||||||
|
radius = 80f
|
||||||
|
),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.width(30.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_radios),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.padding(start = 4.dp)
|
||||||
|
.size(24.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,12 @@ data class RadarState(
|
|||||||
val shouldShowSweep: Boolean,
|
val shouldShowSweep: Boolean,
|
||||||
val shouldUseCompass: Boolean,
|
val shouldUseCompass: Boolean,
|
||||||
val transmitters: List<SatRadio>,
|
val transmitters: List<SatRadio>,
|
||||||
|
val selectedTransmitterUuid: String?,
|
||||||
|
val selectedFrequency: Long?,
|
||||||
val sendAction: (RadarAction) -> Unit
|
val sendAction: (RadarAction) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed class RadarAction {
|
sealed class RadarAction {
|
||||||
data class AddToCalendar(val name: String, val aosTime: Long, val losTime: Long) : RadarAction()
|
data class AddToCalendar(val name: String, val aosTime: Long, val losTime: Long) : RadarAction()
|
||||||
|
data class SelectTransmitter(val uuid: String) : RadarAction()
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,10 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import com.rtbishop.look4sat.MainApplication
|
import com.rtbishop.look4sat.MainApplication
|
||||||
|
import com.rtbishop.look4sat.data.framework.WithoutExtParams
|
||||||
import com.rtbishop.look4sat.data.framework.BluetoothReporter
|
import com.rtbishop.look4sat.data.framework.BluetoothReporter
|
||||||
|
import com.rtbishop.look4sat.data.framework.BtService
|
||||||
|
import com.rtbishop.look4sat.data.framework.ExtendedParams
|
||||||
import com.rtbishop.look4sat.data.framework.NetworkReporter
|
import com.rtbishop.look4sat.data.framework.NetworkReporter
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.domain.model.SatRadio
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalObject
|
import com.rtbishop.look4sat.domain.predict.OrbitalObject
|
||||||
@@ -65,6 +68,8 @@ class RadarViewModel(
|
|||||||
satTrack = emptyList(),
|
satTrack = emptyList(),
|
||||||
shouldShowSweep = settingsRepo.otherSettings.value.stateOfSweep,
|
shouldShowSweep = settingsRepo.otherSettings.value.stateOfSweep,
|
||||||
shouldUseCompass = settingsRepo.otherSettings.value.stateOfSensors,
|
shouldUseCompass = settingsRepo.otherSettings.value.stateOfSensors,
|
||||||
|
selectedTransmitterUuid = null,
|
||||||
|
selectedFrequency = null,
|
||||||
transmitters = emptyList(),
|
transmitters = emptyList(),
|
||||||
sendAction = ::handleAction,
|
sendAction = ::handleAction,
|
||||||
)
|
)
|
||||||
@@ -109,9 +114,9 @@ class RadarViewModel(
|
|||||||
_uiState.update { it.copy(currentTime = time, isCurrentTimeAos = false) }
|
_uiState.update { it.copy(currentTime = time, isCurrentTimeAos = false) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
processRadios(transmitters, satPass.orbitalObject, timeNow)
|
||||||
sendPassData(satPass, pos, satPass.orbitalObject)
|
sendPassData(satPass, pos, satPass.orbitalObject)
|
||||||
sendPassDataBT(pos)
|
sendPassDataBT(pos)
|
||||||
processRadios(transmitters, satPass.orbitalObject, timeNow)
|
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,6 +131,7 @@ class RadarViewModel(
|
|||||||
private fun handleAction(action: RadarAction) {
|
private fun handleAction(action: RadarAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is RadarAction.AddToCalendar -> addToCalendar(action.name, action.aosTime, action.losTime)
|
is RadarAction.AddToCalendar -> addToCalendar(action.name, action.aosTime, action.losTime)
|
||||||
|
is RadarAction.SelectTransmitter -> { _uiState.update { it.copy(selectedTransmitterUuid = action.uuid) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,25 +147,47 @@ class RadarViewModel(
|
|||||||
if (settingsRepo.rcSettings.value.rotatorState) {
|
if (settingsRepo.rcSettings.value.rotatorState) {
|
||||||
val server = settingsRepo.rcSettings.value.rotatorAddress
|
val server = settingsRepo.rcSettings.value.rotatorAddress
|
||||||
val port = settingsRepo.rcSettings.value.rotatorPort.toInt()
|
val port = settingsRepo.rcSettings.value.rotatorPort.toInt()
|
||||||
|
val format = settingsRepo.rcSettings.value.rotatorFormat
|
||||||
val azimuth = orbitalPos.azimuth.toDegrees().round(2)
|
val azimuth = orbitalPos.azimuth.toDegrees().round(2)
|
||||||
val elevation = orbitalPos.elevation.toDegrees().round(2)
|
val elevation = orbitalPos.elevation.toDegrees().round(2)
|
||||||
networkReporter.reportRotation(server, port, azimuth, elevation)
|
networkReporter.reportRotation(format, azimuth, elevation, ExtendedParams(server, port))
|
||||||
|
}
|
||||||
|
if (settingsRepo.rcSettings.value.frequencyState) {
|
||||||
|
_uiState.value.selectedFrequency?.let { freq ->
|
||||||
|
val server = settingsRepo.rcSettings.value.frequencyAddress
|
||||||
|
val port = settingsRepo.rcSettings.value.frequencyPort.toInt()
|
||||||
|
val format = settingsRepo.rcSettings.value.frequencyFormat
|
||||||
|
networkReporter.reportFrequency(format,freq, ExtendedParams(server, port))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendPassDataBT(orbitalPos: OrbitalPos) {
|
private fun sendPassDataBT(orbitalPos: OrbitalPos) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (settingsRepo.rcSettings.value.bluetoothState) {
|
if (settingsRepo.rcSettings.value.bluetoothRotatorState) {
|
||||||
val btDevice = settingsRepo.rcSettings.value.bluetoothAddress
|
val btRotatorDevice = settingsRepo.rcSettings.value.bluetoothRotatorAddress
|
||||||
if (bluetoothReporter.isConnected()) {
|
if (bluetoothReporter.isConnected(BtService.ROTATOR)) {
|
||||||
val format = settingsRepo.rcSettings.value.bluetoothFormat
|
val format = settingsRepo.rcSettings.value.bluetoothRotatorFormat
|
||||||
val azimuth = orbitalPos.azimuth.toDegrees().round(0).toInt()
|
val azimuth = orbitalPos.azimuth.toDegrees().round(0)
|
||||||
val elevation = orbitalPos.elevation.toDegrees().round(0).toInt()
|
val elevation = orbitalPos.elevation.toDegrees().round(0)
|
||||||
bluetoothReporter.reportRotation(format, azimuth, elevation)
|
bluetoothReporter.reportRotation(format, azimuth, elevation, WithoutExtParams(0))
|
||||||
} else if (!bluetoothReporter.isConnecting()) {
|
} else if (!bluetoothReporter.isConnecting(BtService.ROTATOR)) {
|
||||||
// Log.i("BTReporter", "BTReporter: Attempting to connect...")
|
// Log.i("BTReporter", "BTReporter (rotator): Attempting to connect...")
|
||||||
bluetoothReporter.connectBTDevice(btDevice)
|
bluetoothReporter.connect(BtService.ROTATOR,btRotatorDevice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settingsRepo.rcSettings.value.bluetoothFrequencyState) {
|
||||||
|
val btFrequencyDevice = settingsRepo.rcSettings.value.bluetoothFrequencyAddress
|
||||||
|
if (bluetoothReporter.isConnected(BtService.FREQUENCY)) {
|
||||||
|
val format = settingsRepo.rcSettings.value.bluetoothFrequencyFormat
|
||||||
|
val frequency = _uiState.value.selectedFrequency
|
||||||
|
frequency?.let { freq ->
|
||||||
|
bluetoothReporter.reportFrequency(format, freq, WithoutExtParams(0))
|
||||||
|
}
|
||||||
|
} else if (!bluetoothReporter.isConnecting(BtService.FREQUENCY)) {
|
||||||
|
// Log.i("BTReporter", "BTReporter (frequency): Attempting to connect...")
|
||||||
|
bluetoothReporter.connect(BtService.FREQUENCY, btFrequencyDevice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +195,33 @@ class RadarViewModel(
|
|||||||
|
|
||||||
private suspend fun processRadios(radios: List<SatRadio>, orbitalObject: OrbitalObject, time: Long) {
|
private suspend fun processRadios(radios: List<SatRadio>, orbitalObject: OrbitalObject, time: Long) {
|
||||||
val transmitters = satelliteRepo.getRadios(orbitalObject, stationPos, radios, time)
|
val transmitters = satelliteRepo.getRadios(orbitalObject, stationPos, radios, time)
|
||||||
_uiState.update { it.copy(transmitters = transmitters) }
|
_uiState.update { state ->
|
||||||
|
if (!settingsRepo.rcSettings.value.frequencyState && !settingsRepo.rcSettings.value.bluetoothFrequencyState) {
|
||||||
|
return@update state.copy(
|
||||||
|
transmitters = transmitters,
|
||||||
|
selectedTransmitterUuid = null,
|
||||||
|
selectedFrequency = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val selectedUuid = state.selectedTransmitterUuid ?: transmitters.firstOrNull()?.uuid
|
||||||
|
val selectedRadio = transmitters.firstOrNull { it.uuid == selectedUuid }
|
||||||
|
val freq = selectedRadio?.let { radio ->
|
||||||
|
val low = radio.downlinkLow
|
||||||
|
val high = radio.downlinkHigh
|
||||||
|
when {
|
||||||
|
low != null && high != null ->
|
||||||
|
(low + high) / 2
|
||||||
|
low != null ->
|
||||||
|
low
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.copy(
|
||||||
|
transmitters = transmitters,
|
||||||
|
selectedTransmitterUuid = selectedUuid,
|
||||||
|
selectedFrequency = freq
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.rtbishop.look4sat.presentation.LocalSpacing
|
import com.rtbishop.look4sat.presentation.LocalSpacing
|
||||||
|
import com.rtbishop.look4sat.domain.model.RCSettings
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -199,3 +200,283 @@ fun DataSourcesDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun PreviewNetworkOutputDialog() {
|
||||||
|
MainTheme {
|
||||||
|
NetworkOutputDialog(
|
||||||
|
initialSettings = RCSettings(
|
||||||
|
rotatorState = false,
|
||||||
|
rotatorAddress = "127.0.0.1",
|
||||||
|
rotatorPort = "4533",
|
||||||
|
rotatorFormat = $$"P $AZ $EL",
|
||||||
|
frequencyState = false,
|
||||||
|
frequencyAddress = "127.0.0.1",
|
||||||
|
frequencyPort = "4532",
|
||||||
|
frequencyFormat = $$"set_freq $FREQ",
|
||||||
|
bluetoothRotatorState = false,
|
||||||
|
bluetoothRotatorFormat = $$"W$AZ $EL",
|
||||||
|
bluetoothRotatorName = "Default",
|
||||||
|
bluetoothRotatorAddress = "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyState = false,
|
||||||
|
bluetoothFrequencyAddress = "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyFormat = $$"FA$FREQ"
|
||||||
|
),
|
||||||
|
onDismiss = {},
|
||||||
|
onSave = { _, _, _, _, _, _, _, _ -> }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NetworkOutputDialog(
|
||||||
|
initialSettings: RCSettings,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSave: (
|
||||||
|
Boolean, String, String, String,
|
||||||
|
Boolean, String, String, String
|
||||||
|
) -> Unit
|
||||||
|
) {
|
||||||
|
val rotatorState = rememberSaveable { mutableStateOf(initialSettings.rotatorState) }
|
||||||
|
val rotatorAddress = rememberSaveable { mutableStateOf(initialSettings.rotatorAddress) }
|
||||||
|
val rotatorPort = rememberSaveable { mutableStateOf(initialSettings.rotatorPort) }
|
||||||
|
val rotatorFormat = rememberSaveable { mutableStateOf(initialSettings.rotatorFormat) }
|
||||||
|
val frequencyState = rememberSaveable { mutableStateOf(initialSettings.frequencyState) }
|
||||||
|
val frequencyAddress = rememberSaveable { mutableStateOf(initialSettings.frequencyAddress) }
|
||||||
|
val frequencyPort = rememberSaveable { mutableStateOf(initialSettings.frequencyPort) }
|
||||||
|
val frequencyFormat = rememberSaveable { mutableStateOf(initialSettings.frequencyFormat) }
|
||||||
|
val onAccept = {
|
||||||
|
onSave(
|
||||||
|
rotatorState.value,
|
||||||
|
rotatorAddress.value,
|
||||||
|
rotatorPort.value,
|
||||||
|
rotatorFormat.value,
|
||||||
|
frequencyState.value,
|
||||||
|
frequencyAddress.value,
|
||||||
|
frequencyPort.value,
|
||||||
|
frequencyFormat.value
|
||||||
|
)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
SharedDialog(
|
||||||
|
title = stringResource(R.string.prefs_net_title),
|
||||||
|
onCancel = onDismiss,
|
||||||
|
onAccept = onAccept
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(8.dp)) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.prefs_net_rotator_switch))
|
||||||
|
Switch(
|
||||||
|
checked = rotatorState.value,
|
||||||
|
onCheckedChange = { rotatorState.value = it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = rotatorAddress.value,
|
||||||
|
onValueChange = { rotatorAddress.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_rotator_ip_hint)) },
|
||||||
|
modifier = Modifier.weight(1.5f),
|
||||||
|
enabled = rotatorState.value
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = rotatorPort.value,
|
||||||
|
onValueChange = { rotatorPort.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_rotator_port_hint)) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
enabled = rotatorState.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = rotatorFormat.value,
|
||||||
|
onValueChange = { rotatorFormat.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_rotator_format_hint)) },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = rotatorState.value
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.prefs_net_frequency_switch))
|
||||||
|
Switch(
|
||||||
|
checked = frequencyState.value,
|
||||||
|
onCheckedChange = { frequencyState.value = it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = frequencyAddress.value,
|
||||||
|
onValueChange = { frequencyAddress.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_frequency_ip_hint)) },
|
||||||
|
modifier = Modifier.weight(1.5f),
|
||||||
|
enabled = frequencyState.value
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = frequencyPort.value,
|
||||||
|
onValueChange = { frequencyPort.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_frequency_port_hint)) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
enabled = frequencyState.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = frequencyFormat.value,
|
||||||
|
onValueChange = { frequencyFormat.value = it },
|
||||||
|
maxLines = 2,
|
||||||
|
label = { Text(stringResource(R.string.prefs_net_frequency_format_hint)) },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = frequencyState.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun PreviewBluetoothOutputDialog() {
|
||||||
|
MainTheme {
|
||||||
|
BluetoothOutputDialog(
|
||||||
|
initialSettings = RCSettings(
|
||||||
|
rotatorState = false,
|
||||||
|
rotatorAddress = "127.0.0.1",
|
||||||
|
rotatorPort = "4533",
|
||||||
|
rotatorFormat = $$"P $AZ $EL",
|
||||||
|
frequencyState = false,
|
||||||
|
frequencyAddress = "127.0.0.1",
|
||||||
|
frequencyPort = "4532",
|
||||||
|
frequencyFormat = $$"set_freq $FREQ",
|
||||||
|
bluetoothRotatorState = false,
|
||||||
|
bluetoothRotatorFormat = $$"W$AZ $EL",
|
||||||
|
bluetoothRotatorName = "Default",
|
||||||
|
bluetoothRotatorAddress = "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyState = false,
|
||||||
|
bluetoothFrequencyAddress = "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyFormat = $$"FA$FREQ"
|
||||||
|
),
|
||||||
|
onDismiss = {},
|
||||||
|
onSave = { _, _, _, _, _, _ -> }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BluetoothOutputDialog(
|
||||||
|
initialSettings: RCSettings,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSave: (
|
||||||
|
Boolean, String, String,
|
||||||
|
Boolean, String, String
|
||||||
|
) -> Unit
|
||||||
|
) {
|
||||||
|
val rotatorState = rememberSaveable { mutableStateOf(initialSettings.bluetoothRotatorState) }
|
||||||
|
val rotatorAddress = rememberSaveable { mutableStateOf(initialSettings.bluetoothRotatorAddress) }
|
||||||
|
val rotatorFormat = rememberSaveable { mutableStateOf(initialSettings.bluetoothRotatorFormat) }
|
||||||
|
val frequencyState = rememberSaveable { mutableStateOf(initialSettings.bluetoothFrequencyState) }
|
||||||
|
val frequencyAddress = rememberSaveable { mutableStateOf(initialSettings.bluetoothFrequencyAddress) }
|
||||||
|
val frequencyFormat = rememberSaveable { mutableStateOf(initialSettings.bluetoothFrequencyFormat) }
|
||||||
|
val onAccept = {
|
||||||
|
onSave(
|
||||||
|
rotatorState.value,
|
||||||
|
rotatorAddress.value,
|
||||||
|
rotatorFormat.value,
|
||||||
|
frequencyState.value,
|
||||||
|
frequencyAddress.value,
|
||||||
|
frequencyFormat.value
|
||||||
|
)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
SharedDialog(
|
||||||
|
title = stringResource(R.string.prefs_bt_title),
|
||||||
|
onCancel = onDismiss,
|
||||||
|
onAccept = onAccept
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(8.dp)) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.prefs_bt_rotator_switch))
|
||||||
|
Switch(
|
||||||
|
checked = rotatorState.value,
|
||||||
|
onCheckedChange = { rotatorState.value = it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = rotatorAddress.value,
|
||||||
|
onValueChange = { rotatorAddress.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_bt_rotator_device_hint)) },
|
||||||
|
modifier = Modifier.weight(1.5f),
|
||||||
|
enabled = rotatorState.value
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = rotatorFormat.value,
|
||||||
|
onValueChange = { rotatorFormat.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_bt_rotator_output_hint)) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
enabled = rotatorState.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.prefs_bt_frequency_switch))
|
||||||
|
Switch(
|
||||||
|
checked = frequencyState.value,
|
||||||
|
onCheckedChange = { frequencyState.value = it }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = frequencyAddress.value,
|
||||||
|
onValueChange = { frequencyAddress.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_bt_frequency_device_hint)) },
|
||||||
|
modifier = Modifier.weight(1.5f),
|
||||||
|
enabled = frequencyState.value
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = frequencyFormat.value,
|
||||||
|
onValueChange = { frequencyFormat.value = it },
|
||||||
|
singleLine = true,
|
||||||
|
label = { Text(stringResource(R.string.prefs_bt_frequency_output_hint)) },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
enabled = frequencyState.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,7 +37,6 @@ import androidx.compose.material3.ElevatedCard
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -60,7 +59,6 @@ import androidx.navigation.NavGraphBuilder
|
|||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.model.OtherSettings
|
import com.rtbishop.look4sat.domain.model.OtherSettings
|
||||||
import com.rtbishop.look4sat.domain.model.RCSettings
|
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.domain.predict.GeoPos
|
||||||
import com.rtbishop.look4sat.presentation.MainTheme
|
import com.rtbishop.look4sat.presentation.MainTheme
|
||||||
import com.rtbishop.look4sat.presentation.Screen
|
import com.rtbishop.look4sat.presentation.Screen
|
||||||
@@ -87,19 +85,6 @@ fun NavGraphBuilder.settingsDestination() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SettingsScreen(uiState: SettingsState) {
|
private fun SettingsScreen(uiState: SettingsState) {
|
||||||
// Permissions setup
|
|
||||||
val bluetoothContract = ActivityResultContracts.RequestPermission()
|
|
||||||
val bluetoothError = stringResource(R.string.prefs_bt_perm_error)
|
|
||||||
val bluetoothPerm = when {
|
|
||||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> Manifest.permission.BLUETOOTH
|
|
||||||
else -> Manifest.permission.BLUETOOTH_CONNECT
|
|
||||||
}
|
|
||||||
val bluetoothRequest = rememberLauncherForActivityResult(bluetoothContract) { isGranted ->
|
|
||||||
if (!isGranted) {
|
|
||||||
uiState.sendRCAction(RCAction.SetBluetoothState(false))
|
|
||||||
uiState.sendSystemAction(SystemAction.ShowToast(bluetoothError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val locationContract = ActivityResultContracts.RequestMultiplePermissions()
|
val locationContract = ActivityResultContracts.RequestMultiplePermissions()
|
||||||
val locationError = stringResource(R.string.prefs_loc_gps_error)
|
val locationError = stringResource(R.string.prefs_loc_gps_error)
|
||||||
val locationPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
|
val locationPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
@@ -180,12 +165,84 @@ private fun SettingsScreen(uiState: SettingsState) {
|
|||||||
val setRotatorState = { value: Boolean -> uiState.sendRCAction(RCAction.SetRotatorState(value)) }
|
val setRotatorState = { value: Boolean -> uiState.sendRCAction(RCAction.SetRotatorState(value)) }
|
||||||
val setRotatorAddress = { value: String -> uiState.sendRCAction(RCAction.SetRotatorAddress(value)) }
|
val setRotatorAddress = { value: String -> uiState.sendRCAction(RCAction.SetRotatorAddress(value)) }
|
||||||
val setRotatorPort = { value: String -> uiState.sendRCAction(RCAction.SetRotatorPort(value)) }
|
val setRotatorPort = { value: String -> uiState.sendRCAction(RCAction.SetRotatorPort(value)) }
|
||||||
val setBluetoothState = { value: Boolean ->
|
val setRotatorFormat = { value: String -> uiState.sendRCAction(RCAction.SetRotatorFormat(value)) }
|
||||||
bluetoothRequest.launch(bluetoothPerm)
|
val setFrequencyState = { value: Boolean -> uiState.sendRCAction(RCAction.SetFrequencyState(value)) }
|
||||||
uiState.sendRCAction(RCAction.SetBluetoothState(value))
|
val setFrequencyAddress = { value: String -> uiState.sendRCAction(RCAction.SetFrequencyAddress(value)) }
|
||||||
|
val setFrequencyPort = { value: String -> uiState.sendRCAction(RCAction.SetFrequencyPort(value)) }
|
||||||
|
val setFrequencyFormat = { value: String -> uiState.sendRCAction(RCAction.SetFrequencyFormat(value)) }
|
||||||
|
val setBluetoothRotatorState = { value: Boolean -> uiState.sendRCAction(RCAction.SetBluetoothRotatorState(value)) }
|
||||||
|
val setBluetoothRotatorAddress = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothRotatorAddress(value)) }
|
||||||
|
val setBluetoothRotatorFormat = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothRotatorFormat(value)) }
|
||||||
|
val setBluetoothFrequencyState = { value: Boolean -> uiState.sendRCAction(RCAction.SetBluetoothFrequencyState(value)) }
|
||||||
|
val setBluetoothFrequencyAddress = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothFrequencyAddress(value)) }
|
||||||
|
val setBluetoothFrequencyFormat = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothFrequencyFormat(value)) }
|
||||||
|
|
||||||
|
// Network data output
|
||||||
|
val networkDialogState = rememberSaveable { mutableStateOf(false) }
|
||||||
|
val showNetworkDialog = { networkDialogState.value = true }
|
||||||
|
val dismissNetworkDialog = { networkDialogState.value = false }
|
||||||
|
if (networkDialogState.value) {
|
||||||
|
NetworkOutputDialog(
|
||||||
|
initialSettings = rcSettings,
|
||||||
|
onDismiss = dismissNetworkDialog,
|
||||||
|
onSave = { rotatorState,
|
||||||
|
rotatorAddress,
|
||||||
|
rotatorPort,
|
||||||
|
rotatorFormat,
|
||||||
|
frequencyState,
|
||||||
|
frequencyAddress,
|
||||||
|
frequencyPort,
|
||||||
|
frequencyFormat ->
|
||||||
|
setRotatorState(rotatorState)
|
||||||
|
setRotatorAddress(rotatorAddress)
|
||||||
|
setRotatorPort(rotatorPort)
|
||||||
|
setRotatorFormat(rotatorFormat)
|
||||||
|
setFrequencyState(frequencyState)
|
||||||
|
setFrequencyAddress(frequencyAddress)
|
||||||
|
setFrequencyPort(frequencyPort)
|
||||||
|
setFrequencyFormat(frequencyFormat)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bluetooth data output
|
||||||
|
val bluetoothDialogState = rememberSaveable { mutableStateOf(false) }
|
||||||
|
val bluetoothContract = ActivityResultContracts.RequestPermission()
|
||||||
|
val bluetoothError = stringResource(R.string.prefs_bt_perm_error)
|
||||||
|
val bluetoothPerm = when {
|
||||||
|
Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> Manifest.permission.BLUETOOTH
|
||||||
|
else -> Manifest.permission.BLUETOOTH_CONNECT
|
||||||
|
}
|
||||||
|
val bluetoothRequest = rememberLauncherForActivityResult(bluetoothContract) { isGranted ->
|
||||||
|
if (!isGranted)
|
||||||
|
{
|
||||||
|
uiState.sendRCAction(RCAction.SetBluetoothRotatorState(false))
|
||||||
|
uiState.sendRCAction(RCAction.SetBluetoothFrequencyState(false))
|
||||||
|
uiState.sendSystemAction(SystemAction.ShowToast(bluetoothError))
|
||||||
|
}
|
||||||
|
else { bluetoothDialogState.value = true }
|
||||||
|
}
|
||||||
|
val showBluetoothDialog = { bluetoothRequest.launch(bluetoothPerm) }
|
||||||
|
val dismissBluetoothDialog = { bluetoothDialogState.value = false }
|
||||||
|
if (bluetoothDialogState.value) {
|
||||||
|
BluetoothOutputDialog(
|
||||||
|
initialSettings = rcSettings,
|
||||||
|
onDismiss = dismissBluetoothDialog,
|
||||||
|
onSave = { rotatorState,
|
||||||
|
rotatorAddress,
|
||||||
|
rotatorFormat,
|
||||||
|
frequencyState,
|
||||||
|
frequencyAddress,
|
||||||
|
frequencyFormat ->
|
||||||
|
setBluetoothRotatorState(rotatorState)
|
||||||
|
setBluetoothRotatorAddress(rotatorAddress)
|
||||||
|
setBluetoothRotatorFormat(rotatorFormat)
|
||||||
|
setBluetoothFrequencyState(frequencyState)
|
||||||
|
setBluetoothFrequencyAddress(frequencyAddress)
|
||||||
|
setBluetoothFrequencyFormat(frequencyFormat)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val setBluetoothAddress = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothAddress(value)) }
|
|
||||||
val setBluetoothFormat = { value: String -> uiState.sendRCAction(RCAction.SetBluetoothFormat(value)) }
|
|
||||||
|
|
||||||
// Other settings
|
// Other settings
|
||||||
val otherSettings = uiState.otherSettings
|
val otherSettings = uiState.otherSettings
|
||||||
@@ -242,8 +299,7 @@ private fun SettingsScreen(uiState: SettingsState) {
|
|||||||
LocationCard(posSettings, setGpsPos, showPosDialog, showLocDialog, dismissPos, uiState.sendSystemAction)
|
LocationCard(posSettings, setGpsPos, showPosDialog, showLocDialog, dismissPos, uiState.sendSystemAction)
|
||||||
}
|
}
|
||||||
item { DataCard(dataSettings, updateFromWeb, clearAllData, showDataSourcesDialog) }
|
item { DataCard(dataSettings, updateFromWeb, clearAllData, showDataSourcesDialog) }
|
||||||
item { NetworkOutputCard(rcSettings, setRotatorState, setRotatorAddress, setRotatorPort) }
|
item { OutputCard({ showNetworkDialog() }, { showBluetoothDialog() }) }
|
||||||
item { BluetoothOutputCard(rcSettings, setBluetoothState, setBluetoothAddress, setBluetoothFormat) }
|
|
||||||
item { OtherCard(otherSettings, toggleUtc, toggleUpdate, toggleSweep, toggleSensor) }
|
item { OtherCard(otherSettings, toggleUtc, toggleUpdate, toggleSweep, toggleSensor) }
|
||||||
item { CardCredits() }
|
item { CardCredits() }
|
||||||
}
|
}
|
||||||
@@ -375,126 +431,32 @@ private fun DataCard(
|
|||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
private fun NetworkOutputCardPreview() = MainTheme {
|
private fun OutputCardPreview() = MainTheme { OutputCard({}, {}) }
|
||||||
val settings = RCSettings(
|
|
||||||
rotatorState = false,
|
|
||||||
rotatorAddress = "127.0.0.1",
|
|
||||||
rotatorPort = "4533",
|
|
||||||
bluetoothState = false,
|
|
||||||
bluetoothFormat = $$"W$AZ $EL",
|
|
||||||
bluetoothName = "Name",
|
|
||||||
bluetoothAddress = "00:0C:BF:13:80:5D"
|
|
||||||
)
|
|
||||||
NetworkOutputCard(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NetworkOutputCard(
|
private fun OutputCard(
|
||||||
settings: RCSettings,
|
onNetworkClick: () -> Unit,
|
||||||
setRotatorState: (Boolean) -> Unit = {},
|
onBluetoothClick: () -> Unit
|
||||||
setRotatorAddress: (String) -> Unit = {},
|
|
||||||
setRotatorPort: (String) -> Unit = {}
|
|
||||||
) {
|
) {
|
||||||
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
|
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.prefs_net_title),
|
text = stringResource(id = R.string.prefs_data_output_title),
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
)
|
)
|
||||||
Row(
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
CardButton(
|
||||||
modifier = Modifier.fillMaxWidth()
|
onClick = onNetworkClick,
|
||||||
) {
|
text = stringResource(id = R.string.prefs_net_output),
|
||||||
Text(text = stringResource(R.string.prefs_net_switch))
|
modifier = Modifier.weight(1f)
|
||||||
Switch(checked = settings.rotatorState, onCheckedChange = { setRotatorState(it) })
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = settings.rotatorAddress,
|
|
||||||
singleLine = true,
|
|
||||||
label = { Text(text = stringResource(R.string.prefs_net_ip_hint)) },
|
|
||||||
onValueChange = { setRotatorAddress(it) },
|
|
||||||
modifier = Modifier.weight(1.5f),
|
|
||||||
enabled = settings.rotatorState
|
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
CardButton(
|
||||||
value = settings.rotatorPort,
|
onClick = onBluetoothClick,
|
||||||
onValueChange = { setRotatorPort(it) },
|
text = stringResource(id = R.string.prefs_bt_output),
|
||||||
label = { Text(text = stringResource(R.string.prefs_net_port_hint)) },
|
modifier = Modifier.weight(1f)
|
||||||
singleLine = true,
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
enabled = settings.rotatorState
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
private fun BluetoothOutputCardPreview() = MainTheme {
|
|
||||||
val settings = RCSettings(
|
|
||||||
rotatorState = false,
|
|
||||||
rotatorAddress = "127.0.0.1",
|
|
||||||
rotatorPort = "4533",
|
|
||||||
bluetoothState = false,
|
|
||||||
bluetoothFormat = $$"W$AZ $EL",
|
|
||||||
bluetoothName = "Name",
|
|
||||||
bluetoothAddress = "00:0C:BF:13:80:5D"
|
|
||||||
)
|
|
||||||
BluetoothOutputCard(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun BluetoothOutputCard(
|
|
||||||
settings: RCSettings,
|
|
||||||
setBluetoothState: (Boolean) -> Unit = {},
|
|
||||||
setBluetoothAddress: (String) -> Unit = {},
|
|
||||||
setBluetoothFormat: (String) -> Unit = {}
|
|
||||||
) {
|
|
||||||
ElevatedCard(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.prefs_bt_title),
|
|
||||||
color = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(R.string.prefs_bt_switch))
|
|
||||||
Switch(checked = settings.bluetoothState, onCheckedChange = { setBluetoothState(it) })
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = settings.bluetoothAddress,
|
|
||||||
singleLine = true,
|
|
||||||
label = { Text(text = stringResource(R.string.prefs_bt_device_hint)) },
|
|
||||||
onValueChange = { setBluetoothAddress(it) },
|
|
||||||
modifier = Modifier.weight(1.5f),
|
|
||||||
enabled = settings.bluetoothState
|
|
||||||
)
|
|
||||||
OutlinedTextField(
|
|
||||||
value = settings.bluetoothFormat,
|
|
||||||
onValueChange = { setBluetoothFormat(it) },
|
|
||||||
label = { Text(text = stringResource(R.string.prefs_bt_output_hint)) },
|
|
||||||
singleLine = true,
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
enabled = settings.bluetoothState
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,10 +71,18 @@ sealed class RCAction {
|
|||||||
data class SetRotatorState(val value: Boolean) : RCAction()
|
data class SetRotatorState(val value: Boolean) : RCAction()
|
||||||
data class SetRotatorAddress(val value: String) : RCAction()
|
data class SetRotatorAddress(val value: String) : RCAction()
|
||||||
data class SetRotatorPort(val value: String) : RCAction()
|
data class SetRotatorPort(val value: String) : RCAction()
|
||||||
data class SetBluetoothState(val value: Boolean) : RCAction()
|
data class SetRotatorFormat(val value: String) : RCAction()
|
||||||
data class SetBluetoothFormat(val value: String) : RCAction()
|
data class SetFrequencyState(val value: Boolean) : RCAction()
|
||||||
data class SetBluetoothName(val value: String) : RCAction()
|
data class SetFrequencyAddress(val value: String) : RCAction()
|
||||||
data class SetBluetoothAddress(val value: String) : RCAction()
|
data class SetFrequencyPort(val value: String) : RCAction()
|
||||||
|
data class SetFrequencyFormat(val value: String) : RCAction()
|
||||||
|
data class SetBluetoothRotatorState(val value: Boolean) : RCAction()
|
||||||
|
data class SetBluetoothRotatorFormat(val value: String) : RCAction()
|
||||||
|
data class SetBluetoothRotatorName(val value: String) : RCAction()
|
||||||
|
data class SetBluetoothRotatorAddress(val value: String) : RCAction()
|
||||||
|
data class SetBluetoothFrequencyState(val value: Boolean) : RCAction()
|
||||||
|
data class SetBluetoothFrequencyFormat(val value: String) : RCAction()
|
||||||
|
data class SetBluetoothFrequencyAddress(val value: String) : RCAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class DataSourcesAction {
|
sealed class DataSourcesAction {
|
||||||
|
|||||||
@@ -152,10 +152,18 @@ class SettingsViewModel(
|
|||||||
is RCAction.SetRotatorState -> settingsRepo.setRotatorState(action.value)
|
is RCAction.SetRotatorState -> settingsRepo.setRotatorState(action.value)
|
||||||
is RCAction.SetRotatorAddress -> settingsRepo.setRotatorAddress(action.value)
|
is RCAction.SetRotatorAddress -> settingsRepo.setRotatorAddress(action.value)
|
||||||
is RCAction.SetRotatorPort -> settingsRepo.setRotatorPort(action.value)
|
is RCAction.SetRotatorPort -> settingsRepo.setRotatorPort(action.value)
|
||||||
is RCAction.SetBluetoothState -> settingsRepo.setBluetoothState(action.value)
|
is RCAction.SetRotatorFormat -> settingsRepo.setRotatorFormat(action.value)
|
||||||
is RCAction.SetBluetoothAddress -> settingsRepo.setBluetoothAddress(action.value)
|
is RCAction.SetFrequencyState -> settingsRepo.setFrequencyState(action.value)
|
||||||
is RCAction.SetBluetoothFormat -> settingsRepo.setBluetoothFormat(action.value)
|
is RCAction.SetFrequencyAddress -> settingsRepo.setFrequencyAddress(action.value)
|
||||||
is RCAction.SetBluetoothName -> settingsRepo.setBluetoothName(action.value)
|
is RCAction.SetFrequencyPort -> settingsRepo.setFrequencyPort(action.value)
|
||||||
|
is RCAction.SetFrequencyFormat -> settingsRepo.setFrequencyFormat(action.value)
|
||||||
|
is RCAction.SetBluetoothRotatorState -> settingsRepo.setBluetoothRotatorState(action.value)
|
||||||
|
is RCAction.SetBluetoothRotatorAddress -> settingsRepo.setBluetoothRotatorAddress(action.value)
|
||||||
|
is RCAction.SetBluetoothRotatorFormat -> settingsRepo.setBluetoothRotatorFormat(action.value)
|
||||||
|
is RCAction.SetBluetoothRotatorName -> settingsRepo.setBluetoothRotatorName(action.value)
|
||||||
|
is RCAction.SetBluetoothFrequencyState -> settingsRepo.setBluetoothFrequencyState(action.value)
|
||||||
|
is RCAction.SetBluetoothFrequencyFormat -> settingsRepo.setBluetoothFrequencyFormat(action.value)
|
||||||
|
is RCAction.SetBluetoothFrequencyAddress -> settingsRepo.setBluetoothFrequencyAddress(action.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,15 +112,27 @@
|
|||||||
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
||||||
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Data output</string>
|
||||||
|
<string name="prefs_net_output">Network</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">Salida de datos de red</string>
|
<string name="prefs_net_title">Salida de datos de red</string>
|
||||||
<string name="prefs_net_switch">Habilitar salida</string>
|
<string name="prefs_net_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_net_ip_hint">Dirección IP</string>
|
<string name="prefs_net_rotator_ip_hint">Dirección IP</string>
|
||||||
<string name="prefs_net_port_hint">Puerto</string>
|
<string name="prefs_net_rotator_port_hint">Puerto</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">Formato de datos</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">Dirección IP</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">Puerto</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">Formato de datos</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">Salida por Bluetooth</string>
|
<string name="prefs_bt_title">Salida por Bluetooth</string>
|
||||||
<string name="prefs_bt_switch">Habilitar salida</string>
|
<string name="prefs_bt_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_bt_device_hint">Id dispositivo</string>
|
<string name="prefs_bt_rotator_device_hint">Id dispositivo</string>
|
||||||
<string name="prefs_bt_output_hint">Formato de datos</string>
|
<string name="prefs_bt_rotator_output_hint">Formato de datos</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">Id dispositivo</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">Formato de datos</string>
|
||||||
<string name="prefs_bt_perm_error">Revisa los permisos de Bluetooth</string>
|
<string name="prefs_bt_perm_error">Revisa los permisos de Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">Otros ajustes</string>
|
<string name="prefs_other_title">Otros ajustes</string>
|
||||||
|
|||||||
@@ -111,15 +111,27 @@
|
|||||||
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
||||||
<string name="prefs_data_sources_transceivers_switch">Custom Transceivers URL</string>
|
<string name="prefs_data_sources_transceivers_switch">Custom Transceivers URL</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Вывод данных</string>
|
||||||
|
<string name="prefs_net_output">Сеть</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">Вывод сетевых данных</string>
|
<string name="prefs_net_title">Вывод сетевых данных</string>
|
||||||
<string name="prefs_net_switch">Включить вывод</string>
|
<string name="prefs_net_rotator_switch">Включить вывод ротатора</string>
|
||||||
<string name="prefs_net_ip_hint">IP адрес</string>
|
<string name="prefs_net_rotator_ip_hint">IP адрес</string>
|
||||||
<string name="prefs_net_port_hint">Порт</string>
|
<string name="prefs_net_rotator_port_hint">Порт</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">Формат</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Включить вывод частоты</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">IP адрес</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">Порт</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">Формат</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">Вывод данных Bluetooth</string>
|
<string name="prefs_bt_title">Вывод данных Bluetooth</string>
|
||||||
<string name="prefs_bt_switch">Включить вывод</string>
|
<string name="prefs_bt_rotator_switch">Включить вывод ротатора</string>
|
||||||
<string name="prefs_bt_device_hint">Id устройства</string>
|
<string name="prefs_bt_rotator_device_hint">Id устройства</string>
|
||||||
<string name="prefs_bt_output_hint">Формат данных</string>
|
<string name="prefs_bt_rotator_output_hint">Формат</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Включить вывод частоты</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">Id устройства</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">Формат</string>
|
||||||
<string name="prefs_bt_perm_error">Нет разрешения использовать bluetooth</string>
|
<string name="prefs_bt_perm_error">Нет разрешения использовать bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">Другие настройки</string>
|
<string name="prefs_other_title">Другие настройки</string>
|
||||||
|
|||||||
@@ -112,15 +112,27 @@
|
|||||||
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
||||||
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Data output</string>
|
||||||
|
<string name="prefs_net_output">Network</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">ජාල ප්රතිදානය</string>
|
<string name="prefs_net_title">ජාල ප්රතිදානය</string>
|
||||||
<string name="prefs_net_switch">ප්රතිදානය සක්රීය කරන්න</string>
|
<string name="prefs_net_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_net_ip_hint">IP ලිපිනය</string>
|
<string name="prefs_net_rotator_ip_hint">IP ලිපිනය</string>
|
||||||
<string name="prefs_net_port_hint">Port</string>
|
<string name="prefs_net_rotator_port_hint">Port</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">දත්ත අකාරය</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">IP ලිපිනය</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">Port</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">දත්ත අකාරය</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">Bluetooth දත්ත ප්රතිදානය</string>
|
<string name="prefs_bt_title">Bluetooth දත්ත ප්රතිදානය</string>
|
||||||
<string name="prefs_bt_switch">ප්රතිදානය සක්රීය කරන්න</string>
|
<string name="prefs_bt_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_bt_device_hint">උපාංග id</string>
|
<string name="prefs_bt_rotator_device_hint">උපාංග id</string>
|
||||||
<string name="prefs_bt_output_hint">දත්ත අකාරය</string>
|
<string name="prefs_bt_rotator_output_hint">දත්ත අකාරය</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">උපාංග id</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">දත්ත අකාරය</string>
|
||||||
<string name="prefs_bt_perm_error">Bluetooth අවසර පරික්ෂා ක°</string>
|
<string name="prefs_bt_perm_error">Bluetooth අවසර පරික්ෂා ක°</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">වෙනත් සැකසුම්</string>
|
<string name="prefs_other_title">වෙනත් සැකසුම්</string>
|
||||||
|
|||||||
@@ -112,15 +112,27 @@
|
|||||||
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
<string name="prefs_data_sources_tle_switch">Custom TLE URL</string>
|
||||||
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Data output</string>
|
||||||
|
<string name="prefs_net_output">Network</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">Вивід мережевих даних</string>
|
<string name="prefs_net_title">Вивід мережевих даних</string>
|
||||||
<string name="prefs_net_switch">Увімкнути вихід</string>
|
<string name="prefs_net_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_net_ip_hint">IP адреса</string>
|
<string name="prefs_net_rotator_ip_hint">IP адреса</string>
|
||||||
<string name="prefs_net_port_hint">Порт</string>
|
<string name="prefs_net_rotator_port_hint">Порт</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">Формат даних</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">IP адреса</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">Порт</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">Формат даних</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">Вивід даних Bluetooth</string>
|
<string name="prefs_bt_title">Вивід даних Bluetooth</string>
|
||||||
<string name="prefs_bt_switch">Увімкнути вихід</string>
|
<string name="prefs_bt_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_bt_device_hint">Id пристрою</string>
|
<string name="prefs_bt_rotator_device_hint">Id пристрою</string>
|
||||||
<string name="prefs_bt_output_hint">Формат даних</string>
|
<string name="prefs_bt_rotator_output_hint">Формат даних</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">Id пристрою</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">Формат даних</string>
|
||||||
<string name="prefs_bt_perm_error">Перевірте дозвіл Bluetooth</string>
|
<string name="prefs_bt_perm_error">Перевірте дозвіл Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">Інші налаштування</string>
|
<string name="prefs_other_title">Інші налаштування</string>
|
||||||
|
|||||||
@@ -104,15 +104,27 @@
|
|||||||
<string name="prefs_data_sources_tle_switch">自定义TLE URL</string>
|
<string name="prefs_data_sources_tle_switch">自定义TLE URL</string>
|
||||||
<string name="prefs_data_sources_transceivers_switch">自定义收发器URL</string>
|
<string name="prefs_data_sources_transceivers_switch">自定义收发器URL</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Data output</string>
|
||||||
|
<string name="prefs_net_output">Network</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">网络数据输出</string>
|
<string name="prefs_net_title">网络数据输出</string>
|
||||||
<string name="prefs_net_switch">启用输出</string>
|
<string name="prefs_net_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_net_ip_hint">IP地址</string>
|
<string name="prefs_net_rotator_ip_hint">IP地址</string>
|
||||||
<string name="prefs_net_port_hint">端口</string>
|
<string name="prefs_net_rotator_port_hint">端口</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">数据格式</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">IP地址</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">端口</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">数据格式</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">蓝牙数据输出</string>
|
<string name="prefs_bt_title">蓝牙数据输出</string>
|
||||||
<string name="prefs_bt_switch">启用输出</string>
|
<string name="prefs_bt_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_bt_device_hint">蓝牙设备 ID</string>
|
<string name="prefs_bt_rotator_device_hint">蓝牙设备 ID</string>
|
||||||
<string name="prefs_bt_output_hint">数据格式</string>
|
<string name="prefs_bt_rotator_output_hint">数据格式</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">蓝牙设备 ID</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">数据格式</string>
|
||||||
<string name="prefs_bt_perm_error">请检查蓝牙权限</string>
|
<string name="prefs_bt_perm_error">请检查蓝牙权限</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">其他设置</string>
|
<string name="prefs_other_title">其他设置</string>
|
||||||
|
|||||||
@@ -136,15 +136,27 @@
|
|||||||
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
<string name="prefs_data_sources_transceivers_switch">Custom transceivers URL</string>
|
||||||
<string name="prefs_data_sources_url_title" translatable="false">URL (HTTPS)</string>
|
<string name="prefs_data_sources_url_title" translatable="false">URL (HTTPS)</string>
|
||||||
|
|
||||||
|
<string name="prefs_data_output_title">Data output</string>
|
||||||
|
<string name="prefs_net_output">Network</string>
|
||||||
|
<string name="prefs_bt_output">Bluetooth</string>
|
||||||
|
|
||||||
<string name="prefs_net_title">Network data output</string>
|
<string name="prefs_net_title">Network data output</string>
|
||||||
<string name="prefs_net_switch">Enable output</string>
|
<string name="prefs_net_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_net_ip_hint">IP address</string>
|
<string name="prefs_net_rotator_ip_hint">IP address</string>
|
||||||
<string name="prefs_net_port_hint">Port</string>
|
<string name="prefs_net_rotator_port_hint">Port</string>
|
||||||
|
<string name="prefs_net_rotator_format_hint">Format</string>
|
||||||
|
<string name="prefs_net_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_net_frequency_ip_hint">IP address</string>
|
||||||
|
<string name="prefs_net_frequency_port_hint">Port</string>
|
||||||
|
<string name="prefs_net_frequency_format_hint">Format</string>
|
||||||
|
|
||||||
<string name="prefs_bt_title">Bluetooth data output</string>
|
<string name="prefs_bt_title">Bluetooth data output</string>
|
||||||
<string name="prefs_bt_switch">Enable output</string>
|
<string name="prefs_bt_rotator_switch">Enable rotation output</string>
|
||||||
<string name="prefs_bt_device_hint">Device id</string>
|
<string name="prefs_bt_rotator_device_hint">Device id</string>
|
||||||
<string name="prefs_bt_output_hint">Data format</string>
|
<string name="prefs_bt_rotator_output_hint">Data format</string>
|
||||||
|
<string name="prefs_bt_frequency_switch">Enable frequency output</string>
|
||||||
|
<string name="prefs_bt_frequency_device_hint">Device id</string>
|
||||||
|
<string name="prefs_bt_frequency_output_hint">Data format</string>
|
||||||
<string name="prefs_bt_perm_error">Check your bluetooth permission</string>
|
<string name="prefs_bt_perm_error">Check your bluetooth permission</string>
|
||||||
|
|
||||||
<string name="prefs_other_title">Other settings</string>
|
<string name="prefs_other_title">Other settings</string>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package com.rtbishop.look4sat.data.framework
|
package com.rtbishop.look4sat.data.framework
|
||||||
|
|
||||||
import android.bluetooth.BluetoothManager
|
import android.bluetooth.BluetoothManager
|
||||||
|
import android.bluetooth.BluetoothSocket
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -25,69 +26,110 @@ import kotlin.math.abs
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import com.rtbishop.look4sat.domain.repository.IReporterParams
|
||||||
|
import com.rtbishop.look4sat.domain.repository.IReporterRepo
|
||||||
|
|
||||||
|
data class WithoutExtParams(
|
||||||
|
val dummy: Int
|
||||||
|
) : IReporterParams
|
||||||
|
|
||||||
|
enum class BtService { ROTATOR, FREQUENCY }
|
||||||
|
|
||||||
|
data class DeviceConnection(
|
||||||
|
var socket: BluetoothSocket? = null,
|
||||||
|
var outputStream: OutputStream? = null,
|
||||||
|
var connected: Boolean = false,
|
||||||
|
var connecting: Boolean = false,
|
||||||
|
var connectionJob: Job? = null
|
||||||
|
)
|
||||||
|
|
||||||
class BluetoothReporter(
|
class BluetoothReporter(
|
||||||
private val bluetoothManager: BluetoothManager,
|
private val bluetoothManager: BluetoothManager,
|
||||||
private val reporterScope: CoroutineScope
|
private val reporterScope: CoroutineScope
|
||||||
) {
|
) : IReporterRepo<WithoutExtParams> {
|
||||||
|
|
||||||
private val tag = "BTReporter"
|
private val tag = "BTReporter"
|
||||||
private val sppid: UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
|
private val sppid: UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
|
||||||
private lateinit var outputStream: OutputStream
|
|
||||||
private var rotationConnectionJob: Job? = null
|
|
||||||
private var rotationReportingJob: Job? = null
|
|
||||||
private var connected = false
|
|
||||||
private var connecting = false
|
|
||||||
|
|
||||||
fun isConnected(): Boolean = connected
|
private val serviceToDevice = mutableMapOf<BtService, String>()
|
||||||
|
private val deviceConnections = mutableMapOf<String, DeviceConnection>()
|
||||||
|
private val writeMutex = Mutex()
|
||||||
|
|
||||||
fun isConnecting(): Boolean = connecting
|
fun isConnected(service: BtService): Boolean {
|
||||||
|
val deviceId = serviceToDevice[service] ?: return false
|
||||||
|
return deviceConnections[deviceId]?.connected == true
|
||||||
|
}
|
||||||
|
fun isConnecting(service: BtService): Boolean {
|
||||||
|
val deviceId = serviceToDevice[service] ?: return false
|
||||||
|
return deviceConnections[deviceId]?.connecting == true
|
||||||
|
}
|
||||||
|
|
||||||
fun connectBTDevice(deviceId: String) {
|
fun connect(service: BtService, deviceId: String) {
|
||||||
if (!connected) {
|
serviceToDevice[service] = deviceId
|
||||||
rotationConnectionJob = reporterScope.launch {
|
val connection = deviceConnections.getOrPut(deviceId) {
|
||||||
try {
|
DeviceConnection()
|
||||||
bluetoothManager.adapter.getRemoteDevice(deviceId)?.let { device ->
|
}
|
||||||
device.createInsecureRfcommSocketToServiceRecord(sppid)?.let { socket ->
|
if (connection.connected || connection.connecting) return
|
||||||
connecting = true
|
connection.connectionJob = reporterScope.launch {
|
||||||
socket.connect()
|
try {
|
||||||
outputStream = socket.outputStream
|
connection.connecting = true
|
||||||
connected = true
|
val device = bluetoothManager.adapter.getRemoteDevice(deviceId)
|
||||||
connecting = false
|
val socket = device.createInsecureRfcommSocketToServiceRecord(sppid)
|
||||||
Log.i(tag, "$tag: Connected!")
|
socket.connect()
|
||||||
}
|
connection.socket = socket
|
||||||
}
|
connection.outputStream = socket.outputStream
|
||||||
} catch (e: SecurityException) {
|
connection.connected = true
|
||||||
Log.e(tag, "$tag: ${e.message}")
|
Log.i(tag, "$tag: Connected to $deviceId")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(tag, "$tag: ${e.message}")
|
Log.e(tag, "$tag: ${e.message}")
|
||||||
}
|
connection.connected = false
|
||||||
|
} finally {
|
||||||
|
connection.connecting = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reportRotation(format: String, azimuth: Int, elevation: Int) {
|
private suspend fun write(service: BtService, buffer: String) {
|
||||||
if (connected) {
|
val deviceId = serviceToDevice[service] ?: return
|
||||||
rotationReportingJob = reporterScope.launch {
|
val connection = deviceConnections[deviceId] ?: return
|
||||||
val newElevation = if (elevation > 0) elevation else 0
|
if (!connection.connected) return
|
||||||
try {
|
try {
|
||||||
val azimuthString = intToStringWithLeadingZeroes(azimuth)
|
writeMutex.withLock {
|
||||||
val elevationString = intToStringWithLeadingZeroes(newElevation)
|
connection.outputStream?.write(buffer.toByteArray())
|
||||||
val crChar = '\r'
|
|
||||||
val nlChar = '\n'
|
|
||||||
val tbChar = '\t'
|
|
||||||
var buffer = format.replace("\$AZ", azimuthString)
|
|
||||||
buffer = buffer.replace("\$EL", elevationString)
|
|
||||||
buffer = buffer.replace("\\r", crChar.toString())
|
|
||||||
buffer = buffer.replace("\\n", nlChar.toString())
|
|
||||||
buffer = buffer.replace("\\t", tbChar.toString())
|
|
||||||
Log.i(tag, "$tag: Sending $buffer")
|
|
||||||
if (connected) outputStream.write(buffer.toByteArray())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(tag, "$tag: ${e.message}")
|
|
||||||
connected = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(tag, "$tag: Write failed ${e.message}")
|
||||||
|
connection.connected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportRotation(format: String, azimuth: Double, elevation: Double, params: WithoutExtParams) {
|
||||||
|
reporterScope.launch {
|
||||||
|
if (!isConnected(BtService.ROTATOR)) return@launch
|
||||||
|
val newElevation = if (elevation > 0.0) elevation else 0.0
|
||||||
|
val azimuthString = intToStringWithLeadingZeroes(azimuth.toInt())
|
||||||
|
val elevationString = intToStringWithLeadingZeroes(newElevation.toInt())
|
||||||
|
var buffer = format
|
||||||
|
.replace("\$AZ", azimuthString)
|
||||||
|
.replace("\$EL", elevationString)
|
||||||
|
.replace("\\r", "\r")
|
||||||
|
.replace("\\n", "\n")
|
||||||
|
.replace("\\t", "\t")
|
||||||
|
write(BtService.ROTATOR, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportFrequency(format: String, frequency: Long, params: WithoutExtParams) {
|
||||||
|
reporterScope.launch {
|
||||||
|
if (!isConnected(BtService.FREQUENCY)) return@launch
|
||||||
|
var buffer = format
|
||||||
|
.replace("\$FREQ", frequency.toString())
|
||||||
|
.replace("\\r", "\r")
|
||||||
|
.replace("\\n", "\n")
|
||||||
|
.replace("\\t", "\t")
|
||||||
|
write(BtService.FREQUENCY, buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,49 +22,94 @@ import java.nio.ByteBuffer
|
|||||||
import java.nio.channels.SocketChannel
|
import java.nio.channels.SocketChannel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import com.rtbishop.look4sat.domain.repository.IReporterParams
|
||||||
|
import com.rtbishop.look4sat.domain.repository.IReporterRepo
|
||||||
|
|
||||||
class NetworkReporter(private val reporterScope: CoroutineScope) {
|
data class ExtendedParams(
|
||||||
|
val server: String,
|
||||||
|
val port: Int
|
||||||
|
) : IReporterParams
|
||||||
|
|
||||||
private var rotationSocketChannel: SocketChannel? = null
|
enum class NetworkService { ROTATOR, FREQUENCY }
|
||||||
private var rotationReporting: Job? = null
|
|
||||||
|
|
||||||
// private var frequencySocketChannel: SocketChannel? = null
|
data class SocketConnection(
|
||||||
// private var frequencyReporting: Job? = null
|
var socket: SocketChannel? = null,
|
||||||
//
|
var connected: Boolean = false,
|
||||||
// fun reportFrequency(server: String, port: Int, frequency: Long) {
|
var connecting: Boolean = false,
|
||||||
// frequencyReporting = reporterScope.launch {
|
var connectionJob: Job? = null
|
||||||
// runCatching {
|
)
|
||||||
// if (frequencySocketChannel == null) {
|
|
||||||
// frequencySocketChannel = SocketChannel.open(InetSocketAddress(server, port))
|
|
||||||
// } else {
|
|
||||||
// val buffer = ByteBuffer.wrap("\\set_freq $frequency\n".toByteArray())
|
|
||||||
// frequencySocketChannel?.write(buffer)
|
|
||||||
// }
|
|
||||||
// }.onFailure { error ->
|
|
||||||
// println(error.localizedMessage)
|
|
||||||
// frequencySocketChannel = null
|
|
||||||
// frequencyReporting?.cancelAndJoin()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
fun reportRotation(server: String, port: Int, azimuth: Double, elevation: Double) {
|
class NetworkReporter(private val reporterScope: CoroutineScope) : IReporterRepo<ExtendedParams> {
|
||||||
rotationReporting = reporterScope.launch {
|
private val serviceToAddress = mutableMapOf<NetworkService, String>()
|
||||||
val newElevation = if (elevation > 0.0) elevation else 0.0
|
private val connections = mutableMapOf<String, SocketConnection>()
|
||||||
runCatching {
|
private val writeMutex = Mutex()
|
||||||
if (rotationSocketChannel == null) {
|
|
||||||
rotationSocketChannel = SocketChannel.open(InetSocketAddress(server, port))
|
fun isConnected(service: NetworkService): Boolean {
|
||||||
} else {
|
val addr = serviceToAddress[service] ?: return false
|
||||||
val buffer = ByteBuffer.wrap("\\P $azimuth $newElevation\n".toByteArray())
|
return connections[addr]?.connected == true
|
||||||
rotationSocketChannel?.write(buffer)
|
}
|
||||||
}
|
|
||||||
}.onFailure { error ->
|
private fun getOrCreateConnection(addr: String): SocketConnection {
|
||||||
println(error.localizedMessage)
|
return connections.getOrPut(addr) { SocketConnection() }
|
||||||
rotationSocketChannel = null
|
}
|
||||||
rotationReporting?.cancelAndJoin()
|
|
||||||
|
fun connect(service: NetworkService, server: String, port: Int) {
|
||||||
|
val addr = "$server:$port"
|
||||||
|
serviceToAddress[service] = addr
|
||||||
|
val connection = getOrCreateConnection(addr)
|
||||||
|
if (connection.connected || connection.connecting) return
|
||||||
|
connection.connectionJob = reporterScope.launch {
|
||||||
|
try {
|
||||||
|
connection.connecting = true
|
||||||
|
val socket = SocketChannel.open(InetSocketAddress(server, port))
|
||||||
|
connection.socket = socket
|
||||||
|
connection.connected = true
|
||||||
|
println("NetworkReporter: $service connected to $addr")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("NetworkReporter connect error: ${e.message}")
|
||||||
|
connection.connected = false
|
||||||
|
} finally {
|
||||||
|
connection.connecting = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun write(service: NetworkService, command: String) {
|
||||||
|
val addr = serviceToAddress[service] ?: return
|
||||||
|
val connection = connections[addr] ?: return
|
||||||
|
if (!connection.connected) return
|
||||||
|
try {
|
||||||
|
writeMutex.withLock {
|
||||||
|
val buffer = ByteBuffer.wrap("\\$command\n".toByteArray())
|
||||||
|
connection.socket?.write(buffer)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("NetworkReporter write error: ${e.message}")
|
||||||
|
connection.connected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportRotation(format: String, azimuth: Double, elevation: Double, params: ExtendedParams) {
|
||||||
|
reporterScope.launch {
|
||||||
|
connect(NetworkService.ROTATOR, params.server, params.port)
|
||||||
|
if (!isConnected(NetworkService.ROTATOR)) return@launch
|
||||||
|
val el = if (elevation > 0.0) elevation else 0.0
|
||||||
|
val command = format
|
||||||
|
.replace("\$AZ", azimuth.toString())
|
||||||
|
.replace("\$EL", el.toString())
|
||||||
|
write(NetworkService.ROTATOR, command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reportFrequency(format: String, frequency: Long, params: ExtendedParams) {
|
||||||
|
reporterScope.launch {
|
||||||
|
connect(NetworkService.FREQUENCY, params.server, params.port)
|
||||||
|
if (!isConnected(NetworkService.FREQUENCY)) return@launch
|
||||||
|
val command = format.replace("\$FREQ", frequency.toString())
|
||||||
|
write(NetworkService.FREQUENCY, command)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,10 +42,13 @@ class SettingsRepo(
|
|||||||
private val preferences: SharedPreferences
|
private val preferences: SharedPreferences
|
||||||
) : ISettingsRepo, LocationListenerCompat {
|
) : ISettingsRepo, LocationListenerCompat {
|
||||||
|
|
||||||
private val keyBluetoothAddress = "bluetoothAddress"
|
private val keyBluetoothRotatorAddress = "bluetoothAddress"
|
||||||
private val keyBluetoothName = "bluetoothName"
|
private val keyBluetoothRotatorName = "bluetoothName"
|
||||||
private val keyBluetoothFormat = "bluetoothFormat"
|
private val keyBluetoothRotatorFormat = "bluetoothFormat"
|
||||||
private val keyBluetoothState = "bluetoothState"
|
private val keyBluetoothRotatorState = "bluetoothState"
|
||||||
|
private val keyBluetoothFrequencyState = "bluetoothFrequencyState"
|
||||||
|
private val keyBluetoothFrequencyAddress = "bluetoothFrequencyAddress"
|
||||||
|
private val keyBluetoothFrequencyFormat = "bluetoothFrequencyFormat"
|
||||||
private val keyFilterHoursAhead = "filterHoursAhead"
|
private val keyFilterHoursAhead = "filterHoursAhead"
|
||||||
private val keyFilterMinElevation = "filterMinElevation"
|
private val keyFilterMinElevation = "filterMinElevation"
|
||||||
private val keyNumberOfRadios = "numberOfRadios"
|
private val keyNumberOfRadios = "numberOfRadios"
|
||||||
@@ -53,6 +56,11 @@ class SettingsRepo(
|
|||||||
private val keyRotatorAddress = "rotatorAddress"
|
private val keyRotatorAddress = "rotatorAddress"
|
||||||
private val keyRotatorPort = "rotatorPort"
|
private val keyRotatorPort = "rotatorPort"
|
||||||
private val keyRotatorState = "rotatorState"
|
private val keyRotatorState = "rotatorState"
|
||||||
|
private val keyRotatorFormat = "rotatorFormat"
|
||||||
|
private val keyFrequencyState = "frequencyState"
|
||||||
|
private val keyFrequencyAddress = "frequencyAddress"
|
||||||
|
private val keyFrequencyPort = "frequencyPort"
|
||||||
|
private val keyFrequencyFormat = "frequencyFormat"
|
||||||
private val keySelectedIds = "selectedIds"
|
private val keySelectedIds = "selectedIds"
|
||||||
private val keySelectedTypes = "selectedTypes"
|
private val keySelectedTypes = "selectedTypes"
|
||||||
private val keySelectedModes = "selectedModes"
|
private val keySelectedModes = "selectedModes"
|
||||||
@@ -240,24 +248,39 @@ class SettingsRepo(
|
|||||||
private val _rcSettings = MutableStateFlow(getRCSettings())
|
private val _rcSettings = MutableStateFlow(getRCSettings())
|
||||||
override val rcSettings: StateFlow<RCSettings> = _rcSettings
|
override val rcSettings: StateFlow<RCSettings> = _rcSettings
|
||||||
|
|
||||||
override fun setBluetoothAddress(value: String) {
|
override fun setBluetoothRotatorAddress(value: String) {
|
||||||
preferences.edit { putString(keyBluetoothAddress, value) }
|
preferences.edit { putString(keyBluetoothRotatorAddress, value) }
|
||||||
_rcSettings.update { it.copy(bluetoothAddress = value) }
|
_rcSettings.update { it.copy(bluetoothRotatorAddress = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setBluetoothFormat(value: String) {
|
override fun setBluetoothRotatorFormat(value: String) {
|
||||||
preferences.edit { putString(keyBluetoothFormat, value) }
|
preferences.edit { putString(keyBluetoothRotatorFormat, value) }
|
||||||
_rcSettings.update { it.copy(bluetoothFormat = value) }
|
_rcSettings.update { it.copy(bluetoothRotatorFormat = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setBluetoothName(value: String) {
|
override fun setBluetoothRotatorName(value: String) {
|
||||||
preferences.edit { putString(keyBluetoothName, value) }
|
preferences.edit { putString(keyBluetoothRotatorName, value) }
|
||||||
_rcSettings.update { it.copy(bluetoothName = value) }
|
_rcSettings.update { it.copy(bluetoothRotatorName = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setBluetoothState(value: Boolean) {
|
override fun setBluetoothRotatorState(value: Boolean) {
|
||||||
preferences.edit { putBoolean(keyBluetoothState, value) }
|
preferences.edit { putBoolean(keyBluetoothRotatorState, value) }
|
||||||
_rcSettings.update { it.copy(bluetoothState = value) }
|
_rcSettings.update { it.copy(bluetoothRotatorState = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBluetoothFrequencyState(value: Boolean) {
|
||||||
|
preferences.edit { putBoolean(keyBluetoothFrequencyState, value) }
|
||||||
|
_rcSettings.update { it.copy(bluetoothFrequencyState = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBluetoothFrequencyAddress(value: String) {
|
||||||
|
preferences.edit { putString(keyBluetoothFrequencyAddress, value) }
|
||||||
|
_rcSettings.update { it.copy(bluetoothFrequencyAddress = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBluetoothFrequencyFormat(value: String) {
|
||||||
|
preferences.edit { putString(keyBluetoothFrequencyFormat, value) }
|
||||||
|
_rcSettings.update { it.copy(bluetoothFrequencyFormat = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRotatorAddress(value: String) {
|
override fun setRotatorAddress(value: String) {
|
||||||
@@ -275,14 +298,47 @@ class SettingsRepo(
|
|||||||
_rcSettings.update { it.copy(rotatorState = value) }
|
_rcSettings.update { it.copy(rotatorState = value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setRotatorFormat(value: String) {
|
||||||
|
preferences.edit { putString(keyRotatorFormat, value) }
|
||||||
|
_rcSettings.update { it.copy(rotatorFormat = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setFrequencyState(value: Boolean) {
|
||||||
|
preferences.edit { putBoolean(keyFrequencyState, value) }
|
||||||
|
_rcSettings.update { it.copy(frequencyState = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setFrequencyAddress(value: String) {
|
||||||
|
preferences.edit { putString(keyFrequencyAddress, value) }
|
||||||
|
_rcSettings.update { it.copy(frequencyAddress = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setFrequencyPort(value: String) {
|
||||||
|
preferences.edit { putString(keyFrequencyPort, value) }
|
||||||
|
_rcSettings.update { it.copy(frequencyPort = value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setFrequencyFormat(value: String) {
|
||||||
|
preferences.edit { putString(keyFrequencyFormat, value) }
|
||||||
|
_rcSettings.update { it.copy(frequencyFormat = value) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun getRCSettings(): RCSettings = RCSettings(
|
private fun getRCSettings(): RCSettings = RCSettings(
|
||||||
rotatorState = preferences.getBoolean(keyRotatorState, false),
|
rotatorState = preferences.getBoolean(keyRotatorState, false),
|
||||||
rotatorAddress = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1",
|
rotatorAddress = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1",
|
||||||
rotatorPort = preferences.getString(keyRotatorPort, null) ?: "4533",
|
rotatorPort = preferences.getString(keyRotatorPort, null) ?: "4533",
|
||||||
bluetoothState = preferences.getBoolean(keyBluetoothState, false),
|
rotatorFormat = preferences.getString(keyRotatorFormat, null) ?: $$"P $AZ $EL",
|
||||||
bluetoothFormat = preferences.getString(keyBluetoothFormat, null) ?: $$"W$AZ $EL",
|
frequencyState = preferences.getBoolean(keyFrequencyState, false),
|
||||||
bluetoothName = preferences.getString(keyBluetoothName, null) ?: "Default",
|
frequencyAddress = preferences.getString(keyFrequencyAddress, null) ?: "127.0.0.1",
|
||||||
bluetoothAddress = preferences.getString(keyBluetoothAddress, null) ?: "00:0C:BF:13:80:5D"
|
frequencyPort = preferences.getString(keyFrequencyPort, null) ?: "4532",
|
||||||
|
frequencyFormat = preferences.getString(keyFrequencyFormat, null) ?: $$"set_freq $FREQ",
|
||||||
|
bluetoothRotatorState = preferences.getBoolean(keyBluetoothRotatorState, false),
|
||||||
|
bluetoothRotatorFormat = preferences.getString(keyBluetoothRotatorFormat, null) ?: $$"W$AZ $EL",
|
||||||
|
bluetoothRotatorName = preferences.getString(keyBluetoothRotatorName, null) ?: "Default",
|
||||||
|
bluetoothRotatorAddress = preferences.getString(keyBluetoothRotatorAddress, null) ?: "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyState = preferences.getBoolean(keyBluetoothFrequencyState, false),
|
||||||
|
bluetoothFrequencyAddress = preferences.getString(keyBluetoothFrequencyAddress, null) ?: "00:0C:BF:13:80:5D",
|
||||||
|
bluetoothFrequencyFormat = preferences.getString(keyBluetoothFrequencyFormat, null) ?: $$"FA$FREQ"
|
||||||
)
|
)
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,18 @@ data class RCSettings(
|
|||||||
val rotatorState: Boolean,
|
val rotatorState: Boolean,
|
||||||
val rotatorAddress: String,
|
val rotatorAddress: String,
|
||||||
val rotatorPort: String,
|
val rotatorPort: String,
|
||||||
val bluetoothState: Boolean,
|
val rotatorFormat: String,
|
||||||
val bluetoothFormat: String,
|
val frequencyState: Boolean,
|
||||||
val bluetoothName: String,
|
val frequencyAddress: String,
|
||||||
val bluetoothAddress: String,
|
val frequencyPort: String,
|
||||||
|
val frequencyFormat: String,
|
||||||
|
val bluetoothRotatorState: Boolean,
|
||||||
|
val bluetoothRotatorFormat: String,
|
||||||
|
val bluetoothRotatorName: String,
|
||||||
|
val bluetoothRotatorAddress: String,
|
||||||
|
val bluetoothFrequencyState: Boolean,
|
||||||
|
val bluetoothFrequencyFormat: String,
|
||||||
|
val bluetoothFrequencyAddress: String
|
||||||
)
|
)
|
||||||
|
|
||||||
data class OtherSettings(
|
data class OtherSettings(
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2026 Arty Bishop and contributors.
|
||||||
|
*
|
||||||
|
* 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.rtbishop.look4sat.domain.repository
|
||||||
|
|
||||||
|
interface IReporterParams
|
||||||
|
|
||||||
|
interface IReporterRepo<T : IReporterParams> {
|
||||||
|
fun reportRotation(format: String, azimuth: Double, elevation: Double, params: T)
|
||||||
|
fun reportFrequency(format: String, frequency: Long, params: T)
|
||||||
|
}
|
||||||
@@ -55,13 +55,22 @@ interface ISettingsRepo {
|
|||||||
|
|
||||||
//region # RC settings
|
//region # RC settings
|
||||||
val rcSettings: StateFlow<RCSettings>
|
val rcSettings: StateFlow<RCSettings>
|
||||||
fun setBluetoothAddress(value: String)
|
fun setBluetoothRotatorAddress(value: String)
|
||||||
fun setBluetoothFormat(value: String)
|
fun setBluetoothRotatorFormat(value: String)
|
||||||
fun setBluetoothName(value: String)
|
fun setBluetoothRotatorName(value: String)
|
||||||
fun setBluetoothState(value: Boolean)
|
fun setBluetoothRotatorState(value: Boolean)
|
||||||
|
fun setBluetoothFrequencyAddress(value: String)
|
||||||
|
fun setBluetoothFrequencyFormat(value: String)
|
||||||
|
fun setBluetoothFrequencyState(value: Boolean)
|
||||||
fun setRotatorAddress(value: String)
|
fun setRotatorAddress(value: String)
|
||||||
fun setRotatorPort(value: String)
|
fun setRotatorPort(value: String)
|
||||||
fun setRotatorState(value: Boolean)
|
fun setRotatorState(value: Boolean)
|
||||||
|
fun setRotatorFormat(value: String)
|
||||||
|
fun setFrequencyAddress(value: String)
|
||||||
|
fun setFrequencyPort(value: String)
|
||||||
|
fun setFrequencyState(value: Boolean)
|
||||||
|
fun setFrequencyFormat(value: String)
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region # Other settings
|
//region # Other settings
|
||||||
|
|||||||
Reference in new issue
Block a user