Further classes movement and cleanup

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:33 +00:00
1 parent 542cfcfd50
commit 622d4e3632
27 files changed
+684 -578

No files matched your search

@@ -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())}")
@@ -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)
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<GeoPos> = _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)
}
}
@@ -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<Pair<Float, Float>> = _orientation
override val orientation: StateFlow<Pair<Float, Float>> = _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
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<GeoPos> = _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<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
preferences.edit { putStringSet(keySelection, stringList.toSet()) }
}
override fun loadEntriesSelection(): List<Int> {
val catnums =
preferences.getStringSet(keySelection, emptySet())?.map { catnum -> catnum.toInt() }
return catnums?.sorted() ?: emptyList()
}
override fun saveSatType(type: String, catnums: List<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
preferences.edit { putStringSet("type$type", stringList.toSet()) }
}
override fun loadSatType(type: String): List<Int> {
val catnums =
preferences.getStringSet("type$type", emptySet())?.map { catnum -> catnum.toInt() }
return catnums ?: emptyList()
}
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<String>) {
preferences.edit { putStringSet(keyModes, modes.toSet()) }
}
override fun loadModesSelection(): List<String> {
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())
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
prefs.edit { putStringSet(keySelection, stringList.toSet()) }
}
override fun loadEntriesSelection(): List<Int> {
val catnums = prefs.getStringSet(keySelection, emptySet())?.map { catnum -> catnum.toInt() }
return catnums?.sorted() ?: emptyList()
}
override fun saveSatType(type: String, catnums: List<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
prefs.edit { putStringSet("type$type", stringList.toSet()) }
}
override fun loadSatType(type: String): List<Int> {
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<String>) {
prefs.edit { putStringSet(keyModes, modes.toSet()) }
}
override fun loadModesSelection(): List<String> {
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 <reified T> SharedPreferences.observeKey(key: String, default: T): Flow<T> {
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 <reified T> 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}")
}
}
}
@@ -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<String> = 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<Int>, isSelected: Boolean) {
@@ -99,14 +95,9 @@ class EntriesViewModel @Inject constructor(
}
}
private suspend fun loadEntriesWithSelection(): List<SatItem> {
val selectedIds = settings.loadEntriesSelection()
return repository.getEntriesWithModes().onEach { it.isSelected = it.catnum in selectedIds }
}
private fun filterByType(items: List<SatItem>, type: String): List<SatItem> {
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 }
}
@@ -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<Satellite>()
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<GeoPos>()
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<Satellite>, pos: GeoPos, date: Date) {
val positions = mutableMapOf<Satellite, GeoPos>()
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())
@@ -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, { _,_ -> }) }
}
@@ -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<List<SatPass>>>(DataState.Loading)
@@ -48,18 +45,18 @@ class PassesViewModel @Inject constructor(
val passes: StateFlow<DataState<List<SatPass>>> = _passes
val timerText: StateFlow<Triple<String, String, String>?> = _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<Int>? = 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
)
}
}
@@ -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<List<SatRadio>>(emptyList())
val radarData = mutableStateOf<RadarData?>(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<Int>("catNum") ?: 0
val aosTime = savedStateHandle.get<Long>("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<SatPos> = 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<SatRadio>, 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
}
}
@@ -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
@@ -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(
@@ -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)
}