diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3ac0c97e..4aa74d8a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -55,7 +55,6 @@ dependencies { implementation("org.osmdroid:osmdroid-android:6.1.16") debugImplementation("androidx.compose.ui:ui-tooling:1.5.0") debugImplementation("androidx.compose.ui:ui-test-manifest:1.5.0") - debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12") testImplementation("junit:junit:4.13.2") testImplementation("io.mockk:mockk:1.13.7") diff --git a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt index cb4f232e..de17c141 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt @@ -40,8 +40,8 @@ class MainApplication : Application() { private suspend fun checkAutoUpdate() { val settingsRepo = container.settingsRepo - if (settingsRepo.otherSettings.value.updateState) { - val timeDelta = System.currentTimeMillis() - settingsRepo.databaseState.value.timestamp + if (settingsRepo.otherSettings.value.stateOfAutoUpdate) { + val timeDelta = System.currentTimeMillis() - settingsRepo.databaseState.value.updateTimestamp if (timeDelta > AUTO_UPDATE_DELTA_MS) { val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault()) println("Started periodic data update on ${sdf.format(Date())}") diff --git a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt index 47b4bae5..cdee1a1c 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt @@ -99,8 +99,11 @@ class MainContainer(private val context: Context) { private fun provideSettingsRepo(): ISettingsRepo { val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager - val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE) - Configuration.getInstance().load(context, preferences) - return SettingsRepo(manager, preferences) + val appPrefsFileName = "${context.packageName}_preferences" + val appPreferences = context.getSharedPreferences(appPrefsFileName, Context.MODE_PRIVATE) + val mapPrefsFileName = "${context.packageName}_osmdroid" + val mapPreferences = context.getSharedPreferences(mapPrefsFileName, Context.MODE_PRIVATE) + Configuration.getInstance().load(context, mapPreferences) + return SettingsRepo(manager, appPreferences) } } 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 bb7554c1..b4d92661 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 @@ -98,7 +98,7 @@ class PassesViewModel( fun calculatePasses(timeRef: Long, hoursAhead: Int, minElev: Double) = viewModelScope.launch { _passes.emit(DataState.Loading) passesProcessing?.cancelAndJoin() - settingsRepo.savePassesSettings(PassesSettings(hoursAhead, minElev)) + settingsRepo.updatePassesSettings(PassesSettings(hoursAhead, minElev)) satelliteRepo.calculatePasses(timeRef, hoursAhead, minElev) } 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 154adefa..db5d06e9 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 @@ -61,7 +61,7 @@ class RadarViewModel( val orientation = mutableStateOf(sensorSource.orientation.value) init { - if (settingsRepo.otherSettings.value.sensorState) { + if (settingsRepo.otherSettings.value.stateOfSensors) { viewModelScope.launch { sensorSource.enableSensor() sensorSource.orientation.collect { data -> @@ -117,8 +117,8 @@ class RadarViewModel( satellite, stationPos, satPass.aosTime, satPass.losTime ) } - if (settingsRepo.getRotatorEnabled()) { - val server = settingsRepo.getRotatorServer() + if (settingsRepo.getRotatorState()) { + val server = settingsRepo.getRotatorAddress() val port = settingsRepo.getRotatorPort().toInt() val azimuth = satPos.azimuth.toDegrees().round(1) val elevation = satPos.elevation.toDegrees().round(1) @@ -130,10 +130,10 @@ class RadarViewModel( private fun sendPassDataBT(satPos: SatPos) { viewModelScope.launch { - if (settingsRepo.getBTEnabled()) { - val btDevice = settingsRepo.getBTDeviceAddr() + if (settingsRepo.getBluetoothState()) { + val btDevice = settingsRepo.getBluetoothAddress() if (bluetoothReporter.isConnected()) { - val format = settingsRepo.getBTFormat() + val format = settingsRepo.getBluetoothFormat() val azimuth = satPos.azimuth.toDegrees().round(0).toInt() val elevation = satPos.elevation.toDegrees().round(0).toInt() bluetoothReporter.reportRotation(format, azimuth, elevation) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt index 21ceb7f7..237ee318 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt @@ -367,7 +367,7 @@ private fun DataCard( @Preview(showBackground = true) @Composable private fun OtherCardPreview() = MainTheme { - val values = OtherSettings(utcState = false, updateState = true, sweepState = true, sensorState = true) + val values = OtherSettings(stateOfAutoUpdate = true, stateOfSensors = true, stateOfSweep = true, stateOfUtc = false) OtherCard(settings = values, {}, {}, {}, {}) } @@ -387,7 +387,7 @@ private fun OtherCard( modifier = Modifier.fillMaxWidth() ) { Text(text = stringResource(id = R.string.other_switch_utc)) - Switch(checked = settings.utcState, onCheckedChange = { toggleUtc(it) }) + Switch(checked = settings.stateOfUtc, onCheckedChange = { toggleUtc(it) }) } Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -395,7 +395,7 @@ private fun OtherCard( modifier = Modifier.fillMaxWidth() ) { Text(text = stringResource(id = R.string.other_switch_update)) - Switch(checked = settings.updateState, onCheckedChange = { toggleUpdate(it) }) + Switch(checked = settings.stateOfAutoUpdate, onCheckedChange = { toggleUpdate(it) }) } Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -403,7 +403,7 @@ private fun OtherCard( modifier = Modifier.fillMaxWidth() ) { Text(text = stringResource(id = R.string.other_switch_sweep)) - Switch(checked = settings.sweepState, onCheckedChange = { toggleSweep(it) }) + Switch(checked = settings.stateOfSweep, onCheckedChange = { toggleSweep(it) }) } Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -411,7 +411,7 @@ private fun OtherCard( modifier = Modifier.fillMaxWidth() ) { Text(text = stringResource(id = R.string.other_switch_sensors)) - Switch(checked = settings.sensorState, onCheckedChange = { toggleSensor(it) }) + Switch(checked = settings.stateOfSensors, onCheckedChange = { toggleSensor(it) }) } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsViewModel.kt index 2d7ede83..7161ad97 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsViewModel.kt @@ -57,9 +57,9 @@ class SettingsViewModel( settingsRepo.databaseState.collect { state -> _dataSettings.value = _dataSettings.value.copy( isUpdating = false, - entriesTotal = state.entriesTotal, - radiosTotal = state.radiosTotal, - timestamp = state.timestamp + entriesTotal = state.numberOfSatellites, + radiosTotal = state.numberOfRadios, + timestamp = state.updateTimestamp ) } } @@ -69,7 +69,7 @@ class SettingsViewModel( } fun setGpsPosition() { - if (settingsRepo.setGpsPosition()) { + if (settingsRepo.setStationPositionGps()) { val messageResId = R.string.location_success _positionSettings.value = _positionSettings.value.copy(isUpdating = true, messageResId = messageResId) @@ -80,7 +80,7 @@ class SettingsViewModel( } fun setGeoPosition(latitude: Double, longitude: Double) { - if (settingsRepo.setGeoPosition(latitude, longitude)) { + if (settingsRepo.setStationPositionGeo(latitude, longitude, 0.0)) { val messageResId = R.string.location_success _positionSettings.value = _positionSettings.value.copy(messageResId = messageResId) } else { @@ -90,7 +90,7 @@ class SettingsViewModel( } fun setQthPosition(locator: String) { - if (settingsRepo.setQthPosition(locator)) { + if (settingsRepo.setStationPositionQth(locator)) { val messageResId = R.string.location_success _positionSettings.value = _positionSettings.value.copy(messageResId = messageResId) } else { @@ -125,10 +125,10 @@ class SettingsViewModel( fun clearAllData() = viewModelScope.launch { databaseRepo.clearAllData() } - fun toggleUtc(value: Boolean) = settingsRepo.toggleUtc(value) - fun toggleUpdate(value: Boolean) = settingsRepo.toggleUpdate(value) - fun toggleSweep(value: Boolean) = settingsRepo.toggleSweep(value) - fun toggleSensor(value: Boolean) = settingsRepo.toggleSensor(value) + fun toggleUtc(value: Boolean) = settingsRepo.setStateOfUtc(value) + fun toggleUpdate(value: Boolean) = settingsRepo.setStateOfAutoUpdate(value) + fun toggleSweep(value: Boolean) = settingsRepo.setStateOfSweep(value) + fun toggleSensor(value: Boolean) = settingsRepo.setStateOfSensors(value) // fun getRotatorEnabled(): Boolean = settings.getRotatorEnabled() // fun setRotatorEnabled(value: Boolean) = settings.setRotatorEnabled(value) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt index 6eeaa7e3..0b444925 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt @@ -57,11 +57,11 @@ class DatabaseRepo( jobsMap.mapValues { job -> job.value.await() }.forEach { entry -> entry.value?.let { stream -> when (val type = entry.key) { - "AMSAT", "R4UAB" -> { + "Amsat", "R4UAB" -> { // parse tle stream val satellites = importSatellites(stream) val catnums = satellites.map { it.data.catnum } - settingsRepo.saveSatType(type, catnums) + settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } @@ -70,7 +70,7 @@ class DatabaseRepo( val unzipped = ZipInputStream(stream).apply { nextEntry } val satellites = importSatellites(unzipped) val catnums = satellites.map { it.data.catnum } - settingsRepo.saveSatType(type, catnums) + settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } @@ -79,7 +79,7 @@ class DatabaseRepo( val parsed = dataParser.parseCSVStream(stream) val satellites = parsed.map { data -> SatEntry(data) } val catnums = satellites.map { it.data.catnum } - settingsRepo.saveSatType(type, catnums) + settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } } @@ -99,9 +99,9 @@ class DatabaseRepo( } private suspend fun setUpdateSuccessful(timestamp: Long) = withContext(dispatcher) { - val satellitesTotal = localSource.getEntriesTotal() - val radiosTotal = localSource.getRadiosTotal() - settingsRepo.saveDatabaseState(DatabaseState(satellitesTotal, radiosTotal, timestamp)) + val numberOfRadios = localSource.getRadiosTotal() + val numberOfSatellites = localSource.getEntriesTotal() + settingsRepo.updateDatabaseState(DatabaseState(numberOfRadios, numberOfSatellites, timestamp)) } private suspend fun importSatellites(stream: InputStream): List { diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt index c01aab8e..f893a1b4 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt @@ -48,7 +48,7 @@ class SatelliteRepo( override suspend fun getRadiosWithId(id: Int) = localStorage.getRadiosWithId(id) override suspend fun initRepository() = withContext(dispatcher) { - settingsRepo.satelliteSelection.collect { selectedIds -> + settingsRepo.selectedIds.collect { selectedIds -> _satellites.update { localStorage.getEntriesWithIds(selectedIds) } val (hoursAhead, minElevation) = settingsRepo.passesSettings.value calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt index e02903a5..3f65f2d3 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt @@ -33,7 +33,7 @@ class SelectionRepo( override fun getTypesList() = settingsRepo.satelliteSourcesMap.keys.sorted() override suspend fun getEntriesFlow() = withContext(dispatcher) { - val selectedIds = settingsRepo.satelliteSelection.value + val selectedIds = settingsRepo.selectedIds.value currentItems.value = localSource.getEntriesList().map { item -> item.copy(isSelected = item.catnum in selectedIds) } @@ -60,12 +60,12 @@ class SelectionRepo( override suspend fun saveSelection() = withContext(dispatcher) { val currentSelection = currentItems.value.filter { it.isSelected }.map { it.catnum } - settingsRepo.saveEntriesSelection(currentSelection) + settingsRepo.setSelectedIds(currentSelection) } private suspend fun List.filterByType(type: String) = withContext(dispatcher) { if (type == "All") return@withContext this@filterByType - val catnums = settingsRepo.loadSatType(type) + val catnums = settingsRepo.getSatelliteTypeIds(type) if (catnums.isEmpty()) return@withContext this@filterByType return@withContext this@filterByType.filter { item -> item.catnum in catnums } } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SettingsRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SettingsRepo.kt index e50d8ffc..799c3de4 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SettingsRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SettingsRepo.kt @@ -34,55 +34,104 @@ import java.util.concurrent.Executors import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -class SettingsRepo( - private val locationManager: LocationManager, private val preferences: SharedPreferences -) : ISettingsRepo { +class SettingsRepo(private val manager: LocationManager, private val preferences: SharedPreferences) : ISettingsRepo { - private val keyModes = "satModes" - private val keyUtcState = "utcState" - private val keyUpdateState = "updateState" - private val keySweepState = "sweepState" - private val keySensorState = "sensorState" - private val keyDataEntries = "dataEntries" - private val keyDataRadios = "dataRadios" - private val keyDataTimestamp = "dataTimestamp" - private val keyHoursAhead = "hoursAhead" - private val keyMinElevation = "minElevation" - private val keyRotator = "isRotatorEnabled" + private val keyBluetoothAddress = "bluetoothAddress" + private val keyBluetoothName = "bluetoothName" + private val keyBluetoothFormat = "bluetoothFormat" + private val keyBluetoothState = "bluetoothState" + private val keyFilterHoursAhead = "filterHoursAhead" + private val keyFilterMinElevation = "filterMinElevation" + private val keyNumberOfRadios = "numberOfRadios" + private val keyNumberOfSatellites = "numberOfSatellites" private val keyRotatorAddress = "rotatorAddress" private val keyRotatorPort = "rotatorPort" - private val keyBTEnabled = "isBTEnabled" - private val keyBTDeviceName = "BTDeviceName" - private val keyBTDeviceAddr = "BTDeviceAddr" - private val keyBTFormat = "BTFormat" - private val keyLatitude = "stationLat" - private val keyLongitude = "stationLon" - private val keyAltitude = "stationAlt" - private val keyLocator = "stationQTH" - private val keyLocTimestamp = "locTimestamp" - private val keySelection = "selection" + private val keyRotatorState = "rotatorState" + private val keySelectedIds = "selectedIds" + private val keySelectedModes = "selectedModes" + private val keyStateOfAutoUpdate = "stateOfAutoUpdate" + private val keyStateOfSensors = "stateOfSensors" + private val keyStateOfSweep = "stateOfSweep" + private val keyStateOfUtc = "stateOfUtc" + private val keyStationAltitude = "stationAltitude" + private val keyStationLatitude = "stationLatitude" + private val keyStationLongitude = "stationLongitude" + private val keyStationQth = "stationQth" + private val keyStationTimestamp = "stationTimestamp" + private val keyUpdateTimestamp = "updateTimestamp" + private val separatorComma = "," + + //region # Satellites selection settings + private val _satelliteSelection = MutableStateFlow(getSelectedIds()) + override val selectedIds: StateFlow> = _satelliteSelection + + override fun setSelectedIds(ids: List) { + val selectionString = ids.joinToString(separatorComma) + preferences.edit { putString(keySelectedIds, selectionString) } + _satelliteSelection.value = ids + } + + private fun getSelectedIds(): List { + val selectionString = preferences.getString(keySelectedIds, null) + val selectionList = selectionString?.split(separatorComma)?.map { it.toInt() } + return selectionList ?: emptyList() + } + //endregion + + //region # Passes filter settings + private val _passesSettings = MutableStateFlow(getPassesSettings()) + override val passesSettings: StateFlow = _passesSettings + + override fun getSelectedModes(): List { + val selectedModesString = preferences.getString(keySelectedModes, null) + return selectedModesString?.split(separatorComma)?.sorted() ?: emptyList() + } + + override fun setSelectedModes(modes: List) { + val selectedModes = modes.joinToString(separatorComma) + preferences.edit { putString(keySelectedModes, selectedModes) } + } + + override fun updatePassesSettings(settings: PassesSettings) = preferences.edit { + putInt(keyFilterHoursAhead, settings.filterHoursAhead) + putLong(keyFilterMinElevation, settings.filterMinElevation.toRawBits()) + _passesSettings.value = settings + } + + private fun getPassesSettings(): PassesSettings { + val hoursAhead = preferences.getInt(keyFilterHoursAhead, 24) + val minElevation = Double.fromBits(preferences.getLong(keyFilterMinElevation, 16.0.toRawBits())) + return PassesSettings(hoursAhead, minElevation) + } + //endregion //region # Station position settings - - private val _stationPosition = MutableStateFlow(loadStationPosition()) + private val _stationPosition = MutableStateFlow(getStationPosition()) + private val executor = Executors.newSingleThreadExecutor() private val providerDef = LocationManager.PASSIVE_PROVIDER private val providerGps = LocationManager.GPS_PROVIDER private val providerNet = LocationManager.NETWORK_PROVIDER - private val executor = Executors.newSingleThreadExecutor() private val timeoutSignal = CancellationSignal().apply { - setOnCancelListener { _stationPosition.value = loadStationPosition() } + setOnCancelListener { _stationPosition.value = getStationPosition() } } override val stationPosition: StateFlow = _stationPosition - override fun setGpsPosition(): Boolean { - if (!LocationManagerCompat.isLocationEnabled(locationManager)) return false + override fun setStationPositionGeo(latitude: Double, longitude: Double, altitude: Double): Boolean { + val newLongitude = if (longitude > 180.0) longitude - 180 else longitude + val locator = positionToQth(latitude, newLongitude) ?: return false + setStationPosition(latitude, newLongitude, altitude, locator) + return true + } + + override fun setStationPositionGps(): Boolean { + if (!LocationManagerCompat.isLocationEnabled(manager)) return false try { - val hasGps = LocationManagerCompat.hasProvider(locationManager, providerGps) - val hasNet = LocationManagerCompat.hasProvider(locationManager, providerNet) - val provider = if (hasGps) providerGps else if (hasNet) providerNet else providerDef + val hasProviderGps = LocationManagerCompat.hasProvider(manager, providerGps) + val hasProviderNet = LocationManagerCompat.hasProvider(manager, providerNet) + val provider = if (hasProviderGps) providerGps else if (hasProviderNet) providerNet else providerDef println("Requesting location for $provider provider") - LocationManagerCompat.getCurrentLocation(locationManager, provider, timeoutSignal, executor) { - it?.let { setGeoPosition(it.latitude, it.longitude, it.altitude) } + LocationManagerCompat.getCurrentLocation(manager, provider, timeoutSignal, executor) { + it?.let { setStationPositionGeo(it.latitude, it.longitude, it.altitude) } } } catch (exception: SecurityException) { println("No permissions were given - $exception") @@ -90,224 +139,124 @@ class SettingsRepo( return true } - override fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double): Boolean { - val newLongitude = if (longitude > 180.0) longitude - 180 else longitude - val locator = positionToQth(latitude, newLongitude) ?: return false - saveGeoPos(latitude, newLongitude, altitude, locator) - return true - } - - override fun setQthPosition(locator: String): Boolean { + override fun setStationPositionQth(locator: String): Boolean { val position = qthToPosition(locator) ?: return false - saveGeoPos(position.latitude, position.longitude, 0.0, locator) + setStationPosition(position.latitude, position.longitude, 0.0, locator) return true } - private fun saveStationPosition(stationPos: GeoPos) = preferences.edit { - putString(keyLatitude, stationPos.latitude.toString()) - putString(keyLongitude, stationPos.longitude.toString()) - putString(keyAltitude, stationPos.altitude.toString()) - putString(keyLocator, stationPos.qthLocator) - putLong(keyLocTimestamp, stationPos.timestamp) - _stationPosition.value = stationPos + private fun getStationPosition(): GeoPos { + val latitude = (preferences.getString(keyStationLatitude, null) ?: "0.0").toDouble() + val longitude = (preferences.getString(keyStationLongitude, null) ?: "0.0").toDouble() + val altitude = (preferences.getString(keyStationAltitude, null) ?: "0.0").toDouble() + val qthLocator = preferences.getString(keyStationQth, null) ?: "JJ00aa" + val timestamp = preferences.getLong(keyStationTimestamp, 0L) + return GeoPos(latitude, longitude, altitude, qthLocator, timestamp) } - private fun saveGeoPos(latitude: Double, longitude: Double, altitude: Double, locator: String) { + private fun setStationPosition(latitude: Double, longitude: Double, altitude: Double, locator: String) { val newLat = latitude.round(4) val newLon = longitude.round(4) val newAlt = altitude.round(1) val timestamp = System.currentTimeMillis() println("Received new Position($newLat, $newLon, $newAlt) & Locator $locator") - saveStationPosition(GeoPos(newLat, newLon, newAlt, locator, timestamp)) + setStationPosition(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) + private fun setStationPosition(stationPos: GeoPos) = preferences.edit { + putString(keyStationLatitude, stationPos.latitude.toString()) + putString(keyStationLongitude, stationPos.longitude.toString()) + putString(keyStationAltitude, stationPos.altitude.toString()) + putString(keyStationQth, stationPos.qthLocator) + putLong(keyStationTimestamp, stationPos.timestamp) + _stationPosition.value = stationPos } - //endregion //region # Database update settings - - private val _databaseState = MutableStateFlow(loadDatabaseState()) + private val _databaseState = MutableStateFlow(getDatabaseState()) override val databaseState: StateFlow = _databaseState - override fun saveDatabaseState(state: DatabaseState) = preferences.edit { - putInt(keyDataEntries, state.entriesTotal) - putInt(keyDataRadios, state.radiosTotal) - putLong(keyDataTimestamp, state.timestamp) + override fun getSatelliteTypeIds(type: String): List { + val typesString = preferences.getString("type$type", null) + if (typesString.isNullOrBlank()) return emptyList() + return typesString.split(separatorComma).map { it.toInt() } + } + + override fun setSatelliteTypeIds(type: String, ids: List) { + if (type == "All") return + val typesString = ids.joinToString(separatorComma) + preferences.edit { putString("type$type", typesString) } + } + + override fun updateDatabaseState(state: DatabaseState) = preferences.edit { + putInt(keyNumberOfSatellites, state.numberOfSatellites) + putInt(keyNumberOfRadios, state.numberOfRadios) + putLong(keyUpdateTimestamp, state.updateTimestamp) _databaseState.value = state } - override fun saveSatType(type: String, catnums: List) { - val stringList = catnums.map { catnum -> catnum.toString() } - preferences.edit { putStringSet("type$type", stringList.toSet()) } + private fun getDatabaseState(): DatabaseState { + val numberOfRadios = preferences.getInt(keyNumberOfRadios, 0) + val numberOfSatellites = preferences.getInt(keyNumberOfSatellites, 0) + val updateTimestamp = preferences.getLong(keyUpdateTimestamp, 0L) + return DatabaseState(numberOfRadios, numberOfSatellites, updateTimestamp) } - - 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 - - override fun saveEntriesSelection(catnums: List) = preferences.edit { - putStringSet(keySelection, catnums.map { catnum -> catnum.toString() }.toSet()) - _satelliteSelection.value = catnums - } - - private fun loadEntriesSelection(): List { - val catNums = preferences.getStringSet(keySelection, emptySet()) - return catNums?.map { catnum -> catnum.toInt() }?.sorted() ?: emptyList() - } - - //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 saveModesSelection(modes: List) { - preferences.edit { putStringSet(keyModes, modes.toSet()) } - } - - override fun loadModesSelection(): List { - return preferences.getStringSet(keyModes, null)?.toList()?.sorted() ?: emptyList() - } - - private fun loadPassesSettings(): PassesSettings { - val hoursAhead = preferences.getInt(keyHoursAhead, 24) - val minElevation = preferences.getDouble(keyMinElevation, 16.0) - return PassesSettings(hoursAhead, minElevation) - } - //endregion //region # Other settings - - private val _otherSettings = MutableStateFlow(loadOtherSettings()) + private val _otherSettings = MutableStateFlow(getOtherSettings()) override val otherSettings: StateFlow = _otherSettings - override fun toggleUtc(value: Boolean) { - preferences.edit { putBoolean(keyUtcState, value) } - _otherSettings.value = otherSettings.value.copy(utcState = value) + override fun setStateOfAutoUpdate(value: Boolean) { + preferences.edit { putBoolean(keyStateOfAutoUpdate, value) } + _otherSettings.value = otherSettings.value.copy(stateOfAutoUpdate = value) } - override fun toggleUpdate(value: Boolean) { - preferences.edit { putBoolean(keyUpdateState, value) } - _otherSettings.value = otherSettings.value.copy(updateState = value) + override fun setStateOfSensors(value: Boolean) { + preferences.edit { putBoolean(keyStateOfSensors, value) } + _otherSettings.value = otherSettings.value.copy(stateOfSensors = value) } - override fun toggleSweep(value: Boolean) { - preferences.edit { putBoolean(keySweepState, value) } - _otherSettings.value = otherSettings.value.copy(sweepState = value) + override fun setStateOfSweep(value: Boolean) { + preferences.edit { putBoolean(keyStateOfSweep, value) } + _otherSettings.value = otherSettings.value.copy(stateOfSweep = value) } - override fun toggleSensor(value: Boolean) { - preferences.edit { putBoolean(keySensorState, value) } - _otherSettings.value = otherSettings.value.copy(sensorState = value) + override fun setStateOfUtc(value: Boolean) { + preferences.edit { putBoolean(keyStateOfUtc, value) } + _otherSettings.value = otherSettings.value.copy(stateOfUtc = value) } - private fun loadOtherSettings(): OtherSettings { - val utcState = preferences.getBoolean(keyUtcState, false) - val updateState = preferences.getBoolean(keyUpdateState, true) - val sweepState = preferences.getBoolean(keySweepState, true) - val sensorState = preferences.getBoolean(keySensorState, true) - return OtherSettings(utcState, updateState, sweepState, sensorState) + private fun getOtherSettings(): OtherSettings { + val stateOfAutoUpdate = preferences.getBoolean(keyStateOfAutoUpdate, true) + val stateOfSensors = preferences.getBoolean(keyStateOfSensors, true) + val stateOfSweep = preferences.getBoolean(keyStateOfSweep, true) + val stateOfUtc = preferences.getBoolean(keyStateOfUtc, false) + return OtherSettings(stateOfAutoUpdate, stateOfSensors, stateOfSweep, stateOfUtc) } - //endregion //region # Undefined settings + override fun getBluetoothAddress(): String = preferences.getString(keyBluetoothAddress, null) ?: "00:0C:BF:13:80:5D" + override fun setBluetoothAddress(value: String) = preferences.edit { putString(keyBluetoothAddress, value) } - override fun getRotatorEnabled(): Boolean { - return preferences.getBoolean(keyRotator, false) - } + override fun getBluetoothFormat(): String = preferences.getString(keyBluetoothFormat, null) ?: "W\$AZ \$EL" + override fun setBluetoothFormat(value: String) = preferences.edit { putString(keyBluetoothFormat, value) } - override fun setRotatorEnabled(value: Boolean) { - preferences.edit { putBoolean(keyRotator, value) } - } + override fun getBluetoothName(): String = preferences.getString(keyBluetoothName, null) ?: "Default" + override fun setBluetoothName(value: String) = preferences.edit { putString(keyBluetoothName, value) } - override fun getRotatorServer(): String { - return preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1" - } + override fun getBluetoothState(): Boolean = preferences.getBoolean(keyBluetoothState, false) + override fun setBluetoothState(value: Boolean) = preferences.edit { putBoolean(keyBluetoothState, value) } - override fun setRotatorServer(value: String) { - preferences.edit { putString(keyRotatorAddress, value) } - } + override fun getRotatorAddress(): String = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1" + override fun setRotatorAddress(value: String) = preferences.edit { putString(keyRotatorAddress, value) } - override fun getRotatorPort(): String { - return preferences.getString(keyRotatorPort, null) ?: "4533" - } - - override fun setRotatorPort(value: String) { - preferences.edit { putString(keyRotatorPort, value) } - } - - override fun getBTEnabled(): Boolean { - return preferences.getBoolean(keyBTEnabled, false) - } - - override fun setBTEnabled(value: Boolean) { - preferences.edit { putBoolean(keyBTEnabled, value) } - } - - override fun getBTDeviceAddr(): String { - return preferences.getString(keyBTDeviceAddr, null) ?: "00:0C:BF:13:80:5D" - } - - override fun setBTDeviceAddr(value: String) { - preferences.edit { putString(keyBTDeviceAddr, value) } - } - - override fun getBTDeviceName(): String { - return preferences.getString(keyBTDeviceName, null) ?: "Default" - } - - override fun setBTDeviceName(value: String) { - preferences.edit { putString(keyBTDeviceName, value) } - } - - override fun getBTFormat(): String { - return preferences.getString(keyBTFormat, null) ?: "W\$AZ \$EL" - } - - override fun setBTFormat(value: String) { - preferences.edit { putString(keyBTFormat, value) } - } + override fun getRotatorPort(): String = preferences.getString(keyRotatorPort, null) ?: "4533" + override fun setRotatorPort(value: String) = preferences.edit { putString(keyRotatorPort, value) } + override fun getRotatorState(): Boolean = preferences.getBoolean(keyRotatorState, false) + override fun setRotatorState(value: Boolean) = preferences.edit { putBoolean(keyRotatorState, value) } //endregion - - private fun SharedPreferences.getDouble(key: String, default: Double): Double { - return Double.fromBits(getLong(key, default.toRawBits())) - } - - private fun SharedPreferences.Editor.putDouble(key: String, double: Double) { - putLong(key, double.toRawBits()) - } } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt b/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt index d75084e8..5a82a5d4 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt @@ -33,6 +33,7 @@ class RemoteSource( val request = Request.Builder().url(url).build() httpClient.newCall(request).execute().body?.byteStream() } catch (exception: Exception) { + println("RemoteSource fetching stream exception: $exception") null } } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/model/Settings.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/model/Settings.kt index 9de940c2..3ab535e7 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/model/Settings.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/model/Settings.kt @@ -1,12 +1,12 @@ package com.rtbishop.look4sat.domain.model -data class DatabaseState(val entriesTotal: Int, val radiosTotal: Int, val timestamp: Long) +data class DatabaseState(val numberOfRadios: Int, val numberOfSatellites: Int, val updateTimestamp: Long) -data class PassesSettings(val hoursAhead: Int, val minElevation: Double) +data class PassesSettings(val filterHoursAhead: Int, val filterMinElevation: Double) data class OtherSettings( - val utcState: Boolean, - val updateState: Boolean, - val sweepState: Boolean, - val sensorState: Boolean + val stateOfAutoUpdate: Boolean, + val stateOfSensors: Boolean, + val stateOfSweep: Boolean, + val stateOfUtc: Boolean ) diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt index efa57f4f..b146314b 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt @@ -56,93 +56,54 @@ interface ISettingsRepo { "X-Comm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv" ) - //region # Station position settings - - val stationPosition: StateFlow - - fun setGpsPosition(): Boolean - - fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double = 0.0): Boolean - - fun setQthPosition(locator: String): Boolean - - //endregion - - //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) - + //region # Satellites selection settings + val selectedIds: StateFlow> + fun setSelectedIds(ids: List) //endregion //region # Passes filter settings - val passesSettings: StateFlow + fun getSelectedModes(): List + fun setSelectedModes(modes: List) + fun updatePassesSettings(settings: PassesSettings) + //endregion - fun savePassesSettings(settings: PassesSettings) - - fun saveModesSelection(modes: List) - - fun loadModesSelection(): List + //region # Station position settings + val stationPosition: StateFlow + fun setStationPositionGeo(latitude: Double, longitude: Double, altitude: Double): Boolean + fun setStationPositionGps(): Boolean + fun setStationPositionQth(locator: String): Boolean + //endregion + //region # Database update settings + val databaseState: StateFlow + fun getSatelliteTypeIds(type: String): List + fun setSatelliteTypeIds(type: String, ids: List) + fun updateDatabaseState(state: DatabaseState) //endregion //region # Other settings - val otherSettings: StateFlow - - fun toggleUtc(value: Boolean) - - fun toggleUpdate(value: Boolean) - - fun toggleSweep(value: Boolean) - - fun toggleSensor(value: Boolean) - + fun setStateOfAutoUpdate(value: Boolean) + fun setStateOfSensors(value: Boolean) + fun setStateOfSweep(value: Boolean) + fun setStateOfUtc(value: Boolean) //endregion //region # Undefined settings - - fun getRotatorEnabled(): Boolean - - fun setRotatorEnabled(value: Boolean) - - fun getRotatorServer(): String - - fun setRotatorServer(value: String) - + fun getBluetoothAddress(): String + fun setBluetoothAddress(value: String) + fun getBluetoothFormat(): String + fun setBluetoothFormat(value: String) + fun getBluetoothName(): String + fun setBluetoothName(value: String) + fun getBluetoothState(): Boolean + fun setBluetoothState(value: Boolean) + fun getRotatorAddress(): String + fun setRotatorAddress(value: String) fun getRotatorPort(): String - fun setRotatorPort(value: String) - - fun getBTEnabled(): Boolean - - fun setBTEnabled(value: Boolean) - - fun getBTDeviceAddr(): String - - fun setBTDeviceAddr(value: String) - - fun getBTDeviceName(): String - - fun setBTDeviceName(value: String) - - fun getBTFormat(): String - - fun setBTFormat(value: String) - + fun getRotatorState(): Boolean + fun setRotatorState(value: Boolean) //endregion }