Even more restructuring and code cleanup

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:40 +00:00
1 parent a807cfd8f6
commit f8e7bcdf39
12 files changed
+222 -217

No files matched your search

@@ -8,21 +8,21 @@ import android.location.LocationManager
import androidx.room.Room
import com.rtbishop.look4sat.data.DataParser
import com.rtbishop.look4sat.data.DatabaseRepo
import com.rtbishop.look4sat.data.ISensorSource
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.data.SelectionRepo
import com.rtbishop.look4sat.domain.IDatabaseRepo
import com.rtbishop.look4sat.domain.ISatelliteRepo
import com.rtbishop.look4sat.domain.ISelectionRepo
import com.rtbishop.look4sat.domain.ISensorsRepo
import com.rtbishop.look4sat.domain.ISettingsRepo
import com.rtbishop.look4sat.framework.BluetoothReporter
import com.rtbishop.look4sat.framework.NetworkReporter
import com.rtbishop.look4sat.framework.SensorsRepo
import com.rtbishop.look4sat.framework.SettingsRepo
import com.rtbishop.look4sat.framework.data.DataSource
import com.rtbishop.look4sat.framework.data.LocalStorage
import com.rtbishop.look4sat.framework.data.MIGRATION_1_2
import com.rtbishop.look4sat.framework.data.MainDatabase
import com.rtbishop.look4sat.framework.data.SensorSource
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -40,7 +40,6 @@ class MainContainer(private val context: Context) {
val databaseRepo = provideDatabaseRepo()
val satelliteRepo = provideSatelliteRepo()
val selectionRepo = provideSelectionRepo()
val sensorsRepo = provideSensorsRepo()
fun provideBluetoothReporter(): BluetoothReporter {
val btManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
@@ -51,6 +50,12 @@ class MainContainer(private val context: Context) {
return NetworkReporter(CoroutineScope(Dispatchers.IO))
}
fun provideSensorSource(): ISensorSource {
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
return SensorSource(sensorManager, sensor)
}
private fun provideDatabaseRepo(): IDatabaseRepo {
val dataParser = DataParser(Dispatchers.Default)
val dataSource = DataSource(context.contentResolver, Dispatchers.IO)
@@ -58,19 +63,13 @@ class MainContainer(private val context: Context) {
}
private fun provideSatelliteRepo(): ISatelliteRepo {
return SatelliteRepo(Dispatchers.Default, localStorage)
return SatelliteRepo(Dispatchers.Default, localStorage, settingsRepo)
}
private fun provideSelectionRepo(): ISelectionRepo {
return SelectionRepo(Dispatchers.Default, localStorage, settingsRepo)
}
private fun provideSensorsRepo(): ISensorsRepo {
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
return SensorsRepo(sensorManager, sensor)
}
private fun provideSettingsRepo(): ISettingsRepo {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE)
@@ -27,6 +27,7 @@ import com.rtbishop.look4sat.domain.ISettingsRepo
import com.rtbishop.look4sat.model.DatabaseState
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.OtherSettings
import com.rtbishop.look4sat.model.PassesSettings
import com.rtbishop.look4sat.utility.QthConverter
import com.rtbishop.look4sat.utility.round
import kotlinx.coroutines.flow.MutableStateFlow
@@ -99,15 +100,6 @@ class SettingsRepo(
return true
}
private fun loadStationPosition(): GeoPos {
val latitude = (preferences.getString(keyLatitude, null) ?: "0.0").toDouble()
val longitude = (preferences.getString(keyLongitude, null) ?: "0.0").toDouble()
val altitude = (preferences.getString(keyAltitude, null) ?: "0.0").toDouble()
val qthLocator = preferences.getString(keyLocator, null) ?: "null"
val timestamp = preferences.getLong(keyLocTimestamp, 0L)
return GeoPos(latitude, longitude, altitude, qthLocator, timestamp)
}
private fun saveStationPosition(stationPos: GeoPos) = preferences.edit {
putString(keyLatitude, stationPos.latitude.toString())
putString(keyLongitude, stationPos.longitude.toString())
@@ -126,8 +118,51 @@ class SettingsRepo(
saveStationPosition(GeoPos(newLat, newLon, newAlt, locator, timestamp))
}
private fun loadStationPosition(): GeoPos {
val latitude = (preferences.getString(keyLatitude, null) ?: "0.0").toDouble()
val longitude = (preferences.getString(keyLongitude, null) ?: "0.0").toDouble()
val altitude = (preferences.getString(keyAltitude, null) ?: "0.0").toDouble()
val qthLocator = preferences.getString(keyLocator, null) ?: "null"
val timestamp = preferences.getLong(keyLocTimestamp, 0L)
return GeoPos(latitude, longitude, altitude, qthLocator, timestamp)
}
//endregion
//region # Database update settings
private val _databaseState = MutableStateFlow(loadDatabaseState())
override val databaseState: StateFlow<DatabaseState> = _databaseState
override fun saveDatabaseState(state: DatabaseState) = preferences.edit {
putInt(keyDataEntries, state.entriesTotal)
putInt(keyDataRadios, state.radiosTotal)
putLong(keyDataTimestamp, state.timestamp)
_databaseState.value = state
}
override fun saveSatType(type: String, catnums: List<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
preferences.edit { putStringSet("type$type", stringList.toSet()) }
}
override fun loadSatType(type: String): List<Int> {
val catnums =
preferences.getStringSet("type$type", emptySet())?.map { catnum -> catnum.toInt() }
return catnums ?: emptyList()
}
private fun loadDatabaseState(): DatabaseState {
val entriesTotal = preferences.getInt(keyDataEntries, 0)
val radiosTotal = preferences.getInt(keyDataRadios, 0)
val timestamp = preferences.getLong(keyDataTimestamp, 0L)
return DatabaseState(entriesTotal, radiosTotal, timestamp)
}
//endregion
//region # Entries selection settings
private val _satelliteSelection = MutableStateFlow(loadEntriesSelection())
override val satelliteSelection: StateFlow<List<Int>> = _satelliteSelection
@@ -141,49 +176,36 @@ class SettingsRepo(
return catNums?.map { catnum -> catnum.toInt() }?.sorted() ?: emptyList()
}
override fun saveSatType(type: String, catnums: List<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
preferences.edit { putStringSet("type$type", stringList.toSet()) }
//endregion
//region # Passes filter settings
private val _passesSettings = MutableStateFlow(loadPassesSettings())
override val passesSettings: StateFlow<PassesSettings> = _passesSettings
override fun savePassesSettings(settings: PassesSettings) = preferences.edit {
putInt(keyHoursAhead, settings.hoursAhead)
putDouble(keyMinElevation, settings.minElevation)
_passesSettings.value = settings
}
override fun loadSatType(type: String): List<Int> {
val catnums =
preferences.getStringSet("type$type", emptySet())?.map { catnum -> catnum.toInt() }
return catnums ?: emptyList()
override fun saveModesSelection(modes: List<String>) {
preferences.edit { putStringSet(keyModes, modes.toSet()) }
}
override fun getHoursAhead(): Int {
return preferences.getInt(keyHoursAhead, 24)
override fun loadModesSelection(): List<String> {
return preferences.getStringSet(keyModes, null)?.toList()?.sorted() ?: emptyList()
}
override fun setHoursAhead(hoursAhead: Int) {
preferences.edit { putInt(keyHoursAhead, hoursAhead) }
private fun loadPassesSettings(): PassesSettings {
val hoursAhead = preferences.getInt(keyHoursAhead, 24)
val minElevation = preferences.getDouble(keyMinElevation, 16.0)
return PassesSettings(hoursAhead, minElevation)
}
override fun getMinElevation(): Double {
return preferences.getDouble(keyMinElevation, 16.0)
}
//endregion
override fun setMinElevation(minElevation: Double) {
preferences.edit { putDouble(keyMinElevation, minElevation) }
}
private val _databaseState = MutableStateFlow(loadDatabaseState())
override val databaseState: StateFlow<DatabaseState> = _databaseState
override fun saveDatabaseState(state: DatabaseState) = preferences.edit {
putInt(keyDataEntries, state.entriesTotal)
putInt(keyDataRadios, state.radiosTotal)
putLong(keyDataTimestamp, state.timestamp)
_databaseState.value = state
}
private fun loadDatabaseState(): DatabaseState {
val entriesTotal = preferences.getInt(keyDataEntries, 0)
val radiosTotal = preferences.getInt(keyDataRadios, 0)
val timestamp = preferences.getLong(keyDataTimestamp, 0L)
return DatabaseState(entriesTotal, radiosTotal, timestamp)
}
//region # Other settings
private val _otherSettings = MutableStateFlow(loadOtherSettings())
override val otherSettings: StateFlow<OtherSettings> = _otherSettings
@@ -216,13 +238,9 @@ class SettingsRepo(
return OtherSettings(utcState, updateState, sweepState, sensorState)
}
override fun saveModesSelection(modes: List<String>) {
preferences.edit { putStringSet(keyModes, modes.toSet()) }
}
//endregion
override fun loadModesSelection(): List<String> {
return preferences.getStringSet(keyModes, null)?.toList()?.sorted() ?: emptyList()
}
//region # Undefined settings
override fun getRotatorEnabled(): Boolean {
return preferences.getBoolean(keyRotator, false)
@@ -280,6 +298,8 @@ class SettingsRepo(
preferences.edit { putString(keyBTFormat, value) }
}
//endregion
private fun SharedPreferences.getDouble(key: String, default: Double): Double {
return Double.fromBits(getLong(key, default.toRawBits()))
}
@@ -15,30 +15,30 @@
* 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.framework
package com.rtbishop.look4sat.framework.data
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import com.rtbishop.look4sat.domain.ISensorsRepo
import com.rtbishop.look4sat.data.ISensorSource
import com.rtbishop.look4sat.domain.RAD2DEG
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlin.math.round
class SensorsRepo(private val sensorManager: SensorManager, private val sensor: Sensor?) :
SensorEventListener, ISensorsRepo {
private val rotationMatrix = FloatArray(9)
private val orientationValues = FloatArray(3)
private var sensorAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE
class SensorSource(private val sensorManager: SensorManager, private val sensor: Sensor?) :
SensorEventListener, ISensorSource {
private val _orientation = MutableStateFlow(Pair(0f, 0f))
private val rotationMatrix = FloatArray(9)
private val orientationValues = FloatArray(3)
private var sensorAccuracy = SensorManager.SENSOR_STATUS_UNRELIABLE
override val orientation: StateFlow<Pair<Float, Float>> = _orientation
override fun enableSensor() {
sensor?.let { sensorManager.registerListener(this, it, 16000) }
sensor?.let { sensorManager.registerListener(this, it, 8000) }
}
override fun disableSensor() = sensorManager.unregisterListener(this)
@@ -57,12 +57,10 @@ class SensorsRepo(private val sensorManager: SensorManager, private val sensor:
SensorManager.getRotationMatrixFromVector(rotationMatrix, rotationVector)
SensorManager.getOrientation(rotationMatrix, orientationValues)
val azimuth = (orientationValues[0] * RAD2DEG).toFloat()
val pitch = (orientationValues[1] * RAD2DEG).toFloat()
// val roll = (orientationValues[2] * RAD2DEG).toFloat()
val pitch = (orientationValues[1] * RAD2DEG).toFloat() // roll [2]
val magneticAzimuth = (azimuth + 360f) % 360f
val roundedAzimuth = round(magneticAzimuth * 10) / 10
val roundedPitch = round(pitch * 10) / 10
// val roundedRoll = round(roll * 10) / 10
_orientation.value = Pair(roundedAzimuth, roundedPitch)
}
}
@@ -49,8 +49,8 @@ class MapViewModel(
) : ViewModel() {
private val stationPos = settingsRepo.stationPosition.value
private var allPasses = satelliteRepo.getPasses()
private var allSatellites = listOf<Satellite>()
private var allPasses = satelliteRepo.passes.value
private var allSatellites = satelliteRepo.satellites.value
private var dataUpdateJob: Job? = null
private var dataUpdateRate = 1000L
private var selectedSatellite: Satellite? = null
@@ -87,18 +87,12 @@ class MapViewModel(
}
fun selectDefaultSatellite(catnum: Int) {
viewModelScope.launch {
val selectedIds = settingsRepo.satelliteSelection.value
satelliteRepo.getEntriesWithIds(selectedIds).also { satellites ->
if (satellites.isNotEmpty()) {
allSatellites = satellites
if (catnum == -1) {
allPasses.find { pass -> pass.progress < 100 && !pass.isDeepSpace }
?.let { pass -> selectSatellite(pass.satellite) }
} else {
satellites.find { it.data.catnum == catnum }?.let { selectSatellite(it) }
}
}
if (allSatellites.isNotEmpty()) {
if (catnum == -1) {
allPasses.find { pass -> pass.progress < 100 && !pass.isDeepSpace }
?.let { pass -> selectSatellite(pass.satellite) }
} else {
allSatellites.find { it.data.catnum == catnum }?.let { selectSatellite(it) }
}
}
}
@@ -53,10 +53,9 @@ fun PassesScreen(navToRadar: (Int, Long) -> Unit) {
val showDialog = rememberSaveable { mutableStateOf(false) }
val toggleDialog = { showDialog.value = showDialog.value.not() }
if (showDialog.value) {
FilterDialog(viewModel.getHoursAhead(),
viewModel.getMinElevation(),
{ toggleDialog() }) { hours, elev ->
viewModel.calculatePasses(hours, elev)
val (hoursAhead, minElevation) = viewModel.getFilterSettings()
FilterDialog(hoursAhead, minElevation, { toggleDialog() }) { newHours, newElevation ->
viewModel.calculatePasses(System.currentTimeMillis(), newHours, newElevation)
}
}
@@ -26,6 +26,7 @@ import com.rtbishop.look4sat.MainApplication
import com.rtbishop.look4sat.domain.ISatelliteRepo
import com.rtbishop.look4sat.domain.ISettingsRepo
import com.rtbishop.look4sat.model.DataState
import com.rtbishop.look4sat.model.PassesSettings
import com.rtbishop.look4sat.model.SatPass
import com.rtbishop.look4sat.utility.toTimerString
import kotlinx.coroutines.Job
@@ -47,13 +48,14 @@ class PassesViewModel(
val passes: StateFlow<DataState<List<SatPass>>> = _passes
val timerText: StateFlow<Triple<String, String, String>?> = _timerText
fun getHoursAhead() = settingsRepo.getHoursAhead()
fun getFilterSettings() = settingsRepo.passesSettings.value
fun getMinElevation() = settingsRepo.getMinElevation()
fun shouldUseUTC() = settingsRepo.otherSettings.value.utcState
init {
viewModelScope.launch { satelliteRepo.initRepository() }
viewModelScope.launch {
satelliteRepo.calculatedPasses.collect { passes ->
satelliteRepo.passes.collect { passes ->
passesProcessing?.cancelAndJoin()
passesProcessing = viewModelScope.launch {
while (isActive) {
@@ -84,32 +86,20 @@ class PassesViewModel(
}
}
}
viewModelScope.launch {
settingsRepo.satelliteSelection.collect { calculatePasses() }
}
}
fun shouldUseUTC() = settingsRepo.otherSettings.value.utcState
fun calculatePasses() = viewModelScope.launch {
_passes.emit(DataState.Loading)
passesProcessing?.cancelAndJoin()
val (hoursAhead, minElevation) = settingsRepo.passesSettings.value
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation)
}
fun calculatePasses(
hoursAhead: Int = 1,
minElevation: Double = settingsRepo.getMinElevation(),
timeRef: Long = System.currentTimeMillis()
) {
viewModelScope.launch {
_passes.emit(DataState.Loading)
// _timerText.postValue(timerDefaultText)
passesProcessing?.cancelAndJoin()
// selection?.let { items -> settingsRepository.saveEntriesSelection(items) }
settingsRepo.setHoursAhead(hoursAhead)
settingsRepo.setMinElevation(minElevation)
val stationPos = settingsRepo.stationPosition.value
val selectedIds = settingsRepo.satelliteSelection.value
val satellites = satelliteRepo.getEntriesWithIds(selectedIds)
satelliteRepo.calculatePasses(
satellites, stationPos, timeRef, hoursAhead, minElevation
)
}
fun calculatePasses(timeRef: Long, hoursAhead: Int, minElev: Double) = viewModelScope.launch {
_passes.emit(DataState.Loading)
passesProcessing?.cancelAndJoin()
settingsRepo.savePassesSettings(PassesSettings(hoursAhead, minElev))
satelliteRepo.calculatePasses(timeRef, hoursAhead, minElev)
}
companion object {
@@ -28,8 +28,8 @@ import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.rtbishop.look4sat.MainApplication
import com.rtbishop.look4sat.data.ISensorSource
import com.rtbishop.look4sat.domain.ISatelliteRepo
import com.rtbishop.look4sat.domain.ISensorsRepo
import com.rtbishop.look4sat.domain.ISettingsRepo
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.framework.BluetoothReporter
@@ -51,20 +51,20 @@ class RadarViewModel(
private val networkReporter: NetworkReporter,
private val satelliteRepo: ISatelliteRepo,
private val settingsRepo: ISettingsRepo,
private val sensorsRepo: ISensorsRepo
private val sensorSource: ISensorSource
) : ViewModel() {
private val stationPos = settingsRepo.stationPosition.value
private val magDeclination = getMagDeclination(stationPos)
val transmitters = mutableStateOf<List<SatRadio>>(emptyList())
val radarData = mutableStateOf<RadarData?>(null)
val orientation = mutableStateOf(sensorsRepo.orientation.value)
val orientation = mutableStateOf(sensorSource.orientation.value)
init {
if (settingsRepo.otherSettings.value.sensorState) {
viewModelScope.launch {
sensorsRepo.enableSensor()
sensorsRepo.orientation.collect { data ->
sensorSource.enableSensor()
sensorSource.orientation.collect { data ->
orientation.value = Pair(data.first + magDeclination, data.second)
}
}
@@ -72,29 +72,28 @@ class RadarViewModel(
}
override fun onCleared() {
sensorsRepo.disableSensor()
sensorSource.disableSensor()
super.onCleared()
}
fun getPass() = flow {
val catNum = savedStateHandle.get<Int>("catNum") ?: 0
val aosTime = savedStateHandle.get<Long>("aosTime") ?: 0L
satelliteRepo.calculatedPasses.collect { passes ->
val pass = passes.find { pass -> pass.catNum == catNum && pass.aosTime == aosTime }
val currentPass = pass ?: passes.firstOrNull()
currentPass?.let { satPass ->
emit(satPass)
val transmitters = satelliteRepo.getRadiosWithId(satPass.catNum)
viewModelScope.launch {
while (isActive) {
val timeNow = System.currentTimeMillis()
val satPos =
satelliteRepo.getPosition(satPass.satellite, stationPos, timeNow)
sendPassData(satPass, satPos, satPass.satellite)
sendPassDataBT(satPos)
processRadios(transmitters, satPass.satellite, timeNow)
delay(1000)
}
val passes = satelliteRepo.passes.value
val pass = passes.find { pass -> pass.catNum == catNum && pass.aosTime == aosTime }
val currentPass = pass ?: passes.firstOrNull()
currentPass?.let { satPass ->
emit(satPass)
val transmitters = satelliteRepo.getRadiosWithId(satPass.catNum)
viewModelScope.launch {
while (isActive) {
val timeNow = System.currentTimeMillis()
val satPos =
satelliteRepo.getPosition(satPass.satellite, stationPos, timeNow)
sendPassData(satPass, satPos, satPass.satellite)
sendPassDataBT(satPos)
processRadios(transmitters, satPass.satellite, timeNow)
delay(1000)
}
}
}
@@ -165,7 +164,7 @@ class RadarViewModel(
container.provideNetworkReporter(),
container.satelliteRepo,
container.settingsRepo,
container.sensorsRepo
container.provideSensorSource()
)
}
}
@@ -1,8 +1,8 @@
package com.rtbishop.look4sat.domain
package com.rtbishop.look4sat.data
import kotlinx.coroutines.flow.StateFlow
interface ISensorsRepo {
interface ISensorSource {
val orientation: StateFlow<Pair<Float, Float>>
@@ -18,6 +18,7 @@
package com.rtbishop.look4sat.data
import com.rtbishop.look4sat.domain.ISatelliteRepo
import com.rtbishop.look4sat.domain.ISettingsRepo
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPass
@@ -26,25 +27,33 @@ import com.rtbishop.look4sat.model.SatRadio
import com.rtbishop.look4sat.utility.round
import com.rtbishop.look4sat.utility.toDegrees
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext
class SatelliteRepo(
private val dispatcher: CoroutineDispatcher,
private val localStorage: ILocalStorage
private val localStorage: ILocalStorage,
private val settingsRepo: ISettingsRepo
) : ISatelliteRepo {
private var passes = listOf<SatPass>()
private val _calculatedPasses = MutableSharedFlow<List<SatPass>>(replay = 1)
override val calculatedPasses: SharedFlow<List<SatPass>> = _calculatedPasses
private val _passes = MutableStateFlow<List<SatPass>>(emptyList())
override val passes: StateFlow<List<SatPass>> = _passes
override fun getPasses(): List<SatPass> = passes
override suspend fun getEntriesWithIds(ids: List<Int>) = localStorage.getEntriesWithIds(ids)
private val _satellites = MutableStateFlow<List<Satellite>>(emptyList())
override val satellites: StateFlow<List<Satellite>> = _satellites
override suspend fun getRadiosWithId(id: Int) = localStorage.getRadiosWithId(id)
override suspend fun initRepository() = withContext(dispatcher) {
settingsRepo.satelliteSelection.collect { selectedIds ->
_satellites.update { localStorage.getEntriesWithIds(selectedIds) }
val (hoursAhead, minElevation) = settingsRepo.passesSettings.value
calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation)
}
}
override suspend fun getPosition(sat: Satellite, pos: GeoPos, time: Long): SatPos {
return withContext(dispatcher) { sat.getPosition(pos, time) }
}
@@ -70,12 +79,8 @@ class SatelliteRepo(
val satPos = sat.getPosition(pos, time)
val copiedList = radios.map { it.copy() }
copiedList.forEach { transmitter ->
transmitter.downlink?.let {
transmitter.downlink = satPos.getDownlinkFreq(it)
}
transmitter.uplink?.let {
transmitter.uplink = satPos.getUplinkFreq(it)
}
transmitter.downlink?.let { transmitter.downlink = satPos.getDownlinkFreq(it) }
transmitter.uplink?.let { transmitter.uplink = satPos.getUplinkFreq(it) }
}
copiedList.map { it.copy() }
}
@@ -97,23 +102,18 @@ class SatelliteRepo(
}
}
override suspend fun calculatePasses(
satList: List<Satellite>, pos: GeoPos, time: Long, hoursAhead: Int, minElevation: Double
) {
if (satList.isEmpty()) {
val newPasses = emptyList<SatPass>()
passes = newPasses
_calculatedPasses.emit(newPasses)
} else {
override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double) {
if (_satellites.value.isNotEmpty()) {
withContext(dispatcher) {
val allPasses = mutableListOf<SatPass>()
satList.forEach { satellite ->
allPasses.addAll(satellite.getPasses(pos, time, hoursAhead))
val stationPos = settingsRepo.stationPosition.value
_satellites.value.forEach { satellite ->
allPasses.addAll(satellite.getPasses(stationPos, time, hoursAhead))
}
val newPasses = allPasses.filter(time, hoursAhead, minElevation)
passes = newPasses
_calculatedPasses.emit(newPasses)
_passes.update { allPasses.filter(time, hoursAhead, minElevation) }
}
} else {
_passes.update { emptyList() }
}
}
@@ -151,8 +151,7 @@ class SatelliteRepo(
private fun getGeoPass(sat: Satellite, pos: GeoPos, time: Long): SatPass {
val satPos = sat.getPosition(pos, time)
val aos = time - 24 * 60L * 60L * 1000L
val los = time + 24 * 60L * 60L * 1000L
// val tca = (aos + los) / 2
val los = time + 24 * 60L * 60L * 1000L // val tca = (aos + los) / 2
val az = satPos.azimuth.toDegrees().round(1)
val elev = satPos.elevation.toDegrees().round(1)
val alt = satPos.altitude
@@ -164,8 +163,7 @@ class SatelliteRepo(
var calendarTimeMillis = time
var elevation: Double
var maxElevation = 0.0
var alt = 0.0
// var tcaAz = 0.0
var alt = 0.0 // var tcaAz = 0.0
// rewind 1/4 of an orbit
if (rewind) calendarTimeMillis += -quarterOrbitMin * 60L * 1000L
@@ -187,8 +185,7 @@ class SatelliteRepo(
elevation = satPos.elevation
if (elevation > maxElevation) {
maxElevation = elevation
alt = satPos.altitude
// tcaAz = satPos.azimuth.toDegrees()
alt = satPos.altitude // tcaAz = satPos.azimuth.toDegrees()
}
} while (satPos.elevation < 0.0)
@@ -200,8 +197,7 @@ class SatelliteRepo(
elevation = satPos.elevation
if (elevation > maxElevation) {
maxElevation = elevation
alt = satPos.altitude
// tcaAz = satPos.azimuth.toDegrees()
alt = satPos.altitude // tcaAz = satPos.azimuth.toDegrees()
}
} while (satPos.elevation < 0.0)
@@ -215,8 +211,7 @@ class SatelliteRepo(
elevation = satPos.elevation
if (elevation > maxElevation) {
maxElevation = elevation
alt = satPos.altitude
// tcaAz = satPos.azimuth.toDegrees()
alt = satPos.altitude // tcaAz = satPos.azimuth.toDegrees()
}
} while (satPos.elevation > 0.0)
@@ -228,14 +223,12 @@ class SatelliteRepo(
elevation = satPos.elevation
if (elevation > maxElevation) {
maxElevation = elevation
alt = satPos.altitude
// tcaAz = satPos.azimuth.toDegrees()
alt = satPos.altitude // tcaAz = satPos.azimuth.toDegrees()
}
} while (satPos.elevation > 0.0)
val los = satPos.time
val los = satPos.time // val tca = (aos + los) / 2
val losAz = satPos.azimuth.toDegrees().round(1)
// val tca = (aos + los) / 2
val elev = maxElevation.toDegrees().round(1)
return SatPass(aos, aosAz, los, losAz, alt.toInt(), elev, sat)
}
@@ -4,36 +4,27 @@ import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPass
import com.rtbishop.look4sat.model.SatPos
import com.rtbishop.look4sat.model.SatRadio
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
interface ISatelliteRepo {
val calculatedPasses: SharedFlow<List<SatPass>>
val passes: StateFlow<List<SatPass>>
fun getPasses(): List<SatPass>
suspend fun getEntriesWithIds(ids: List<Int>): List<Satellite>
val satellites: StateFlow<List<Satellite>>
suspend fun getRadiosWithId(id: Int): List<SatRadio>
suspend fun initRepository()
suspend fun getPosition(sat: Satellite, pos: GeoPos, time: Long): SatPos
suspend fun getTrack(sat: Satellite, pos: GeoPos, start: Long, end: Long): List<SatPos>
suspend fun processRadios(
sat: Satellite,
pos: GeoPos,
radios: List<SatRadio>,
time: Long
sat: Satellite, pos: GeoPos, radios: List<SatRadio>, time: Long
): List<SatRadio>
suspend fun processPasses(passList: List<SatPass>, time: Long): List<SatPass>
suspend fun calculatePasses(
satList: List<Satellite>,
pos: GeoPos,
time: Long,
hoursAhead: Int = 8,
minElevation: Double = 16.0
)
suspend fun calculatePasses(time: Long, hoursAhead: Int = 8, minElevation: Double = 16.0)
}
@@ -20,12 +20,12 @@ package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.model.DatabaseState
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.OtherSettings
import com.rtbishop.look4sat.model.PassesSettings
import kotlinx.coroutines.flow.StateFlow
interface ISettingsRepo {
val radioSourceUrl: String get() = "https://db.satnogs.org/api/transmitters/?format=json"
val satelliteSourcesMap: Map<String, String>
get() = mapOf(
"All" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=active&FORMAT=csv",
@@ -56,9 +56,9 @@ interface ISettingsRepo {
"X-Comm" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv"
)
val stationPosition: StateFlow<GeoPos>
//region # Station position settings
val satelliteSelection: StateFlow<List<Int>>
val stationPosition: StateFlow<GeoPos>
fun setGpsPosition(): Boolean
@@ -66,18 +66,42 @@ interface ISettingsRepo {
fun setQthPosition(locator: String): Boolean
fun getHoursAhead(): Int
//endregion
fun setHoursAhead(hoursAhead: Int)
fun getMinElevation(): Double
fun setMinElevation(minElevation: Double)
//region # Database update settings
val databaseState: StateFlow<DatabaseState>
fun saveDatabaseState(state: DatabaseState)
fun saveSatType(type: String, catnums: List<Int>)
fun loadSatType(type: String): List<Int>
//endregion
//region # Entries selection settings
val satelliteSelection: StateFlow<List<Int>>
fun saveEntriesSelection(catnums: List<Int>)
//endregion
//region # Passes filter settings
val passesSettings: StateFlow<PassesSettings>
fun savePassesSettings(settings: PassesSettings)
fun saveModesSelection(modes: List<String>)
fun loadModesSelection(): List<String>
//endregion
//region # Other settings
val otherSettings: StateFlow<OtherSettings>
fun toggleUtc(value: Boolean)
@@ -88,15 +112,9 @@ interface ISettingsRepo {
fun toggleSensor(value: Boolean)
fun saveModesSelection(modes: List<String>)
//endregion
fun loadModesSelection(): List<String>
fun saveEntriesSelection(catnums: List<Int>)
fun saveSatType(type: String, catnums: List<Int>)
fun loadSatType(type: String): List<Int>
//region # Undefined settings
fun getRotatorEnabled(): Boolean
@@ -125,4 +143,6 @@ interface ISettingsRepo {
fun getBTFormat(): String
fun setBTFormat(value: String)
//endregion
}
@@ -1,10 +1,12 @@
package com.rtbishop.look4sat.model
data class DatabaseState(val entriesTotal: Int, val radiosTotal: Int, val timestamp: Long)
data class PassesSettings(val hoursAhead: Int, val minElevation: Double)
data class OtherSettings(
val utcState: Boolean,
val updateState: Boolean,
val sweepState: Boolean,
val sensorState: Boolean
)
data class DatabaseState(val entriesTotal: Int, val radiosTotal: Int, val timestamp: Long)