From f8e7bcdf394e2ab481e0270b27bcac16f7ddefa9 Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Thu, 30 Mar 2023 21:21:48 +0100 Subject: [PATCH] Even more restructuring and code cleanup --- .../com/rtbishop/look4sat/MainContainer.kt | 19 ++- .../look4sat/framework/SettingsRepo.kt | 118 ++++++++++-------- .../{SensorsRepo.kt => data/SensorSource.kt} | 22 ++-- .../look4sat/presentation/map/MapViewModel.kt | 22 ++-- .../presentation/passes/PassesScreen.kt | 7 +- .../presentation/passes/PassesViewModel.kt | 42 +++---- .../presentation/radar/RadarViewModel.kt | 45 ++++--- .../ISensorsRepo.kt => data/ISensorSource.kt} | 4 +- .../rtbishop/look4sat/data/SatelliteRepo.kt | 77 ++++++------ .../look4sat/domain/ISatelliteRepo.kt | 23 ++-- .../rtbishop/look4sat/domain/ISettingsRepo.kt | 54 +++++--- .../com/rtbishop/look4sat/model/Settings.kt | 6 +- 12 files changed, 222 insertions(+), 217 deletions(-) rename app/src/main/java/com/rtbishop/look4sat/framework/{SensorsRepo.kt => data/SensorSource.kt} (80%) rename base/src/main/java/com/rtbishop/look4sat/{domain/ISensorsRepo.kt => data/ISensorSource.kt} (70%) diff --git a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt index c56c98e5..adda728b 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt @@ -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) diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepo.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepo.kt index 1366bc36..0f594228 100644 --- a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepo.kt +++ b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepo.kt @@ -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 + + 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) { + val stringList = catnums.map { catnum -> catnum.toString() } + preferences.edit { putStringSet("type$type", stringList.toSet()) } + } + + override fun loadSatType(type: String): List { + 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> = _satelliteSelection @@ -141,49 +176,36 @@ class SettingsRepo( return catNums?.map { catnum -> catnum.toInt() }?.sorted() ?: emptyList() } - override fun saveSatType(type: String, catnums: List) { - 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 + + override fun savePassesSettings(settings: PassesSettings) = preferences.edit { + putInt(keyHoursAhead, settings.hoursAhead) + putDouble(keyMinElevation, settings.minElevation) + _passesSettings.value = settings } - override fun loadSatType(type: String): List { - val catnums = - preferences.getStringSet("type$type", emptySet())?.map { catnum -> catnum.toInt() } - return catnums ?: emptyList() + override fun saveModesSelection(modes: List) { + preferences.edit { putStringSet(keyModes, modes.toSet()) } } - override fun getHoursAhead(): Int { - return preferences.getInt(keyHoursAhead, 24) + override fun loadModesSelection(): List { + 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 - - 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 @@ -216,13 +238,9 @@ class SettingsRepo( return OtherSettings(utcState, updateState, sweepState, sensorState) } - override fun saveModesSelection(modes: List) { - preferences.edit { putStringSet(keyModes, modes.toSet()) } - } + //endregion - override fun loadModesSelection(): List { - 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())) } diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/SensorsRepo.kt b/app/src/main/java/com/rtbishop/look4sat/framework/data/SensorSource.kt similarity index 80% rename from app/src/main/java/com/rtbishop/look4sat/framework/SensorsRepo.kt rename to app/src/main/java/com/rtbishop/look4sat/framework/data/SensorSource.kt index aa21e0ce..26122641 100644 --- a/app/src/main/java/com/rtbishop/look4sat/framework/SensorsRepo.kt +++ b/app/src/main/java/com/rtbishop/look4sat/framework/data/SensorSource.kt @@ -15,30 +15,30 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -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> = _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) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt index 68f06588..4b80d9cd 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt @@ -49,8 +49,8 @@ class MapViewModel( ) : ViewModel() { private val stationPos = settingsRepo.stationPosition.value - private var allPasses = satelliteRepo.getPasses() - private var allSatellites = listOf() + 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) } } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt index 8f8cd64d..df174d03 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt @@ -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) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt index 151e08b3..982a6a7d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt @@ -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>> = _passes val timerText: StateFlow?> = _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 { diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt index 8882d981..0f4b9c0c 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt @@ -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>(emptyList()) val radarData = mutableStateOf(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("catNum") ?: 0 val aosTime = savedStateHandle.get("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() ) } } diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISensorsRepo.kt b/base/src/main/java/com/rtbishop/look4sat/data/ISensorSource.kt similarity index 70% rename from base/src/main/java/com/rtbishop/look4sat/domain/ISensorsRepo.kt rename to base/src/main/java/com/rtbishop/look4sat/data/ISensorSource.kt index 2f7e9223..30b64b09 100644 --- a/base/src/main/java/com/rtbishop/look4sat/domain/ISensorsRepo.kt +++ b/base/src/main/java/com/rtbishop/look4sat/data/ISensorSource.kt @@ -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> diff --git a/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepo.kt b/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepo.kt index 6542fad3..7ae59c75 100644 --- a/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepo.kt +++ b/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepo.kt @@ -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() - private val _calculatedPasses = MutableSharedFlow>(replay = 1) - override val calculatedPasses: SharedFlow> = _calculatedPasses + private val _passes = MutableStateFlow>(emptyList()) + override val passes: StateFlow> = _passes - override fun getPasses(): List = passes - - override suspend fun getEntriesWithIds(ids: List) = localStorage.getEntriesWithIds(ids) + private val _satellites = MutableStateFlow>(emptyList()) + override val satellites: StateFlow> = _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, pos: GeoPos, time: Long, hoursAhead: Int, minElevation: Double - ) { - if (satList.isEmpty()) { - val newPasses = emptyList() - 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() - 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) } diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepo.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepo.kt index 37ece884..554421aa 100644 --- a/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepo.kt +++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepo.kt @@ -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> + val passes: StateFlow> - fun getPasses(): List - - suspend fun getEntriesWithIds(ids: List): List + val satellites: StateFlow> suspend fun getRadiosWithId(id: Int): List + 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 suspend fun processRadios( - sat: Satellite, - pos: GeoPos, - radios: List, - time: Long + sat: Satellite, pos: GeoPos, radios: List, time: Long ): List suspend fun processPasses(passList: List, time: Long): List - suspend fun calculatePasses( - satList: List, - pos: GeoPos, - time: Long, - hoursAhead: Int = 8, - minElevation: Double = 16.0 - ) + suspend fun calculatePasses(time: Long, hoursAhead: Int = 8, minElevation: Double = 16.0) } diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepo.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepo.kt index e853e722..2a8931ff 100644 --- a/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepo.kt +++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepo.kt @@ -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 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 + //region # Station position settings - val satelliteSelection: StateFlow> + val stationPosition: StateFlow 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 fun saveDatabaseState(state: DatabaseState) + fun saveSatType(type: String, catnums: List) + + fun loadSatType(type: String): List + + //endregion + + //region # Entries selection settings + + val satelliteSelection: StateFlow> + + fun saveEntriesSelection(catnums: List) + + //endregion + + //region # Passes filter settings + + val passesSettings: StateFlow + + fun savePassesSettings(settings: PassesSettings) + + fun saveModesSelection(modes: List) + + fun loadModesSelection(): List + + //endregion + + //region # Other settings + val otherSettings: StateFlow fun toggleUtc(value: Boolean) @@ -88,15 +112,9 @@ interface ISettingsRepo { fun toggleSensor(value: Boolean) - fun saveModesSelection(modes: List) + //endregion - fun loadModesSelection(): List - - fun saveEntriesSelection(catnums: List) - - fun saveSatType(type: String, catnums: List) - - fun loadSatType(type: String): List + //region # Undefined settings fun getRotatorEnabled(): Boolean @@ -125,4 +143,6 @@ interface ISettingsRepo { fun getBTFormat(): String fun setBTFormat(value: String) + + //endregion } diff --git a/base/src/main/java/com/rtbishop/look4sat/model/Settings.kt b/base/src/main/java/com/rtbishop/look4sat/model/Settings.kt index 513cedb4..45800c44 100644 --- a/base/src/main/java/com/rtbishop/look4sat/model/Settings.kt +++ b/base/src/main/java/com/rtbishop/look4sat/model/Settings.kt @@ -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)