diff --git a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt
index 7ef73f5c..e6fa2a15 100644
--- a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt
@@ -19,7 +19,7 @@ package com.rtbishop.look4sat
import android.app.Application
import com.rtbishop.look4sat.domain.IDataRepository
-import com.rtbishop.look4sat.domain.ISettingsSource
+import com.rtbishop.look4sat.domain.ISettingsRepository
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber
import java.text.SimpleDateFormat
@@ -33,7 +33,7 @@ class MainApplication : Application() {
lateinit var dataRepository: IDataRepository
@Inject
- lateinit var settingsSource: ISettingsSource
+ lateinit var settingsRepository: ISettingsRepository
override fun onCreate() {
super.onCreate()
@@ -44,8 +44,8 @@ class MainApplication : Application() {
}
private fun checkAutoUpdate() {
- if (settingsSource.isUpdateEnabled()) {
- val timeDelta = System.currentTimeMillis() - settingsSource.getLastUpdateTime()
+ if (settingsRepository.isUpdateEnabled()) {
+ val timeDelta = System.currentTimeMillis() - settingsRepository.getLastUpdateTime()
if (timeDelta > 172800000) { // 48 hours in ms
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
Timber.d("Started periodic data update on ${sdf.format(Date())}")
diff --git a/app/src/main/java/com/rtbishop/look4sat/MainModule.kt b/app/src/main/java/com/rtbishop/look4sat/MainModule.kt
index 553d627f..5d9729be 100644
--- a/app/src/main/java/com/rtbishop/look4sat/MainModule.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/MainModule.kt
@@ -25,6 +25,7 @@ import android.location.LocationManager
import androidx.room.Room
import com.rtbishop.look4sat.data.DataParser
import com.rtbishop.look4sat.data.DataRepository
+import com.rtbishop.look4sat.data.SatelliteRepository
import com.rtbishop.look4sat.domain.*
import com.rtbishop.look4sat.framework.*
import com.rtbishop.look4sat.framework.data.*
@@ -55,12 +56,14 @@ object MainModule {
@Provides
@Singleton
- fun provideNetworkReporter(): NetworkReporter = NetworkReporter(CoroutineScope(Dispatchers.IO))
+ fun provideNetworkReporter(): NetworkReporter {
+ return NetworkReporter(CoroutineScope(Dispatchers.IO))
+ }
@Provides
@Singleton
fun provideDataRepository(
- @ApplicationContext context: Context, settings: ISettingsSource
+ @ApplicationContext context: Context, settings: ISettingsRepository
): IDataRepository {
val db = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb")
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
@@ -75,28 +78,23 @@ object MainModule {
@Provides
@Singleton
- fun provideLocationSource(
- @ApplicationContext context: Context, settings: ISettingsSource
- ): ILocationSource {
- val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
- return LocationSource(manager, settings)
- }
-
- @Provides
- @Singleton
- fun provideOrientationSource(@ApplicationContext context: Context): OrientationSource {
+ fun provideSensorRepository(@ApplicationContext context: Context): ISensorRepository {
val manager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = manager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
- return OrientationSource(manager, sensor)
+ return SensorRepository(manager, sensor)
}
@Provides
@Singleton
- fun provideSatelliteManager(): ISatelliteManager = SatelliteManager(Dispatchers.Default)
+ fun provideSatelliteRepository(): ISatelliteRepository {
+ return SatelliteRepository(Dispatchers.Default)
+ }
@Provides
@Singleton
- fun provideSettingsSource(@ApplicationContext context: Context): ISettingsSource {
- return SettingsSource(context.getSharedPreferences("default", Context.MODE_PRIVATE))
+ fun provideSettingsRepository(@ApplicationContext context: Context): ISettingsRepository {
+ val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+ val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE)
+ return SettingsRepository(manager, preferences)
}
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/LocationSource.kt b/app/src/main/java/com/rtbishop/look4sat/framework/LocationSource.kt
deleted file mode 100644
index cf08b955..00000000
--- a/app/src/main/java/com/rtbishop/look4sat/framework/LocationSource.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.rtbishop.look4sat.framework
-
-import android.location.Criteria
-import android.location.LocationManager
-import androidx.core.location.LocationManagerCompat
-import androidx.core.os.CancellationSignal
-import com.rtbishop.look4sat.domain.ILocationSource
-import com.rtbishop.look4sat.domain.ISettingsSource
-import com.rtbishop.look4sat.model.GeoPos
-import com.rtbishop.look4sat.utility.QthConverter
-import com.rtbishop.look4sat.utility.round
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import timber.log.Timber
-import java.util.concurrent.Executors
-
-class LocationSource(
- private val manager: LocationManager,
- private val settings: ISettingsSource,
-) : ILocationSource {
-
- private val _stationPosition = MutableStateFlow(settings.loadStationPosition())
- private val defaultProvider = LocationManager.PASSIVE_PROVIDER
- private val executor = Executors.newSingleThreadExecutor()
- private val timeoutSignal = CancellationSignal().apply {
- setOnCancelListener { _stationPosition.value = _stationPosition.value }
- }
- override val stationPosition: StateFlow = _stationPosition
-
- override fun setGpsPosition(): Boolean {
- if (!LocationManagerCompat.isLocationEnabled(manager)) return false
- try {
- val criteria = Criteria().apply { isCostAllowed = true }
- val provider = manager.getBestProvider(criteria, true) ?: defaultProvider
- Timber.d("Requesting location for $provider provider")
- LocationManagerCompat.getCurrentLocation(manager, provider, timeoutSignal, executor) {
- it?.let { setGeoPosition(it.latitude, it.longitude, it.altitude) }
- }
- } catch (exception: SecurityException) {
- Timber.d("No permissions were given")
- }
- return true
- }
-
- override fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double): Boolean {
- val newLongitude = if (longitude > 180.0) longitude - 180 else longitude
- val locator = QthConverter.positionToQth(latitude, newLongitude) ?: return false
- saveGeoPos(latitude, newLongitude, altitude, locator)
- return true
- }
-
- override fun setQthPosition(locator: String): Boolean {
- val position = QthConverter.qthToPosition(locator) ?: return false
- saveGeoPos(position.latitude, position.longitude, 0.0, locator)
- return true
- }
-
- private fun saveGeoPos(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()
- Timber.d("Received new Position($newLat, $newLon, $newAlt) & Locator $locator")
- _stationPosition.value = GeoPos(newLat, newLon, newAlt, locator, timestamp)
- settings.saveStationPosition(stationPosition.value)
- }
-}
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/OrientationSource.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SensorRepository.kt
similarity index 84%
rename from app/src/main/java/com/rtbishop/look4sat/framework/OrientationSource.kt
rename to app/src/main/java/com/rtbishop/look4sat/framework/SensorRepository.kt
index 5d46789f..08c43c39 100644
--- a/app/src/main/java/com/rtbishop/look4sat/framework/OrientationSource.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/SensorRepository.kt
@@ -21,27 +21,27 @@ import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
+import com.rtbishop.look4sat.domain.ISensorRepository
import com.rtbishop.look4sat.domain.RAD2DEG
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlin.math.round
-class OrientationSource(
- private val manager: SensorManager, private val sensor: Sensor?
-) : SensorEventListener {
+class SensorRepository(private val manager: SensorManager, private val sensor: Sensor?) :
+ SensorEventListener, ISensorRepository {
private val rotationMatrix = FloatArray(9)
private val orientationValues = FloatArray(3)
private var sensorAccuracy: Int = SensorManager.SENSOR_STATUS_UNRELIABLE
private val _orientation = MutableStateFlow(Pair(0f, 0f))
- val orientation: StateFlow> = _orientation
+ override val orientation: StateFlow> = _orientation
- fun startListening() = sensor?.let {
- manager.registerListener(this, it, 16000)
+ override fun enableSensor() {
+ sensor?.let { manager.registerListener(this, it, 16000) }
}
- fun stopListening() = manager.unregisterListener(this)
+ override fun disableSensor() = manager.unregisterListener(this)
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
sensorAccuracy = accuracy
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepository.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepository.kt
new file mode 100644
index 00000000..c41b4e5c
--- /dev/null
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsRepository.kt
@@ -0,0 +1,277 @@
+/*
+ * Look4Sat. Amateur radio satellite tracker and pass predictor.
+ * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.rtbishop.look4sat.framework
+
+import android.content.SharedPreferences
+import android.location.Criteria
+import android.location.LocationManager
+import androidx.core.content.edit
+import androidx.core.location.LocationManagerCompat
+import androidx.core.os.CancellationSignal
+import com.rtbishop.look4sat.domain.ISettingsRepository
+import com.rtbishop.look4sat.model.GeoPos
+import com.rtbishop.look4sat.utility.QthConverter
+import com.rtbishop.look4sat.utility.round
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import timber.log.Timber
+import java.util.concurrent.Executors
+
+class SettingsRepository(
+ private val manager: LocationManager, private val preferences: SharedPreferences
+) : ISettingsRepository {
+
+ private val keyModes = "satModes"
+ private val keyCompass = "compass"
+ private val keyRadarSweep = "radarSweep"
+ private val keyTimeUTC = "timeUTC"
+ private val keyLastUpdateTime = "lastUpdateTime"
+ private val keyAutoUpdateEnabled = "autoUpdateEnabled"
+ private val keyHoursAhead = "hoursAhead"
+ private val keyMinElevation = "minElevation"
+ private val keyRotator = "isRotatorEnabled"
+ 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"
+
+ //region # Station position settings
+
+ private val _stationPosition = MutableStateFlow(loadStationPosition())
+ private val defaultProvider = LocationManager.PASSIVE_PROVIDER
+ private val executor = Executors.newSingleThreadExecutor()
+ private val timeoutSignal = CancellationSignal().apply {
+ setOnCancelListener { _stationPosition.value = loadStationPosition() }
+ }
+ override val stationPosition: StateFlow = _stationPosition
+
+ override fun setGpsPosition(): Boolean {
+ if (!LocationManagerCompat.isLocationEnabled(manager)) return false
+ try {
+ val criteria = Criteria().apply { isCostAllowed = true }
+ val provider = manager.getBestProvider(criteria, true) ?: defaultProvider
+ Timber.d("Requesting location for $provider provider")
+ LocationManagerCompat.getCurrentLocation(manager, provider, timeoutSignal, executor) {
+ it?.let { setGeoPosition(it.latitude, it.longitude, it.altitude) }
+ }
+ } catch (exception: SecurityException) {
+ Timber.d("No permissions were given")
+ }
+ return true
+ }
+
+ override fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double): Boolean {
+ val newLongitude = if (longitude > 180.0) longitude - 180 else longitude
+ val locator = QthConverter.positionToQth(latitude, newLongitude) ?: return false
+ saveGeoPos(latitude, newLongitude, altitude, locator)
+ return true
+ }
+
+ override fun setQthPosition(locator: String): Boolean {
+ val position = QthConverter.qthToPosition(locator) ?: return false
+ saveGeoPos(position.latitude, position.longitude, 0.0, locator)
+ 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())
+ putString(keyAltitude, stationPos.altitude.toString())
+ putString(keyLocator, stationPos.qthLocator)
+ putLong(keyLocTimestamp, stationPos.timestamp)
+ _stationPosition.value = stationPos
+ }
+
+ private fun saveGeoPos(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()
+ Timber.d("Received new Position($newLat, $newLon, $newAlt) & Locator $locator")
+ saveStationPosition(GeoPos(newLat, newLon, newAlt, locator, timestamp))
+ }
+
+ //endregion
+
+ override fun saveEntriesSelection(catnums: List) {
+ val stringList = catnums.map { catnum -> catnum.toString() }
+ preferences.edit { putStringSet(keySelection, stringList.toSet()) }
+ }
+
+ override fun loadEntriesSelection(): List {
+ val catnums =
+ preferences.getStringSet(keySelection, emptySet())?.map { catnum -> catnum.toInt() }
+ return catnums?.sorted() ?: emptyList()
+ }
+
+ 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()
+ }
+
+ override fun getHoursAhead(): Int {
+ return preferences.getInt(keyHoursAhead, 24)
+ }
+
+ override fun setHoursAhead(hoursAhead: Int) {
+ preferences.edit { putInt(keyHoursAhead, hoursAhead) }
+ }
+
+ override fun getMinElevation(): Double {
+ return preferences.getDouble(keyMinElevation, 16.0)
+ }
+
+ override fun setMinElevation(minElevation: Double) {
+ preferences.edit { putDouble(keyMinElevation, minElevation) }
+ }
+
+ override fun isUtcEnabled(): Boolean {
+ return preferences.getBoolean(keyTimeUTC, false)
+ }
+
+ override fun setUtcState(value: Boolean) {
+ preferences.edit { putBoolean(keyTimeUTC, value) }
+ }
+
+ override fun getLastUpdateTime(): Long {
+ return preferences.getLong(keyLastUpdateTime, 0L)
+ }
+
+ override fun setLastUpdateTime(updateTime: Long) {
+ preferences.edit { putLong(keyLastUpdateTime, updateTime) }
+ }
+
+ override fun isUpdateEnabled(): Boolean {
+ return preferences.getBoolean(keyAutoUpdateEnabled, true)
+ }
+
+ override fun setUpdateState(value: Boolean) {
+ preferences.edit { putBoolean(keyAutoUpdateEnabled, value) }
+ }
+
+ override fun isSensorEnabled(): Boolean {
+ return preferences.getBoolean(keyCompass, true)
+ }
+
+ override fun setSensorState(value: Boolean) {
+ preferences.edit { putBoolean(keyCompass, value) }
+ }
+
+ override fun isSweepEnabled(): Boolean {
+ return preferences.getBoolean(keyRadarSweep, true)
+ }
+
+ override fun setSweepState(value: Boolean) {
+ preferences.edit { putBoolean(keyRadarSweep, value) }
+ }
+
+ override fun saveModesSelection(modes: List) {
+ preferences.edit { putStringSet(keyModes, modes.toSet()) }
+ }
+
+ override fun loadModesSelection(): List {
+ return preferences.getStringSet(keyModes, null)?.toList()?.sorted() ?: emptyList()
+ }
+
+ override fun getRotatorEnabled(): Boolean {
+ return preferences.getBoolean(keyRotator, false)
+ }
+
+ override fun setRotatorEnabled(value: Boolean) {
+ preferences.edit { putBoolean(keyRotator, value) }
+ }
+
+ override fun getRotatorServer(): String {
+ return preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
+ }
+
+ override fun setRotatorServer(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) }
+ }
+
+ 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/app/src/main/java/com/rtbishop/look4sat/framework/SettingsSource.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsSource.kt
deleted file mode 100644
index b91d96a8..00000000
--- a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsSource.kt
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.rtbishop.look4sat.framework
-
-import android.content.SharedPreferences
-import androidx.core.content.edit
-import com.rtbishop.look4sat.domain.ISettingsSource
-import com.rtbishop.look4sat.model.GeoPos
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.onCompletion
-
-class SettingsSource(private val prefs: SharedPreferences) : ISettingsSource {
-
- companion object {
- const val keyModes = "satModes"
- const val keyCompass = "compass"
- const val keyRadarSweep = "radarSweep"
- const val keyTimeUTC = "timeUTC"
- const val keyLastUpdateTime = "lastUpdateTime"
- const val keyAutoUpdateEnabled = "autoUpdateEnabled"
- const val keyHoursAhead = "hoursAhead"
- const val keyMinElevation = "minElevation"
- const val keyRotator = "isRotatorEnabled"
- const val keyRotatorAddress = "rotatorAddress"
- const val keyRotatorPort = "rotatorPort"
- const val keyBTEnabled = "isBTEnabled"
- const val keyBTDeviceName = "BTDeviceName"
- const val keyBTDeviceAddr = "BTDeviceAddr"
- const val keyBTFormat = "BTFormat"
- const val keyLatitude = "stationLat"
- const val keyLongitude = "stationLon"
- const val keyAltitude = "stationAlt"
- const val keyLocator = "stationQTH"
- const val keyLocTimestamp = "locTimestamp"
- const val keySelection = "selection"
- }
-
- override fun loadStationPosition(): GeoPos {
- val latitude = (prefs.getString(keyLatitude, null) ?: "0.0").toDouble()
- val longitude = (prefs.getString(keyLongitude, null) ?: "0.0").toDouble()
- val altitude = (prefs.getString(keyAltitude, null) ?: "0.0").toDouble()
- val qthLocator = prefs.getString(keyLocator, null) ?: "null"
- val timestamp = prefs.getLong(keyLocTimestamp, 0L)
- return GeoPos(latitude, longitude, altitude, qthLocator, timestamp)
- }
-
- override fun saveStationPosition(stationPos: GeoPos) = prefs.edit {
- putString(keyLatitude, stationPos.latitude.toString())
- putString(keyLongitude, stationPos.longitude.toString())
- putString(keyAltitude, stationPos.altitude.toString())
- putString(keyLocator, stationPos.qthLocator)
- putLong(keyLocTimestamp, stationPos.timestamp)
- }
-
- override fun saveEntriesSelection(catnums: List) {
- val stringList = catnums.map { catnum -> catnum.toString() }
- prefs.edit { putStringSet(keySelection, stringList.toSet()) }
- }
-
- override fun loadEntriesSelection(): List {
- val catnums = prefs.getStringSet(keySelection, emptySet())?.map { catnum -> catnum.toInt() }
- return catnums?.sorted() ?: emptyList()
- }
-
- override fun saveSatType(type: String, catnums: List) {
- val stringList = catnums.map { catnum -> catnum.toString() }
- prefs.edit { putStringSet("type$type", stringList.toSet()) }
- }
-
- override fun loadSatType(type: String): List {
- val catnums = prefs.getStringSet("type$type", emptySet())?.map { catnum -> catnum.toInt() }
- return catnums ?: emptyList()
- }
-
- override fun getHoursAhead(): Int {
- return prefs.getInt(keyHoursAhead, 24)
- }
-
- override fun setHoursAhead(hoursAhead: Int) {
- prefs.edit { putInt(keyHoursAhead, hoursAhead) }
- }
-
- override fun getMinElevation(): Double {
- return prefs.getDouble(keyMinElevation, 16.0)
- }
-
- override fun setMinElevation(minElevation: Double) {
- prefs.edit { putDouble(keyMinElevation, minElevation) }
- }
-
- override fun isUtcEnabled(): Boolean {
- return prefs.getBoolean(keyTimeUTC, false)
- }
-
- override fun setUtcState(value: Boolean) {
- prefs.edit { putBoolean(keyTimeUTC, value) }
- }
-
- override fun getLastUpdateTime(): Long {
- return prefs.getLong(keyLastUpdateTime, 0L)
- }
-
- override fun setLastUpdateTime(updateTime: Long) {
- prefs.edit { putLong(keyLastUpdateTime, updateTime) }
- }
-
- override fun isUpdateEnabled(): Boolean {
- return prefs.getBoolean(keyAutoUpdateEnabled, true)
- }
-
- override fun setUpdateState(value: Boolean) {
- prefs.edit { putBoolean(keyAutoUpdateEnabled, value) }
- }
-
- override fun isSensorEnabled(): Boolean {
- return prefs.getBoolean(keyCompass, true)
- }
-
- override fun setSensorState(value: Boolean) {
- prefs.edit { putBoolean(keyCompass, value) }
- }
-
- override fun isSweepEnabled(): Boolean {
- return prefs.getBoolean(keyRadarSweep, true)
- }
-
- override fun setSweepState(value: Boolean) {
- prefs.edit { putBoolean(keyRadarSweep, value) }
- }
-
- override fun saveModesSelection(modes: List) {
- prefs.edit { putStringSet(keyModes, modes.toSet()) }
- }
-
- override fun loadModesSelection(): List {
- return prefs.getStringSet(keyModes, null)?.toList()?.sorted() ?: emptyList()
- }
-
- override fun getRotatorEnabled(): Boolean {
- return prefs.getBoolean(keyRotator, false)
- }
-
- override fun setRotatorEnabled(value: Boolean) {
- prefs.edit { putBoolean(keyRotator, value) }
- }
-
- override fun getRotatorServer(): String {
- return prefs.getString(keyRotatorAddress, null) ?: "127.0.0.1"
- }
-
- override fun setRotatorServer(value: String) {
- prefs.edit { putString(keyRotatorAddress, value) }
- }
-
- override fun getRotatorPort(): String {
- return prefs.getString(keyRotatorPort, null) ?: "4533"
- }
-
- override fun setRotatorPort(value: String) {
- prefs.edit { putString(keyRotatorPort, value) }
- }
-
- override fun getBTEnabled(): Boolean {
- return prefs.getBoolean(keyBTEnabled, false)
- }
-
- override fun setBTEnabled(value: Boolean) {
- prefs.edit { putBoolean(keyBTEnabled, value) }
- }
-
- override fun getBTDeviceAddr(): String {
- return prefs.getString(keyBTDeviceAddr, null) ?: "00:0C:BF:13:80:5D"
- }
-
- override fun setBTDeviceAddr(value: String) {
- prefs.edit { putString(keyBTDeviceAddr, value) }
- }
-
- override fun getBTDeviceName(): String {
- return prefs.getString(keyBTDeviceName, null) ?: "Default"
- }
-
- override fun setBTDeviceName(value: String) {
- prefs.edit { putString(keyBTDeviceName, value) }
- }
-
- override fun getBTFormat(): String {
- return prefs.getString(keyBTFormat, null) ?: "W\$AZ \$EL"
- }
-
- override fun setBTFormat(value: String) {
- prefs.edit { putString(keyBTFormat, value) }
- }
-
- 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())
- }
-
- inline fun SharedPreferences.observeKey(key: String, default: T): Flow {
- val flow = MutableStateFlow(getItem(key, default))
- val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, k ->
- if (key == k) flow.value = getItem(key, default)
- }
- registerOnSharedPreferenceChangeListener(listener)
- return flow.onCompletion { unregisterOnSharedPreferenceChangeListener(listener) }
- }
-
- inline fun SharedPreferences.getItem(key: String, default: T): T {
- return when (default) {
- is Boolean -> getBoolean(key, default) as T
- is Int -> getInt(key, default) as T
- is Long -> getLong(key, default) as T
- is Float -> getFloat(key, default) as T
- is String -> getString(key, default) as T
- else -> throw IllegalArgumentException("Could not handle ${T::class.java.name}")
- }
- }
-}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entries/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entries/EntriesViewModel.kt
index 817597f5..971195c7 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/entries/EntriesViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entries/EntriesViewModel.kt
@@ -20,11 +20,9 @@ package com.rtbishop.look4sat.presentation.entries
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.IDataRepository
-import com.rtbishop.look4sat.domain.ILocationSource
-import com.rtbishop.look4sat.domain.ISatelliteManager
-import com.rtbishop.look4sat.domain.ISettingsSource
+import com.rtbishop.look4sat.domain.ISatelliteRepository
+import com.rtbishop.look4sat.domain.ISettingsRepository
import com.rtbishop.look4sat.model.DataState
-import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatItem
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,10 +35,9 @@ import javax.inject.Inject
@OptIn(ExperimentalCoroutinesApi::class)
@HiltViewModel
class EntriesViewModel @Inject constructor(
- private val satelliteManager: ISatelliteManager,
- private val repository: IDataRepository,
- private val settings: ISettingsSource,
- private val locationSource: ILocationSource
+ private val dataRepository: IDataRepository,
+ private val satelliteRepository: ISatelliteRepository,
+ private val settingsRepository: ISettingsRepository
) : ViewModel() {
private val satType = MutableStateFlow("All")
@@ -53,12 +50,12 @@ class EntriesViewModel @Inject constructor(
itemsWithType.map { items -> filterByQuery(items, query) }
}
val satData = itemsWithQuery.map { items -> DataState.Success(items) }
- val satTypes: List = settings.sourcesMap.keys.sorted()
+ val satTypes = dataRepository.getSatelliteTypes()
init {
viewModelScope.launch {
delay(250)
- itemsFromRepo.value = loadEntriesWithSelection()
+ itemsFromRepo.value = dataRepository.getEntriesWithSelection()
}
}
@@ -78,15 +75,14 @@ class EntriesViewModel @Inject constructor(
fun saveSelection() = viewModelScope.launch {
val newSelection = itemsFromRepo.value.filter { it.isSelected }.map { it.catnum }
- settings.saveEntriesSelection(newSelection)
- val selectedIds = settings.loadEntriesSelection()
- val satellites = repository.getEntriesWithIds(selectedIds)
- val stationPos = locationSource.stationPosition.value
- val geoPos = GeoPos(stationPos.latitude, stationPos.longitude)
+ settingsRepository.saveEntriesSelection(newSelection)
+ val selectedIds = settingsRepository.loadEntriesSelection()
+ val satellites = dataRepository.getEntriesWithIds(selectedIds)
+ val stationPos = settingsRepository.stationPosition.value
val timeRef = System.currentTimeMillis()
- val hoursAhead = settings.getHoursAhead()
- val minElev = settings.getMinElevation()
- satelliteManager.calculatePasses(satellites, geoPos, timeRef, hoursAhead, minElev)
+ val hoursAhead = settingsRepository.getHoursAhead()
+ val minElev = settingsRepository.getMinElevation()
+ satelliteRepository.calculatePasses(satellites, stationPos, timeRef, hoursAhead, minElev)
}
fun updateSelection(catNums: List, isSelected: Boolean) {
@@ -99,14 +95,9 @@ class EntriesViewModel @Inject constructor(
}
}
- private suspend fun loadEntriesWithSelection(): List {
- val selectedIds = settings.loadEntriesSelection()
- return repository.getEntriesWithModes().onEach { it.isSelected = it.catnum in selectedIds }
- }
-
private fun filterByType(items: List, type: String): List {
if (type == "All") return items
- val catnums = settings.loadSatType(type)
+ val catnums = settingsRepository.loadSatType(type)
if (catnums.isEmpty()) return items
return items.filter { item -> item.catnum in catnums }
}
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 b6136e3a..aefcc08f 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
@@ -19,7 +19,10 @@ package com.rtbishop.look4sat.presentation.map
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.rtbishop.look4sat.domain.*
+import com.rtbishop.look4sat.domain.IDataRepository
+import com.rtbishop.look4sat.domain.ISatelliteRepository
+import com.rtbishop.look4sat.domain.ISettingsRepository
+import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPos
import com.rtbishop.look4sat.utility.QthConverter
@@ -38,15 +41,14 @@ import kotlin.math.min
@HiltViewModel
class MapViewModel @Inject constructor(
- private val repository: IDataRepository,
- private val satelliteManager: ISatelliteManager,
- private val settings: ISettingsSource,
- private val locationSource: ILocationSource
+ private val dataRepository: IDataRepository,
+ private val satelliteRepository: ISatelliteRepository,
+ private val settingsRepository: ISettingsRepository
) : ViewModel() {
- private val stationPosNew = locationSource.stationPosition.value
+ private val stationPosNew = settingsRepository.stationPosition.value
private val stationPosition = GeoPos(stationPosNew.latitude, stationPosNew.longitude)
- private var allPasses = satelliteManager.getPasses()
+ private var allPasses = satelliteRepository.getPasses()
private var allSatellites = listOf()
private var dataUpdateJob: Job? = null
private var dataUpdateRate = 1000L
@@ -85,8 +87,8 @@ class MapViewModel @Inject constructor(
fun selectDefaultSatellite(catnum: Int) {
viewModelScope.launch {
- val selectedIds = settings.loadEntriesSelection()
- repository.getEntriesWithIds(selectedIds).also { satellites ->
+ val selectedIds = settingsRepository.loadEntriesSelection()
+ dataRepository.getEntriesWithIds(selectedIds).also { satellites ->
if (satellites.isNotEmpty()) {
allSatellites = satellites
if (catnum == -1) {
@@ -123,7 +125,7 @@ class MapViewModel @Inject constructor(
val currentTrack = mutableListOf()
val endDate = Date(date.time + (satellite.data.orbitalPeriod * 2.4 * 60000L).toLong())
var oldLongitude = 0.0
- satelliteManager.getTrack(satellite, pos, date.time, endDate.time).forEach { satPos ->
+ satelliteRepository.getTrack(satellite, pos, date.time, endDate.time).forEach { satPos ->
val osmLat = clipLat(satPos.latitude.toDegrees())
val osmLon = clipLon(satPos.longitude.toDegrees())
val currentPosition = GeoPos(osmLat, osmLon)
@@ -150,7 +152,7 @@ class MapViewModel @Inject constructor(
private suspend fun getPositions(satellites: List, pos: GeoPos, date: Date) {
val positions = mutableMapOf()
satellites.forEach { satellite ->
- val satPos = satelliteManager.getPosition(satellite, pos, date.time)
+ val satPos = satelliteRepository.getPosition(satellite, pos, date.time)
val osmLat = clipLat(satPos.latitude.toDegrees())
val osmLon = clipLon(satPos.longitude.toDegrees())
positions[satellite] = GeoPos(osmLat, osmLon)
@@ -159,7 +161,7 @@ class MapViewModel @Inject constructor(
}
private suspend fun getSatFootprint(satellite: Satellite, pos: GeoPos, date: Date) {
- val satPos = satelliteManager.getPosition(satellite, pos, date.time)
+ val satPos = satelliteRepository.getPosition(satellite, pos, date.time)
_footprint.emit(satPos)
}
@@ -177,7 +179,7 @@ class MapViewModel @Inject constructor(
}
}
}
- val satPos = satelliteManager.getPosition(sat, pos, date.time)
+ val satPos = satelliteRepository.getPosition(sat, pos, date.time)
val azimuth = satPos.azimuth.toDegrees()
val elevation = satPos.elevation.toDegrees()
val osmLat = clipLat(satPos.latitude.toDegrees())
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 2de6b221..a27d5e38 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
@@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.*
import androidx.hilt.navigation.compose.hiltViewModel
import com.rtbishop.look4sat.R
-import com.rtbishop.look4sat.domain.NearEarthSat
+import com.rtbishop.look4sat.domain.NearEarthSatellite
import com.rtbishop.look4sat.model.DataState
import com.rtbishop.look4sat.model.OrbitalData
import com.rtbishop.look4sat.model.SatPass
@@ -100,7 +100,7 @@ private fun PassPreview() {
val data = OrbitalData(
"Satellite", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 45000, 0.0
)
- val satellite = NearEarthSat(data)
+ val satellite = NearEarthSatellite(data)
val pass = SatPass(1L, 25.0, 10L, 75.0, 850, 45.0, satellite, 0.5f)
MainTheme { Pass(pass = pass, { _,_ -> }) }
}
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 dda0663d..4df8c25a 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
@@ -20,11 +20,9 @@ package com.rtbishop.look4sat.presentation.passes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.IDataRepository
-import com.rtbishop.look4sat.domain.ILocationSource
-import com.rtbishop.look4sat.domain.ISatelliteManager
-import com.rtbishop.look4sat.domain.ISettingsSource
+import com.rtbishop.look4sat.domain.ISatelliteRepository
+import com.rtbishop.look4sat.domain.ISettingsRepository
import com.rtbishop.look4sat.model.DataState
-import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPass
import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -35,10 +33,9 @@ import javax.inject.Inject
@HiltViewModel
class PassesViewModel @Inject constructor(
- private val satelliteManager: ISatelliteManager,
- private val repository: IDataRepository,
- private val settings: ISettingsSource,
- private val locationSource: ILocationSource
+ private val dataRepository: IDataRepository,
+ private val satelliteRepository: ISatelliteRepository,
+ private val settingsRepository: ISettingsRepository
) : ViewModel() {
private val _passes = MutableStateFlow>>(DataState.Loading)
@@ -48,18 +45,18 @@ class PassesViewModel @Inject constructor(
val passes: StateFlow>> = _passes
val timerText: StateFlow?> = _timerText
- fun getHoursAhead() = settings.getHoursAhead()
+ fun getHoursAhead() = settingsRepository.getHoursAhead()
- fun getMinElevation() = settings.getMinElevation()
+ fun getMinElevation() = settingsRepository.getMinElevation()
init {
viewModelScope.launch {
- satelliteManager.calculatedPasses.collect { passes ->
+ satelliteRepository.calculatedPasses.collect { passes ->
passesProcessing?.cancelAndJoin()
passesProcessing = viewModelScope.launch {
while (isActive) {
val timeNow = System.currentTimeMillis()
- val newPasses = satelliteManager.processPasses(passes, timeNow)
+ val newPasses = satelliteRepository.processPasses(passes, timeNow)
if (newPasses.isNotEmpty()) {
try {
@@ -86,18 +83,18 @@ class PassesViewModel @Inject constructor(
}
}
viewModelScope.launch {
- repository.updateState.collect { updateState ->
+ dataRepository.updateState.collect { updateState ->
if (updateState is DataState.Success) calculatePasses()
}
}
calculatePasses()
}
- fun shouldUseUTC() = settings.isUtcEnabled()
+ fun shouldUseUTC() = settingsRepository.isUtcEnabled()
fun calculatePasses(
hoursAhead: Int = 1,
- minElevation: Double = settings.getMinElevation(),
+ minElevation: Double = settingsRepository.getMinElevation(),
timeRef: Long = System.currentTimeMillis(),
selection: List? = null
) {
@@ -105,15 +102,14 @@ class PassesViewModel @Inject constructor(
_passes.emit(DataState.Loading)
// _timerText.postValue(timerDefaultText)
passesProcessing?.cancelAndJoin()
- selection?.let { items -> settings.saveEntriesSelection(items) }
- settings.setHoursAhead(hoursAhead)
- settings.setMinElevation(minElevation)
- val stationPos = locationSource.stationPosition.value
- val geoPos = GeoPos(stationPos.latitude, stationPos.longitude)
- val selectedIds = settings.loadEntriesSelection()
- val satellites = repository.getEntriesWithIds(selectedIds)
- satelliteManager.calculatePasses(
- satellites, geoPos, timeRef, hoursAhead, minElevation
+ selection?.let { items -> settingsRepository.saveEntriesSelection(items) }
+ settingsRepository.setHoursAhead(hoursAhead)
+ settingsRepository.setMinElevation(minElevation)
+ val stationPos = settingsRepository.stationPosition.value
+ val selectedIds = settingsRepository.loadEntriesSelection()
+ val satellites = dataRepository.getEntriesWithIds(selectedIds)
+ satelliteRepository.calculatePasses(
+ satellites, stationPos, timeRef, hoursAhead, minElevation
)
}
}
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 db660f75..d6cc8c62 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
@@ -26,7 +26,6 @@ import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.domain.*
import com.rtbishop.look4sat.framework.BluetoothReporter
import com.rtbishop.look4sat.framework.NetworkReporter
-import com.rtbishop.look4sat.framework.OrientationSource
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPass
import com.rtbishop.look4sat.model.SatPos
@@ -42,27 +41,26 @@ import javax.inject.Inject
@HiltViewModel
class RadarViewModel @Inject constructor(
- private val savedStateHandle: SavedStateHandle,
- private val orientationSource: OrientationSource,
- private val reporter: NetworkReporter,
private val bluetoothReporter: BluetoothReporter,
- private val satManager: ISatelliteManager,
- private val repository: IDataRepository,
- private val settings: ISettingsSource,
- private val locationSource: ILocationSource
+ private val networkReporter: NetworkReporter,
+ private val savedStateHandle: SavedStateHandle,
+ private val dataRepository: IDataRepository,
+ private val satelliteRepository: ISatelliteRepository,
+ private val sensorRepository: ISensorRepository,
+ private val settingsRepository: ISettingsRepository
) : ViewModel() {
- private val stationPos = locationSource.stationPosition.value
+ private val stationPos = settingsRepository.stationPosition.value
private val magDeclination = getMagDeclination(stationPos)
val transmitters = mutableStateOf>(emptyList())
val radarData = mutableStateOf(null)
- val orientation = mutableStateOf(orientationSource.orientation.value)
+ val orientation = mutableStateOf(sensorRepository.orientation.value)
init {
- if (settings.isSensorEnabled()) {
+ if (settingsRepository.isSensorEnabled()) {
viewModelScope.launch {
- orientationSource.startListening()
- orientationSource.orientation.collect { data ->
+ sensorRepository.enableSensor()
+ sensorRepository.orientation.collect { data ->
orientation.value = Pair(data.first + magDeclination, data.second)
}
}
@@ -70,23 +68,24 @@ class RadarViewModel @Inject constructor(
}
override fun onCleared() {
- orientationSource.stopListening()
+ sensorRepository.disableSensor()
super.onCleared()
}
fun getPass() = flow {
val catNum = savedStateHandle.get("catNum") ?: 0
val aosTime = savedStateHandle.get("aosTime") ?: 0L
- satManager.calculatedPasses.collect { passes ->
+ satelliteRepository.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 = repository.getRadiosWithId(satPass.catNum)
+ val transmitters = dataRepository.getRadiosWithId(satPass.catNum)
viewModelScope.launch {
while (isActive) {
val timeNow = System.currentTimeMillis()
- val satPos = satManager.getPosition(satPass.satellite, stationPos, timeNow)
+ val satPos =
+ satelliteRepository.getPosition(satPass.satellite, stationPos, timeNow)
sendPassData(satPass, satPos, satPass.satellite)
sendPassDataBT(satPos)
processRadios(transmitters, satPass.satellite, timeNow)
@@ -97,9 +96,9 @@ class RadarViewModel @Inject constructor(
}
}
- fun getUseCompass(): Boolean = settings.isSensorEnabled()
+ fun getUseCompass(): Boolean = settingsRepository.isSensorEnabled()
- fun getShowSweep(): Boolean = settings.isSweepEnabled()
+ fun getShowSweep(): Boolean = settingsRepository.isSweepEnabled()
private fun getMagDeclination(geoPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
val latitude = geoPos.latitude.toFloat()
@@ -111,14 +110,16 @@ class RadarViewModel @Inject constructor(
viewModelScope.launch {
var track: List = emptyList()
if (!satPass.isDeepSpace) {
- track = satManager.getTrack(satellite, stationPos, satPass.aosTime, satPass.losTime)
+ track = satelliteRepository.getTrack(
+ satellite, stationPos, satPass.aosTime, satPass.losTime
+ )
}
- if (settings.getRotatorEnabled()) {
- val server = settings.getRotatorServer()
- val port = settings.getRotatorPort().toInt()
+ if (settingsRepository.getRotatorEnabled()) {
+ val server = settingsRepository.getRotatorServer()
+ val port = settingsRepository.getRotatorPort().toInt()
val azimuth = satPos.azimuth.toDegrees().round(1)
val elevation = satPos.elevation.toDegrees().round(1)
- reporter.reportRotation(server, port, azimuth, elevation)
+ networkReporter.reportRotation(server, port, azimuth, elevation)
}
radarData.value = RadarData(satPos, track)
}
@@ -126,10 +127,10 @@ class RadarViewModel @Inject constructor(
private fun sendPassDataBT(satPos: SatPos) {
viewModelScope.launch {
- if (settings.getBTEnabled()) {
- val btDevice = settings.getBTDeviceAddr()
+ if (settingsRepository.getBTEnabled()) {
+ val btDevice = settingsRepository.getBTDeviceAddr()
if (bluetoothReporter.isConnected()) {
- val format = settings.getBTFormat()
+ val format = settingsRepository.getBTFormat()
val azimuth = satPos.azimuth.toDegrees().round(0).toInt()
val elevation = satPos.elevation.toDegrees().round(0).toInt()
bluetoothReporter.reportRotation(format, azimuth, elevation)
@@ -144,7 +145,7 @@ class RadarViewModel @Inject constructor(
private fun processRadios(radios: List, satellite: Satellite, time: Long) {
viewModelScope.launch {
delay(125)
- val list = satManager.processRadios(satellite, stationPos, radios, time)
+ val list = satelliteRepository.processRadios(satellite, stationPos, radios, time)
transmitters.value = list
}
}
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 2a444f22..95113885 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
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
@@ -165,9 +166,8 @@ private fun CardAbout(version: String, modifier: Modifier = Modifier) {
@Composable
private fun LocationCardPreview() = MainTheme {
val stationPos = GeoPos(0.0, 0.0, 0.0, "IO91vl", 0L)
- LocationCard(
- settings = LocationSettings(true, stationPos, {}, { _, _ -> }, { }),
- setGpsLoc = {}, togglePosDialog = {}) {}
+ val settings = LocationSettings(true, stationPos, 0, {}, { _, _ -> }, {}, {})
+ LocationCard(settings = settings, setGpsLoc = {}, togglePosDialog = {}) {}
}
@Composable
@@ -231,14 +231,21 @@ private fun LocationCard(
}
}
}
+ if (settings.messageResId != 0) {
+ val context = LocalContext.current
+ val errorString = stringResource(id = settings.messageResId)
+ LaunchedEffect(key1 = settings.messageResId) {
+ showToast(context, errorString)
+ settings.dismissMessage()
+ }
+ }
}
@Preview(showBackground = true)
@Composable
private fun DataCardPreview() = MainTheme {
- DataCard(settings = DataSettings(
- true, 0L, 5000, 2500, {}, { }, {})
- ) {}
+ val settings = DataSettings(true, 0L, 5000, 2500, {}, {}, {})
+ DataCard(settings = settings) {}
}
@Composable
@@ -335,10 +342,10 @@ private fun DataCard(settings: DataSettings, updateFromFile: () -> Unit) {
@Preview(showBackground = true)
@Composable
private fun OtherCardPreview() = MainTheme {
- OtherCard(settings = OtherSettings(
+ val settings = OtherSettings(
getUtc = false, getUpdate = true, getSweep = true, getSensor = true,
setUtc = {}, setUpdate = {}, setSweep = {}, setSensor = {})
- )
+ OtherCard(settings = settings)
}
@Composable
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreenState.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreenState.kt
index 890fc30b..ab7e34d8 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreenState.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreenState.kt
@@ -5,9 +5,11 @@ import com.rtbishop.look4sat.model.GeoPos
data class LocationSettings(
val isUpdating: Boolean,
val stationPos: GeoPos,
+ val messageResId: Int,
val setGpsLoc: () -> Unit,
val setManualLoc: (Double, Double) -> Unit,
- val setQthLoc: (String) -> Unit
+ val setQthLoc: (String) -> Unit,
+ val dismissMessage: () -> Unit
)
data class DataSettings(
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 26cc98ba..92839665 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
@@ -20,9 +20,9 @@ package com.rtbishop.look4sat.presentation.settings
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.IDataRepository
-import com.rtbishop.look4sat.domain.ILocationSource
-import com.rtbishop.look4sat.domain.ISettingsSource
+import com.rtbishop.look4sat.domain.ISettingsRepository
import com.rtbishop.look4sat.model.DataState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.combine
@@ -31,31 +31,32 @@ import javax.inject.Inject
@HiltViewModel
class SettingsViewModel @Inject constructor(
- private val locationSource: ILocationSource,
- private val repository: IDataRepository,
- private val settings: ISettingsSource
+ private val dataRepository: IDataRepository,
+ private val settingsRepository: ISettingsRepository
) : ViewModel() {
private val defaultLocationSettings = LocationSettings(false,
- locationSource.stationPosition.value,
- { updateStationPosition() },
- { lat, lon -> locationSource.setGeoPosition(lat, lon) },
- { locationSource.setQthPosition(it) })
+ settingsRepository.stationPosition.value,
+ 0,
+ { setGpsPosition() },
+ { latitude, longitude -> setGeoPosition(latitude, longitude) },
+ { locator -> setQthPosition(locator) },
+ { dismissLocationMessage() })
val locationSettings = mutableStateOf(defaultLocationSettings)
private val defaultDataSettings = DataSettings(false,
- settings.getLastUpdateTime(),
+ settingsRepository.getLastUpdateTime(),
0,
0,
- { repository.updateFromWeb() },
- { repository.updateFromFile(it) },
- { repository.clearAllData() })
+ { dataRepository.updateFromWeb() },
+ { dataRepository.updateFromFile(it) },
+ { dataRepository.clearAllData() })
val dataSettings = mutableStateOf(defaultDataSettings)
- private val defaultOtherSettings = OtherSettings(settings.isUtcEnabled(),
- settings.isUpdateEnabled(),
- settings.isSweepEnabled(),
- settings.isSensorEnabled(),
+ private val defaultOtherSettings = OtherSettings(settingsRepository.isUtcEnabled(),
+ settingsRepository.isUpdateEnabled(),
+ settingsRepository.isSweepEnabled(),
+ settingsRepository.isSensorEnabled(),
{ setUtc(it) },
{ setUpdate(it) },
{ setSweep(it) },
@@ -64,49 +65,81 @@ class SettingsViewModel @Inject constructor(
init {
viewModelScope.launch {
- locationSource.stationPosition.collect { stationPos ->
+ settingsRepository.stationPosition.collect { stationPos ->
locationSettings.value = locationSettings.value.copy(
isUpdating = false, stationPos = stationPos
)
}
}
viewModelScope.launch {
- repository.updateState.collect {
+ dataRepository.updateState.collect {
val isUpdating = it is DataState.Loading
dataSettings.value = dataSettings.value.copy(
- isUpdating = isUpdating, lastUpdated = settings.getLastUpdateTime()
+ isUpdating = isUpdating, lastUpdated = settingsRepository.getLastUpdateTime()
)
}
}
viewModelScope.launch {
- combine(repository.getEntriesTotal(), repository.getRadiosTotal()) { sats, radios ->
+ combine(
+ dataRepository.getEntriesTotal(), dataRepository.getRadiosTotal()
+ ) { sats, radios ->
dataSettings.value = dataSettings.value.copy(satsTotal = sats, radiosTotal = radios)
}.collect {}
}
}
- private fun updateStationPosition() {
- val isSuccessful = locationSource.setGpsPosition()
- locationSettings.value = locationSettings.value.copy(isUpdating = isSuccessful)
+ private fun setGpsPosition() {
+ if (settingsRepository.setGpsPosition()) {
+ val messageResId = R.string.location_success
+ locationSettings.value =
+ locationSettings.value.copy(isUpdating = true, messageResId = messageResId)
+ } else {
+ val errorResId = R.string.location_gps_error
+ locationSettings.value = locationSettings.value.copy(messageResId = errorResId)
+ }
+ }
+
+ private fun setGeoPosition(latitude: Double, longitude: Double) {
+ if (settingsRepository.setGeoPosition(latitude, longitude)) {
+ val messageResId = R.string.location_success
+ locationSettings.value = locationSettings.value.copy(messageResId = messageResId)
+ } else {
+ val errorResId = R.string.location_manual_error
+ locationSettings.value = locationSettings.value.copy(messageResId = errorResId)
+ }
+ }
+
+ private fun setQthPosition(locator: String) {
+ if (settingsRepository.setQthPosition(locator)) {
+ val messageResId = R.string.location_success
+ locationSettings.value = locationSettings.value.copy(messageResId = messageResId)
+ } else {
+ val errorResId = R.string.location_qth_error
+ locationSettings.value = locationSettings.value.copy(messageResId = errorResId)
+ }
+ }
+
+ private fun dismissLocationMessage() {
+ locationSettings.value = locationSettings.value.copy(messageResId = 0)
}
private fun setUtc(value: Boolean) {
- settings.setUtcState(value)
+ settingsRepository.setUtcState(value)
otherSettings.value = otherSettings.value.copy(getUtc = value)
}
private fun setUpdate(value: Boolean) {
- settings.setUpdateState(value)
+ settingsRepository.setUpdateState(value)
otherSettings.value = otherSettings.value.copy(getUpdate = value)
}
private fun setSweep(value: Boolean) {
- settings.setSweepState(value)
+ settingsRepository.setSweepState(value)
otherSettings.value = otherSettings.value.copy(getSweep = value)
}
private fun setSensor(value: Boolean) {
- settings.setSensorState(value)
+ settingsRepository.setSensorState(value)
otherSettings.value = otherSettings.value.copy(getSensor = value)
}
diff --git a/base/src/main/java/com/rtbishop/look4sat/data/DataParser.kt b/base/src/main/java/com/rtbishop/look4sat/data/DataParser.kt
index 4ecd5f4a..62388ad6 100644
--- a/base/src/main/java/com/rtbishop/look4sat/data/DataParser.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/data/DataParser.kt
@@ -26,56 +26,52 @@ import org.json.JSONObject
import java.io.InputStream
import kotlin.math.pow
-class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
+class DataParser(private val dispatcher: CoroutineDispatcher) {
- suspend fun parseCSVStream(csvStream: InputStream): List =
- withContext(defaultDispatcher) {
- val parsedItems = mutableListOf()
- csvStream.bufferedReader().useLines { lines ->
- lines.forEachIndexed { index, line ->
- if (index != 0) {
- val values = line.split(",")
- parseCSV(values)?.let { tle -> parsedItems.add(tle) }
- }
+ suspend fun parseCSVStream(stream: InputStream): List = withContext(dispatcher) {
+ val parsedItems = mutableListOf()
+ stream.bufferedReader().useLines { lines ->
+ lines.forEachIndexed { index, line ->
+ if (index != 0) {
+ val values = line.split(",")
+ parseCSV(values)?.let { tle -> parsedItems.add(tle) }
}
}
+ }
+ return@withContext parsedItems
+ }
+
+ suspend fun parseTLEStream(stream: InputStream): List = withContext(dispatcher) {
+ val tleStrings = mutableListOf(String(), String(), String())
+ val parsedItems = mutableListOf()
+ var lineIndex = 0
+ stream.bufferedReader().forEachLine { line ->
+ tleStrings[lineIndex] = line
+ if (lineIndex < 2) {
+ lineIndex++
+ } else {
+ val isLineOneValid = tleStrings[1].substring(0, 1) == "1"
+ val isLineTwoValid = tleStrings[2].substring(0, 1) == "2"
+ if (!isLineOneValid && !isLineTwoValid) return@forEachLine
+ parseTLE(tleStrings)?.let { tle -> parsedItems.add(tle) }
+ lineIndex = 0
+ }
+ }
+ return@withContext parsedItems
+ }
+
+ suspend fun parseJSONStream(stream: InputStream): List = withContext(dispatcher) {
+ val parsedItems = mutableListOf()
+ try {
+ val jsonArray = JSONArray(stream.bufferedReader().readText())
+ for (index in 0 until jsonArray.length()) {
+ val jsonObject = jsonArray.getJSONObject(index)
+ parseJSON(jsonObject)?.let { parsedItems.add(it) }
+ }
return@withContext parsedItems
- }
-
- suspend fun parseTLEStream(tleStream: InputStream): List =
- withContext(defaultDispatcher) {
- val tleStrings = mutableListOf(String(), String(), String())
- val parsedItems = mutableListOf()
- var lineIndex = 0
- tleStream.bufferedReader().forEachLine { line ->
- tleStrings[lineIndex] = line
- if (lineIndex < 2) {
- lineIndex++
- } else {
- val isLineOneValid = tleStrings[1].substring(0, 1) == "1"
- val isLineTwoValid = tleStrings[2].substring(0, 1) == "2"
- if (!isLineOneValid && !isLineTwoValid) return@forEachLine
- parseTLE(tleStrings)?.let { tle -> parsedItems.add(tle) }
- lineIndex = 0
- }
- }
+ } catch (exception: Exception) {
return@withContext parsedItems
}
-
- suspend fun parseJSONStream(jsonStream: InputStream): List {
- return withContext(defaultDispatcher) {
- val parsedItems = mutableListOf()
- try {
- val jsonArray = JSONArray(jsonStream.bufferedReader().readText())
- for (index in 0 until jsonArray.length()) {
- val jsonObject = jsonArray.getJSONObject(index)
- parseJSON(jsonObject)?.let { parsedItems.add(it) }
- }
- return@withContext parsedItems
- } catch (exception: Exception) {
- return@withContext parsedItems
- }
- }
}
private fun parseCSV(values: List): OrbitalData? {
@@ -120,8 +116,9 @@ class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
val argper: Double = tle[2].substring(34, 42).toDouble()
val meanan: Double = tle[2].substring(43, 51).toDouble()
val catnum: Int = tle[1].substring(2, 7).trim().toInt()
- val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() /
- 10.0.pow(tle[1].substring(60, 61).toDouble())
+ val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() / 10.0.pow(
+ tle[1].substring(60, 61).toDouble()
+ )
return OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
} catch (exception: Exception) {
return null
@@ -154,7 +151,7 @@ class DataParser(private val defaultDispatcher: CoroutineDispatcher) {
var dayOfYear = dayOfMonth
// If leap year increment Feb days
if (((year / 4 == 0) && (year / 100 != 0)) || (year / 400 == 0)) daysArray[1]++
- for (i in 0 until month - 1) { dayOfYear += daysArray[i] }
+ for (i in 0 until month - 1) dayOfYear += daysArray[i]
return dayOfYear
}
}
diff --git a/base/src/main/java/com/rtbishop/look4sat/data/DataRepository.kt b/base/src/main/java/com/rtbishop/look4sat/data/DataRepository.kt
index c498b0e3..d20e1fa2 100644
--- a/base/src/main/java/com/rtbishop/look4sat/data/DataRepository.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/data/DataRepository.kt
@@ -18,9 +18,10 @@
package com.rtbishop.look4sat.data
import com.rtbishop.look4sat.domain.IDataRepository
-import com.rtbishop.look4sat.domain.ISettingsSource
+import com.rtbishop.look4sat.domain.ISettingsRepository
import com.rtbishop.look4sat.model.DataState
import com.rtbishop.look4sat.model.SatEntry
+import com.rtbishop.look4sat.model.SatItem
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -34,7 +35,7 @@ class DataRepository(
private val radioSource: IRadiosStorage,
private val remoteSource: INetworkSource,
private val repositoryScope: CoroutineScope,
- private val settingsManager: ISettingsSource
+ private val settingsRepository: ISettingsRepository
) : IDataRepository {
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
@@ -48,10 +49,17 @@ class DataRepository(
override fun getRadiosTotal() = radioSource.getRadiosTotal()
+ override fun getSatelliteTypes() = remoteSource.satelliteSourcesMap.keys.sorted()
+
override suspend fun getEntriesWithModes() = entrySource.getEntriesWithModes()
override suspend fun getEntriesWithIds(ids: List) = entrySource.getEntriesWithIds(ids)
+ override suspend fun getEntriesWithSelection(): List {
+ val selectedIds = settingsRepository.loadEntriesSelection()
+ return getEntriesWithModes().onEach { it.isSelected = it.catnum in selectedIds }
+ }
+
override suspend fun getRadiosWithId(id: Int) = radioSource.getRadiosWithId(id)
override fun updateFromFile(uri: String) {
@@ -69,7 +77,7 @@ class DataRepository(
_updateState.value = DataState.Loading
repositoryScope.launch(exceptionHandler) {
val importedEntries = mutableListOf()
- val sourcesMap = settingsManager.sourcesMap
+ val sourcesMap = remoteSource.satelliteSourcesMap
val jobsMap = sourcesMap.mapValues { async { remoteSource.getDataStream(it.value) } }
jobsMap.mapValues { job -> job.value.await() }.forEach { entry ->
entry.value?.let { stream ->
@@ -78,7 +86,7 @@ class DataRepository(
// parse tle stream
val satellites = importSatellites(stream)
val catnums = satellites.map { it.data.catnum }
- settingsManager.saveSatType(type, catnums)
+ settingsRepository.saveSatType(type, catnums)
importedEntries.addAll(satellites)
}
"McCants", "Classified" -> {
@@ -86,7 +94,7 @@ class DataRepository(
val unzipped = ZipInputStream(stream).apply { nextEntry }
val satellites = importSatellites(unzipped)
val catnums = satellites.map { it.data.catnum }
- settingsManager.saveSatType(type, catnums)
+ settingsRepository.saveSatType(type, catnums)
importedEntries.addAll(satellites)
}
else -> {
@@ -94,7 +102,7 @@ class DataRepository(
val parsed = dataParser.parseCSVStream(stream)
val satellites = parsed.map { data -> SatEntry(data) }
val catnums = satellites.map { it.data.catnum }
- settingsManager.saveSatType(type, catnums)
+ settingsRepository.saveSatType(type, catnums)
importedEntries.addAll(satellites)
}
}
@@ -104,7 +112,7 @@ class DataRepository(
setUpdateSuccessful()
}
repositoryScope.launch(exceptionHandler) {
- remoteSource.getDataStream(remoteSource.radioApi)?.let { stream ->
+ remoteSource.getDataStream(remoteSource.radioSourceUrl)?.let { stream ->
radioSource.insertRadios(dataParser.parseJSONStream(stream))
}
}
@@ -125,7 +133,7 @@ class DataRepository(
}
private fun setUpdateSuccessful(updateTime: Long = System.currentTimeMillis()) {
- settingsManager.setLastUpdateTime(updateTime)
+ settingsRepository.setLastUpdateTime(updateTime)
_updateState.value = DataState.Success(updateTime)
}
diff --git a/base/src/main/java/com/rtbishop/look4sat/data/INetworkSource.kt b/base/src/main/java/com/rtbishop/look4sat/data/INetworkSource.kt
index 4f30ca68..043df8f6 100644
--- a/base/src/main/java/com/rtbishop/look4sat/data/INetworkSource.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/data/INetworkSource.kt
@@ -21,7 +21,36 @@ import java.io.InputStream
interface INetworkSource {
- val radioApi: String get() = "https://db.satnogs.org/api/transmitters/?format=json&status=active"
+ 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",
+ "Amsat" to "https://amsat.org/tle/current/nasabare.txt",
+ "Amateur" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=amateur&FORMAT=csv",
+ "Classified" to "https://www.prismnet.com/~mmccants/tles/classfd.zip",
+ "Cubesat" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=cubesat&FORMAT=csv",
+ "Education" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=education&FORMAT=csv",
+ "Engineer" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=engineering&FORMAT=csv",
+ "Geostationary" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=geo&FORMAT=csv",
+ "Globalstar" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=globalstar&FORMAT=csv",
+ "GNSS" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=gnss&FORMAT=csv",
+ "Intelsat" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=intelsat&FORMAT=csv",
+ "Iridium" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=iridium-NEXT&FORMAT=csv",
+ "McCants" to "https://www.prismnet.com/~mmccants/tles/inttles.zip",
+ "Military" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=military&FORMAT=csv",
+ "New" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=csv",
+ "OneWeb" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=csv",
+ "Orbcomm" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=orbcomm&FORMAT=csv",
+ "R4UAB" to "https://r4uab.ru/satonline.txt",
+ "Resource" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=resource&FORMAT=csv",
+ "SatNOGS" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=satnogs&FORMAT=csv",
+ "Science" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=science&FORMAT=csv",
+ "Spire" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=spire&FORMAT=csv",
+ "Starlink" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=starlink&FORMAT=csv",
+ "Swarm" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=swarm&FORMAT=csv",
+ "Weather" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=weather&FORMAT=csv",
+ "X-Comm" to "https://celestrak.com/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv"
+ )
suspend fun getDataStream(url: String): InputStream?
}
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/SatelliteManager.kt b/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepository.kt
similarity index 94%
rename from base/src/main/java/com/rtbishop/look4sat/domain/SatelliteManager.kt
rename to base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepository.kt
index 2b0fb687..824c82e2 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/SatelliteManager.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/data/SatelliteRepository.kt
@@ -15,8 +15,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-package com.rtbishop.look4sat.domain
+package com.rtbishop.look4sat.data
+import com.rtbishop.look4sat.domain.ISatelliteRepository
+import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPass
import com.rtbishop.look4sat.model.SatPos
@@ -28,7 +30,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.withContext
-class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISatelliteManager {
+class SatelliteRepository(private val dispatcher: CoroutineDispatcher) : ISatelliteRepository {
private var passes = listOf()
private val _calculatedPasses = MutableSharedFlow>(replay = 1)
@@ -37,13 +39,13 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
override fun getPasses(): List = passes
override suspend fun getPosition(sat: Satellite, pos: GeoPos, time: Long): SatPos {
- return withContext(defaultDispatcher) { sat.getPosition(pos, time) }
+ return withContext(dispatcher) { sat.getPosition(pos, time) }
}
override suspend fun getTrack(
sat: Satellite, pos: GeoPos, start: Long, end: Long
): List {
- return withContext(defaultDispatcher) {
+ return withContext(dispatcher) {
val positions = mutableListOf()
var currentTime = start
while (currentTime < end) {
@@ -57,7 +59,7 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
override suspend fun processRadios(
sat: Satellite, pos: GeoPos, radios: List, time: Long
): List {
- return withContext(defaultDispatcher) {
+ return withContext(dispatcher) {
val satPos = sat.getPosition(pos, time)
val copiedList = radios.map { it.copy() }
copiedList.forEach { transmitter ->
@@ -73,7 +75,7 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
}
override suspend fun processPasses(passList: List, time: Long): List {
- return withContext(defaultDispatcher) {
+ return withContext(dispatcher) {
passList.forEach { pass ->
if (!pass.isDeepSpace) {
val timeStart = pass.aosTime
@@ -96,7 +98,7 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
passes = newPasses
_calculatedPasses.emit(newPasses)
} else {
- withContext(defaultDispatcher) {
+ withContext(dispatcher) {
val allPasses = mutableListOf()
satList.forEach { satellite ->
allPasses.addAll(satellite.getPasses(pos, time, hoursAhead))
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSat.kt b/base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSatellite.kt
similarity index 99%
rename from base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSat.kt
rename to base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSatellite.kt
index c6a40a85..8f4b9899 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSat.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/DeepSpaceSatellite.kt
@@ -20,7 +20,7 @@ package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.model.OrbitalData
import kotlin.math.*
-class DeepSpaceSat(data: OrbitalData) : Satellite(data) {
+class DeepSpaceSatellite(data: OrbitalData) : Satellite(data) {
private val c1: Double
private val c4: Double
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/IDataRepository.kt b/base/src/main/java/com/rtbishop/look4sat/domain/IDataRepository.kt
index 9cabd0de..520a5ce9 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/IDataRepository.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/IDataRepository.kt
@@ -31,10 +31,14 @@ interface IDataRepository {
fun getRadiosTotal(): Flow
+ fun getSatelliteTypes(): List
+
suspend fun getEntriesWithModes(): List
suspend fun getEntriesWithIds(ids: List): List
+ suspend fun getEntriesWithSelection(): List
+
suspend fun getRadiosWithId(id: Int): List
fun updateFromFile(uri: String)
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ILocationSource.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ILocationSource.kt
deleted file mode 100644
index b9891d42..00000000
--- a/base/src/main/java/com/rtbishop/look4sat/domain/ILocationSource.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.rtbishop.look4sat.domain
-
-import com.rtbishop.look4sat.model.GeoPos
-import kotlinx.coroutines.flow.StateFlow
-
-interface ILocationSource {
-
- val stationPosition: StateFlow
-
- fun setGpsPosition(): Boolean
-
- fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double = 0.0): Boolean
-
- fun setQthPosition(locator: String): Boolean
-}
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteManager.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepository.kt
similarity index 96%
rename from base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteManager.kt
rename to base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepository.kt
index 370b4335..844640ed 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteManager.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISatelliteRepository.kt
@@ -6,7 +6,7 @@ import com.rtbishop.look4sat.model.SatPos
import com.rtbishop.look4sat.model.SatRadio
import kotlinx.coroutines.flow.SharedFlow
-interface ISatelliteManager {
+interface ISatelliteRepository {
val calculatedPasses: SharedFlow>
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISensorRepository.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISensorRepository.kt
new file mode 100644
index 00000000..0580adc3
--- /dev/null
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISensorRepository.kt
@@ -0,0 +1,12 @@
+package com.rtbishop.look4sat.domain
+
+import kotlinx.coroutines.flow.StateFlow
+
+interface ISensorRepository {
+
+ val orientation: StateFlow>
+
+ fun enableSensor()
+
+ fun disableSensor()
+}
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepository.kt b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepository.kt
new file mode 100644
index 00000000..010940eb
--- /dev/null
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/ISettingsRepository.kt
@@ -0,0 +1,100 @@
+/*
+ * Look4Sat. Amateur radio satellite tracker and pass predictor.
+ * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.rtbishop.look4sat.domain
+
+import com.rtbishop.look4sat.model.GeoPos
+import kotlinx.coroutines.flow.StateFlow
+
+interface ISettingsRepository {
+
+ val stationPosition: StateFlow
+
+ fun setGpsPosition(): Boolean
+
+ fun setGeoPosition(latitude: Double, longitude: Double, altitude: Double = 0.0): Boolean
+
+ fun setQthPosition(locator: String): Boolean
+
+ fun getHoursAhead(): Int
+
+ fun setHoursAhead(hoursAhead: Int)
+
+ fun getMinElevation(): Double
+
+ fun setMinElevation(minElevation: Double)
+
+ fun isUtcEnabled(): Boolean
+
+ fun setUtcState(value: Boolean)
+
+ fun getLastUpdateTime(): Long
+
+ fun setLastUpdateTime(updateTime: Long)
+
+ fun isUpdateEnabled(): Boolean
+
+ fun setUpdateState(value: Boolean)
+
+ fun isSensorEnabled(): Boolean
+
+ fun setSensorState(value: Boolean)
+
+ fun isSweepEnabled(): Boolean
+
+ fun setSweepState(value: Boolean)
+
+ fun saveModesSelection(modes: List)
+
+ fun loadModesSelection(): List
+
+ fun saveEntriesSelection(catnums: List)
+
+ fun loadEntriesSelection(): List
+
+ fun saveSatType(type: String, catnums: List)
+
+ fun loadSatType(type: String): List
+
+ fun getRotatorEnabled(): Boolean
+
+ fun setRotatorEnabled(value: Boolean)
+
+ fun getRotatorServer(): String
+
+ fun setRotatorServer(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)
+}
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSat.kt b/base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSatellite.kt
similarity index 99%
rename from base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSat.kt
rename to base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSatellite.kt
index 9f16df3b..15610e29 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSat.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/NearEarthSatellite.kt
@@ -20,7 +20,7 @@ package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.model.OrbitalData
import kotlin.math.*
-class NearEarthSat(data: OrbitalData) : Satellite(data) {
+class NearEarthSatellite(data: OrbitalData) : Satellite(data) {
private val aodp: Double
private val aycof: Double
diff --git a/base/src/main/java/com/rtbishop/look4sat/domain/Satellite.kt b/base/src/main/java/com/rtbishop/look4sat/domain/Satellite.kt
index af31cfe0..dc1f8283 100644
--- a/base/src/main/java/com/rtbishop/look4sat/domain/Satellite.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/domain/Satellite.kt
@@ -110,8 +110,8 @@ abstract class Satellite(val data: OrbitalData) {
}
private fun calculateSDP4orSGP4(tsince: Double) {
- if (data.isDeepSpace) (this as DeepSpaceSat).calculateSDP4(tsince)
- else (this as NearEarthSat).calculateSGP4(tsince)
+ if (data.isDeepSpace) (this as DeepSpaceSatellite).calculateSDP4(tsince)
+ else (this as NearEarthSatellite).calculateSGP4(tsince)
}
// Converts the sat position and velocity vectors to km and km/sec
diff --git a/base/src/main/java/com/rtbishop/look4sat/model/OrbitalData.kt b/base/src/main/java/com/rtbishop/look4sat/model/OrbitalData.kt
index 0b179633..c92528fb 100644
--- a/base/src/main/java/com/rtbishop/look4sat/model/OrbitalData.kt
+++ b/base/src/main/java/com/rtbishop/look4sat/model/OrbitalData.kt
@@ -39,5 +39,6 @@ data class OrbitalData(
// Space objects are classified as NearEarth (period < 225 min) or DeepSpace (period >= 225 min)
val isDeepSpace: Boolean = orbitalPeriod >= 225.0
) {
- fun getSatellite(): Satellite = if (isDeepSpace) DeepSpaceSat(this) else NearEarthSat(this)
+ fun getSatellite(): Satellite =
+ if (isDeepSpace) DeepSpaceSatellite(this) else NearEarthSatellite(this)
}