diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/LocationProvider.kt b/app/src/main/java/com/rtbishop/look4sat/framework/LocationProvider.kt
new file mode 100644
index 00000000..199636a4
--- /dev/null
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/LocationProvider.kt
@@ -0,0 +1,108 @@
+/*
+ * Look4Sat. Amateur radio satellite tracker and pass predictor.
+ * Copyright (C) 2019-2021 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.Manifest
+import android.content.Context
+import android.content.pm.PackageManager
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import androidx.core.content.ContextCompat
+import com.rtbishop.look4sat.R
+import com.rtbishop.look4sat.domain.LocationHandler
+import com.rtbishop.look4sat.domain.QthConverter
+import com.rtbishop.look4sat.domain.model.DataState
+import com.rtbishop.look4sat.domain.predict.GeoPos
+import com.rtbishop.look4sat.presentation.round
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class LocationProvider @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val settingsProvider: SettingsProvider,
+) : LocationListener, LocationHandler {
+
+ private val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+ private val providerDef = LocationManager.PASSIVE_PROVIDER
+ private val providerNet = LocationManager.NETWORK_PROVIDER
+ private val providerGps = LocationManager.GPS_PROVIDER
+ private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
+ private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
+ private val _stationPosition = MutableSharedFlow>(
+ extraBufferCapacity = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ private var currentPosition = settingsProvider.loadStationPosition()
+ override val stationPosition: SharedFlow> = _stationPosition
+
+ override fun getStationPosition(): GeoPos = currentPosition
+
+ override fun setStationPosition(latitude: Double, longitude: Double) {
+ if (QthConverter.isValidPosition(latitude, longitude)) {
+ val newLat = latitude.round(4)
+ val newLon = longitude.round(4)
+ currentPosition = GeoPos(newLat, newLon)
+ settingsProvider.saveStationPosition(newLat, newLon)
+ _stationPosition.tryEmit(DataState.Success(currentPosition))
+ } else _stationPosition.tryEmit(DataState.Error(context.getString(R.string.pref_pos_gps_null)))
+ }
+
+ override fun setPositionFromLocation() {
+ val result = ContextCompat.checkSelfPermission(context, locationFine)
+ if (manager.isProviderEnabled(providerDef) && result == PackageManager.PERMISSION_GRANTED) {
+ val location = manager.getLastKnownLocation(providerDef)
+ if (location != null) {
+ setStationPosition(location.latitude, location.longitude)
+ } else setPositionFromGps()
+ } else _stationPosition.tryEmit(DataState.Error(context.getString(R.string.pref_pos_gps_null)))
+ }
+
+ override fun setPositionFromNet() {
+ val result = ContextCompat.checkSelfPermission(context, locationCoarse)
+ if (manager.isProviderEnabled(providerNet) && result == PackageManager.PERMISSION_GRANTED) {
+ _stationPosition.tryEmit(DataState.Loading)
+ manager.requestLocationUpdates(providerNet, 0L, 0f, this)
+ } else _stationPosition.tryEmit(DataState.Error(context.getString(R.string.pref_pos_gps_null)))
+ }
+
+ override fun setPositionFromGps() {
+ val result = ContextCompat.checkSelfPermission(context, locationFine)
+ if (manager.isProviderEnabled(providerGps) && result == PackageManager.PERMISSION_GRANTED) {
+ _stationPosition.tryEmit(DataState.Loading)
+ manager.requestLocationUpdates(providerGps, 0L, 0f, this)
+ } else _stationPosition.tryEmit(DataState.Error(context.getString(R.string.pref_pos_gps_null)))
+ }
+
+ override fun setPositionFromQth(qthString: String) {
+ val position = QthConverter.qthToPosition(qthString)
+ if (position != null) {
+ setStationPosition(position.latitude, position.longitude)
+ } else _stationPosition.tryEmit(DataState.Error(context.getString(R.string.pref_pos_qth_error)))
+ }
+
+ override fun onLocationChanged(location: Location) {
+ manager.removeUpdates(this)
+ setStationPosition(location.latitude, location.longitude)
+ }
+}
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 0766904d..00000000
--- a/app/src/main/java/com/rtbishop/look4sat/framework/LocationSource.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2021 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.Manifest
-import android.content.Context
-import android.content.SharedPreferences
-import android.content.pm.PackageManager
-import android.hardware.GeomagneticField
-import android.location.Location
-import android.location.LocationListener
-import android.location.LocationManager
-import androidx.core.content.ContextCompat
-import com.rtbishop.look4sat.domain.LocationProvider
-import com.rtbishop.look4sat.domain.QthConverter
-import com.rtbishop.look4sat.domain.predict.GeoPos
-import com.rtbishop.look4sat.presentation.round
-import dagger.hilt.android.qualifiers.ApplicationContext
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class LocationSource @Inject constructor(
- @ApplicationContext private val context: Context,
- private val preferences: SharedPreferences
-) : LocationListener, LocationProvider {
-
- private val locManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
- private val _updatedLocation = MutableSharedFlow()
- override val updatedLocation: SharedFlow = _updatedLocation
-
- fun getMagDeclination(stationPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
- val lat = stationPos.latitude.toFloat()
- val lon = stationPos.longitude.toFloat()
- return GeomagneticField(lat, lon, 0f, time).declination
- }
-
- fun updatePosition(latitude: Double, longitude: Double) {
- if (QthConverter.isValidPosition(latitude, longitude)) {
- _updatedLocation.tryEmit(GeoPos(latitude, longitude))
- } else _updatedLocation.tryEmit(null)
- }
-
- fun updatePositionFromQth(qthString: String) {
- val position = QthConverter.qthToPosition(qthString)
- if (position != null) {
- _updatedLocation.tryEmit(GeoPos(position.latitude, position.longitude))
- } else _updatedLocation.tryEmit(null)
- }
-
- fun updatePositionFromGps() {
- val provider = LocationManager.GPS_PROVIDER
- val permission = Manifest.permission.ACCESS_FINE_LOCATION
- val result = ContextCompat.checkSelfPermission(context, permission)
- if (locManager.isProviderEnabled(provider) && result == PackageManager.PERMISSION_GRANTED) {
- locManager.requestLocationUpdates(provider, 0L, 0f, this)
- } else _updatedLocation.tryEmit(null)
- }
-
- fun updatePositionFromNetwork() {
- val provider = LocationManager.NETWORK_PROVIDER
- val permission = Manifest.permission.ACCESS_COARSE_LOCATION
- val result = ContextCompat.checkSelfPermission(context, permission)
- if (locManager.isProviderEnabled(provider) && result == PackageManager.PERMISSION_GRANTED) {
- locManager.requestLocationUpdates(provider, 0L, 0f, this)
- } else _updatedLocation.tryEmit(null)
- }
-
- override fun onLocationChanged(location: Location) {
- locManager.removeUpdates(this)
- val latitude = location.latitude.round(4)
- val longitude = location.longitude.round(4)
- _updatedLocation.tryEmit(GeoPos(latitude, longitude))
- }
-}
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/PreferencesSource.kt b/app/src/main/java/com/rtbishop/look4sat/framework/PreferencesSource.kt
deleted file mode 100644
index b69dd601..00000000
--- a/app/src/main/java/com/rtbishop/look4sat/framework/PreferencesSource.kt
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2021 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.hardware.GeomagneticField
-import android.location.LocationManager
-import androidx.core.content.edit
-import com.rtbishop.look4sat.BuildConfig
-import com.rtbishop.look4sat.data.PreferencesHandler
-import com.rtbishop.look4sat.domain.QthConverter
-import com.rtbishop.look4sat.domain.predict.GeoPos
-import com.rtbishop.look4sat.presentation.round
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class PreferencesSource @Inject constructor(
- private val locationManager: LocationManager,
- private val preferences: SharedPreferences
-) : PreferencesHandler {
-
- private val keyInitialSetup = "${BuildConfig.VERSION_NAME}update"
-
- companion object {
- const val keyDataSources = "dataSources"
- const val keyModes = "satModes"
- const val keyCompass = "compass"
- const val keyRadarSweep = "radarSweep"
- const val keyTimeUTC = "timeUTC"
- const val keyHoursAhead = "hoursAhead"
- const val keyMinElevation = "minElevation"
- const val keyRotator = "isRotatorEnabled"
- const val keyRotatorAddress = "rotatorAddress"
- const val keyRotatorPort = "rotatorPort"
- const val keyLatitude = "stationLat"
- const val keyLongitude = "stationLon"
- const val keyPositionGPS = "setPositionGPS"
- const val keyPositionQTH = "setPositionQTH"
- }
-
- fun loadStationPosition(): GeoPos {
- val defaultSP = "0.0"
- val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
- val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
- return GeoPos(latitude.toDouble(), longitude.toDouble())
- }
-
- private fun saveStationPosition(pos: GeoPos) {
- preferences.edit {
- putString(keyLatitude, pos.latitude.toString())
- putString(keyLongitude, pos.longitude.toString())
- }
- }
-
- fun updatePosition(latitude: Double, longitude: Double) {
- val stationPosition = GeoPos(latitude, longitude)
- saveStationPosition(stationPosition)
- }
-
- fun updatePositionFromGPS(): Boolean {
- return try {
- val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
- if (location == null) false
- else {
- val latitude = location.latitude.round(4)
- val longitude = location.longitude.round(4)
- val stationPosition = GeoPos(latitude, longitude)
- saveStationPosition(stationPosition)
- return true
- }
- } catch (exception: SecurityException) {
- false
- }
- }
-
- fun updatePositionFromQTH(qthString: String): Boolean {
- val position = QthConverter.qthToPosition(qthString) ?: return false
- val stationPosition = GeoPos(position.latitude, position.longitude)
- saveStationPosition(stationPosition)
- return true
- }
-
- fun getMagDeclination(): Float {
- val stationPosition = loadStationPosition()
- val lat = stationPosition.latitude.toFloat()
- val lon = stationPosition.longitude.toFloat()
- return GeomagneticField(lat, lon, 0f, System.currentTimeMillis()).declination
- }
-
- fun getHoursAhead(): Int {
- return preferences.getInt(keyHoursAhead, 8)
- }
-
- fun getMinElevation(): Double {
- return preferences.getInt(keyMinElevation, 16).toDouble()
- }
-
- fun getUseUTC(): Boolean {
- return preferences.getBoolean(keyTimeUTC, false)
- }
-
- fun setUseUTC(value: Boolean) {
- preferences.edit { putBoolean(keyTimeUTC, value) }
- }
-
- fun getUseCompass(): Boolean {
- return preferences.getBoolean(keyCompass, true)
- }
-
- fun setUseCompass(value: Boolean) {
- preferences.edit { putBoolean(keyCompass, value) }
- }
-
- fun getShowSweep(): Boolean {
- return preferences.getBoolean(keyRadarSweep, true)
- }
-
- fun setShowSweep(value: Boolean) {
- preferences.edit { putBoolean(keyRadarSweep, value) }
- }
-
- fun getSetupDone(): Boolean {
- return preferences.getBoolean(keyInitialSetup, false)
- }
-
- fun setSetupDone() {
- preferences.edit { putBoolean(keyInitialSetup, true) }
- }
-
- fun saveModesSelection(modes: List) {
- val modesSet = modes.toSet()
- preferences.edit {
- putStringSet(keyModes, modesSet)
- }
- }
-
- fun loadModesSelection(): List {
- preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
- return modesSet.toList().sorted()
- }
- return emptyList()
- }
-
- fun getRotatorEnabled(): Boolean {
- return preferences.getBoolean(keyRotator, false)
- }
-
- fun setRotatorEnabled(value: Boolean) {
- preferences.edit { putBoolean(keyRotator, value) }
- }
-
- fun getRotatorServer(): Pair {
- val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
- val port = preferences.getString(keyRotatorPort, null) ?: "4533"
- return Pair(address, port.toInt())
- }
-
- fun getRotatorIp(): String {
- return preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
- }
-
- fun setRotatorIp(value: String) {
- preferences.edit { putString(keyRotatorAddress, value) }
- }
-
- fun getRotatorPort(): String {
- return preferences.getString(keyRotatorPort, null) ?: "4533"
- }
-
- fun setRotatorPort(value: String) {
- preferences.edit { putString(keyRotatorPort, value) }
- }
-
- override fun loadDataSources(): List {
- val sourcesList = preferences.getStringSet(keyDataSources, null)?.toList()
- return if (sourcesList.isNullOrEmpty()) defaultSources else sourcesList.sortedDescending()
- }
-
- override fun saveDataSources(sources: List) {
- if (sources.isNotEmpty()) preferences.edit { putStringSet(keyDataSources, sources.toSet()) }
- }
-}
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/SettingsProvider.kt b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsProvider.kt
new file mode 100644
index 00000000..6f0facb9
--- /dev/null
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/SettingsProvider.kt
@@ -0,0 +1,156 @@
+/*
+ * Look4Sat. Amateur radio satellite tracker and pass predictor.
+ * Copyright (C) 2019-2021 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.BuildConfig
+import com.rtbishop.look4sat.data.SettingsHandler
+import com.rtbishop.look4sat.domain.predict.GeoPos
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SettingsProvider @Inject constructor(private val prefs: SharedPreferences) : SettingsHandler {
+
+ private val keyInitialSetup = "${BuildConfig.VERSION_NAME}update"
+
+ companion object {
+ const val keyDataSources = "dataSources"
+ const val keyModes = "satModes"
+ const val keyCompass = "compass"
+ const val keyRadarSweep = "radarSweep"
+ const val keyTimeUTC = "timeUTC"
+ const val keyHoursAhead = "hoursAhead"
+ const val keyMinElevation = "minElevation"
+ const val keyRotator = "isRotatorEnabled"
+ const val keyRotatorAddress = "rotatorAddress"
+ const val keyRotatorPort = "rotatorPort"
+ const val keyLatitude = "stationLat"
+ const val keyLongitude = "stationLon"
+ const val keyPositionGPS = "setPositionGPS"
+ const val keyPositionQTH = "setPositionQTH"
+ }
+
+ fun loadStationPosition(): GeoPos {
+ val defaultSP = "0.0"
+ val latitude = prefs.getString(keyLatitude, null) ?: defaultSP
+ val longitude = prefs.getString(keyLongitude, null) ?: defaultSP
+ return GeoPos(latitude.toDouble(), longitude.toDouble())
+ }
+
+ fun saveStationPosition(latitude: Double, longitude: Double) {
+ prefs.edit {
+ putString(keyLatitude, latitude.toString())
+ putString(keyLongitude, longitude.toString())
+ }
+ }
+
+ fun getHoursAhead(): Int {
+ return prefs.getInt(keyHoursAhead, 8)
+ }
+
+ fun getMinElevation(): Double {
+ return prefs.getInt(keyMinElevation, 16).toDouble()
+ }
+
+ fun getUseUTC(): Boolean {
+ return prefs.getBoolean(keyTimeUTC, false)
+ }
+
+ fun setUseUTC(value: Boolean) {
+ prefs.edit { putBoolean(keyTimeUTC, value) }
+ }
+
+ fun getUseCompass(): Boolean {
+ return prefs.getBoolean(keyCompass, true)
+ }
+
+ fun setUseCompass(value: Boolean) {
+ prefs.edit { putBoolean(keyCompass, value) }
+ }
+
+ fun getShowSweep(): Boolean {
+ return prefs.getBoolean(keyRadarSweep, true)
+ }
+
+ fun setShowSweep(value: Boolean) {
+ prefs.edit { putBoolean(keyRadarSweep, value) }
+ }
+
+ fun getSetupDone(): Boolean {
+ return prefs.getBoolean(keyInitialSetup, false)
+ }
+
+ fun setSetupDone() {
+ prefs.edit { putBoolean(keyInitialSetup, true) }
+ }
+
+ fun saveModesSelection(modes: List) {
+ val modesSet = modes.toSet()
+ prefs.edit {
+ putStringSet(keyModes, modesSet)
+ }
+ }
+
+ fun loadModesSelection(): List {
+ prefs.getStringSet(keyModes, setOf())?.let { modesSet ->
+ return modesSet.toList().sorted()
+ }
+ return emptyList()
+ }
+
+ fun getRotatorEnabled(): Boolean {
+ return prefs.getBoolean(keyRotator, false)
+ }
+
+ fun setRotatorEnabled(value: Boolean) {
+ prefs.edit { putBoolean(keyRotator, value) }
+ }
+
+ fun getRotatorServer(): Pair {
+ val address = prefs.getString(keyRotatorAddress, null) ?: "127.0.0.1"
+ val port = prefs.getString(keyRotatorPort, null) ?: "4533"
+ return Pair(address, port.toInt())
+ }
+
+ fun getRotatorIp(): String {
+ return prefs.getString(keyRotatorAddress, null) ?: "127.0.0.1"
+ }
+
+ fun setRotatorIp(value: String) {
+ prefs.edit { putString(keyRotatorAddress, value) }
+ }
+
+ fun getRotatorPort(): String {
+ return prefs.getString(keyRotatorPort, null) ?: "4533"
+ }
+
+ fun setRotatorPort(value: String) {
+ prefs.edit { putString(keyRotatorPort, value) }
+ }
+
+ override fun loadDataSources(): List {
+ val sourcesList = prefs.getStringSet(keyDataSources, null)?.toList()
+ return if (sourcesList.isNullOrEmpty()) defaultSources else sourcesList.sortedDescending()
+ }
+
+ override fun saveDataSources(sources: List) {
+ if (sources.isNotEmpty()) prefs.edit { putStringSet(keyDataSources, sources.toSet()) }
+ }
+}
diff --git a/app/src/main/java/com/rtbishop/look4sat/framework/local/EntriesDao.kt b/app/src/main/java/com/rtbishop/look4sat/framework/local/EntriesDao.kt
index 12fb6f78..147c224d 100644
--- a/app/src/main/java/com/rtbishop/look4sat/framework/local/EntriesDao.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/framework/local/EntriesDao.kt
@@ -39,9 +39,9 @@ interface EntriesDao {
suspend fun insertEntries(entries: List)
@Transaction
- suspend fun updateEntries(entries: List) {
+ suspend fun updateEntries(entries: List, cleanup: Boolean = false) {
val entriesSelection = getEntriesSelection()
- deleteEntries()
+ if (cleanup) deleteEntries()
insertEntries(entries)
restoreSelection(entriesSelection, true)
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/injection/CoreModule.kt b/app/src/main/java/com/rtbishop/look4sat/injection/CoreModule.kt
index 89f5c1b7..5710decb 100644
--- a/app/src/main/java/com/rtbishop/look4sat/injection/CoreModule.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/injection/CoreModule.kt
@@ -19,15 +19,16 @@ package com.rtbishop.look4sat.injection
import android.content.Context
import android.content.SharedPreferences
-import android.location.LocationManager
import androidx.room.Room
import com.rtbishop.look4sat.data.DefaultRepository
-import com.rtbishop.look4sat.data.PreferencesHandler
+import com.rtbishop.look4sat.data.SettingsHandler
import com.rtbishop.look4sat.domain.DataParser
import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.domain.DataRepository
+import com.rtbishop.look4sat.domain.LocationHandler
import com.rtbishop.look4sat.domain.predict.Predictor
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.LocationProvider
+import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.framework.local.LocalSource
import com.rtbishop.look4sat.framework.local.SatelliteDb
import com.rtbishop.look4sat.framework.remote.RemoteSource
@@ -46,7 +47,7 @@ object CoreModule {
@Provides
@Singleton
fun provideSatelliteRepo(
- preferencesHandler: PreferencesHandler,
+ settingsHandler: SettingsHandler,
@ApplicationContext context: Context,
@IoDispatcher ioDispatcher: CoroutineDispatcher,
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
@@ -56,16 +57,22 @@ object CoreModule {
.fallbackToDestructiveMigration().build()
val localSource = LocalSource(db.entriesDao(), db.transmittersDao())
val remoteSource = RemoteSource(ioDispatcher)
- return DefaultRepository(dataParser, localSource, remoteSource, preferencesHandler)
+ return DefaultRepository(dataParser, localSource, remoteSource, settingsHandler)
}
@Provides
@Singleton
- fun providePreferencesHandler(
- locationManager: LocationManager,
- sharedPreferences: SharedPreferences
- ): PreferencesHandler {
- return PreferencesSource(locationManager, sharedPreferences)
+ fun provideSettingsHandler(sharedPreferences: SharedPreferences): SettingsHandler {
+ return SettingsProvider(sharedPreferences)
+ }
+
+ @Provides
+ @Singleton
+ fun provideLocationHandler(
+ @ApplicationContext context: Context,
+ settingsProvider: SettingsProvider
+ ): LocationHandler {
+ return LocationProvider(context, settingsProvider)
}
@Provides
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt
index 8f2bb2ac..8b64ae3d 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt
@@ -89,8 +89,6 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
val message = getString(R.string.entries_update_error)
Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT).show()
}
- else -> {
- }
}
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt
index 1083fdbc..440fc2e5 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt
@@ -24,7 +24,7 @@ import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.model.SatItem
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
@@ -34,14 +34,14 @@ import javax.inject.Inject
@HiltViewModel
class EntriesViewModel @Inject constructor(
- private val preferences: PreferencesSource,
+ private val preferences: SettingsProvider,
private val resolver: ContentResolver,
private val dataRepository: DataRepository
) : ViewModel(), SearchView.OnQueryTextListener, EntriesAdapter.EntriesClickListener {
private val coroutineHandler = CoroutineExceptionHandler { _, throwable ->
Timber.d(throwable)
- _satData.value = DataState.Error(throwable)
+ _satData.value = DataState.Error(null)
}
private val transModes = MutableLiveData(preferences.loadModesSelection())
private val currentQuery = MutableLiveData(String())
@@ -64,7 +64,7 @@ class EntriesViewModel @Inject constructor(
resolver.openInputStream(uri)?.use { stream ->
dataRepository.updateDataFromFile(stream)
}
- }.onFailure { _satData.value = DataState.Error(it) }
+ }.onFailure { _satData.value = DataState.Error(null) }
}
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt
index 2bf6e576..e6f2cd04 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt
@@ -23,7 +23,7 @@ import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.Satellite
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import java.util.*
@@ -35,7 +35,7 @@ import kotlin.math.min
class MapViewModel @Inject constructor(
private val dataRepository: DataRepository,
private val predictor: Predictor,
- preferences: PreferencesSource,
+ preferences: SettingsProvider,
) : ViewModel() {
private val stationPos = preferences.loadStationPosition()
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesFragment.kt
index 55b4fd86..1c7f8681 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesFragment.kt
@@ -17,10 +17,8 @@
*/
package com.rtbishop.look4sat.presentation.passesScreen
-import android.Manifest
import android.os.Bundle
import android.view.View
-import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@@ -43,15 +41,15 @@ import java.util.*
class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesClickListener {
private val passesViewModel: PassesViewModel by viewModels()
- private val permReqContract = ActivityResultContracts.RequestMultiplePermissions()
- private val locPermFine = Manifest.permission.ACCESS_FINE_LOCATION
- private val locPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
- private val locPermReq = registerForActivityResult(permReqContract) { permissions ->
- when {
- permissions[locPermFine] == true -> passesViewModel.triggerInitialSetup()
- permissions[locPermCoarse] == true -> passesViewModel.triggerInitialSetup()
- }
- }
+// private val permReqContract = ActivityResultContracts.RequestMultiplePermissions()
+// private val locPermFine = Manifest.permission.ACCESS_FINE_LOCATION
+// private val locPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
+// private val locPermReq = registerForActivityResult(permReqContract) { permissions ->
+// when {
+// permissions[locPermFine] == true -> passesViewModel.triggerInitialSetup()
+// permissions[locPermCoarse] == true -> passesViewModel.triggerInitialSetup()
+// }
+// }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -88,7 +86,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
handleNewPasses(passesResult, passesAdapter, binding)
})
passesViewModel.isFirstLaunchDone.observe(viewLifecycleOwner, { setupDone ->
- if (!setupDone) locPermReq.launch(arrayOf(locPermFine, locPermCoarse))
+// if (!setupDone) locPermReq.launch(arrayOf(locPermFine, locPermCoarse))
})
getNavResult>(R.id.nav_passes, "prefs") { prefs ->
passesViewModel.forceCalculation(prefs.first, prefs.second)
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesPrefsDialog.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesPrefsDialog.kt
index 154d034e..2b070ffb 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesPrefsDialog.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesPrefsDialog.kt
@@ -8,7 +8,7 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogPassesBinding
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -17,7 +17,7 @@ import javax.inject.Inject
class PassesPrefsDialog : AppCompatDialogFragment() {
@Inject
- lateinit var preferences: PreferencesSource
+ lateinit var preferences: SettingsProvider
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_passes, group, false)
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt
index 2d6bbf4a..9e55afa4 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt
@@ -25,7 +25,7 @@ import com.rtbishop.look4sat.domain.DataRepository
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.SatPass
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import javax.inject.Inject
@@ -34,7 +34,7 @@ import javax.inject.Inject
class PassesViewModel @Inject constructor(
private val dataRepository: DataRepository,
private val predictor: Predictor,
- private val preferences: PreferencesSource
+ private val preferences: SettingsProvider
) : ViewModel() {
private val _passes = MutableLiveData>>()
@@ -66,7 +66,7 @@ class PassesViewModel @Inject constructor(
}
fun triggerInitialSetup() {
- preferences.updatePositionFromGPS()
+// preferences.updatePositionFromGPS()
viewModelScope.launch {
// _passes.postValue(DataState.Loading)
// val satellites = dataRepository.getSelectedSatellites()
@@ -115,8 +115,7 @@ class PassesViewModel @Inject constructor(
}
currentPasses = currentPasses.filter { it.progress < 100 }
val passesCopy = currentPasses.map { it.copy() }
- if (passesCopy.isEmpty()) _passes.postValue(DataState.Empty)
- else _passes.postValue(DataState.Success(passesCopy))
+ _passes.postValue(DataState.Success(passesCopy))
delay(1000)
}
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarFragment.kt
index 0863e9cd..a62f369f 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarFragment.kt
@@ -29,7 +29,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.presentation.navigateSafe
import com.rtbishop.look4sat.presentation.toTimerString
@@ -40,7 +40,7 @@ import javax.inject.Inject
class RadarFragment : Fragment(R.layout.fragment_radar) {
@Inject
- lateinit var preferences: PreferencesSource
+ lateinit var preferences: SettingsProvider
private val viewModel: RadarViewModel by viewModels()
private var radarView: RadarView? = null
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
index aa8d37eb..e5f294e1 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt
@@ -17,15 +17,17 @@
*/
package com.rtbishop.look4sat.presentation.radarScreen
+import android.hardware.GeomagneticField
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.domain.DataRepository
+import com.rtbishop.look4sat.domain.model.Transmitter
+import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
-import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.framework.OrientationSource
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.presentation.round
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
@@ -37,7 +39,7 @@ import javax.inject.Inject
@HiltViewModel
class RadarViewModel @Inject constructor(
private val orientationSource: OrientationSource,
- private val preferences: PreferencesSource,
+ private val preferences: SettingsProvider,
private val predictor: Predictor,
private val dataRepository: DataRepository,
private val dataReporter: DataReporter
@@ -71,7 +73,13 @@ class RadarViewModel @Inject constructor(
}
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
- _orientation.value = Triple(azimuth + preferences.getMagDeclination(), pitch, roll)
+ _orientation.value = Triple(azimuth + getMagDeclination(stationPos), pitch, roll)
+ }
+
+ private fun getMagDeclination(geoPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
+ val latitude = geoPos.latitude.toFloat()
+ val longitude = geoPos.longitude.toFloat()
+ return GeomagneticField(latitude, longitude, 0f, time).declination
}
private fun sendPassData(satPass: SatPass) {
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
index 03134d11..e7cb082a 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt
@@ -18,12 +18,8 @@
package com.rtbishop.look4sat.presentation.settingsScreen
import android.Manifest
-import android.content.Context
+import android.content.ContentResolver
import android.content.Intent
-import android.content.pm.PackageManager
-import android.location.Location
-import android.location.LocationListener
-import android.location.LocationManager
import android.net.Uri
import android.os.Bundle
import android.text.method.LinkMovementMethod
@@ -31,170 +27,161 @@ import android.view.View
import android.widget.EditText
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
-import androidx.core.content.ContextCompat
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
-import androidx.fragment.app.viewModels
+import androidx.lifecycle.asLiveData
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.android.material.snackbar.Snackbar
import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
-import com.rtbishop.look4sat.framework.PreferencesSource
+import com.rtbishop.look4sat.domain.DataRepository
+import com.rtbishop.look4sat.domain.LocationHandler
+import com.rtbishop.look4sat.domain.model.DataState
+import com.rtbishop.look4sat.domain.predict.GeoPos
+import com.rtbishop.look4sat.framework.SettingsProvider
import com.rtbishop.look4sat.presentation.*
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
-class SettingsFragment : Fragment(R.layout.fragment_settings), LocationListener {
+class SettingsFragment : Fragment(R.layout.fragment_settings) {
@Inject
- lateinit var preferences: PreferencesSource
+ lateinit var preferences: SettingsProvider
- private val viewModel: SettingsViewModel by viewModels()
- private val locPermFine = Manifest.permission.ACCESS_FINE_LOCATION
- private val locPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
- private val contentContract = ActivityResultContracts.GetContent()
- private val filePicker = registerForActivityResult(contentContract) { uri ->
- uri?.let { viewModel.updateDataFromFile(uri) }
- }
- private val permReqContract = ActivityResultContracts.RequestMultiplePermissions()
- private val locPermReq = registerForActivityResult(permReqContract) { permissions ->
+ @Inject
+ lateinit var locationHandler: LocationHandler
+
+ @Inject
+ lateinit var resolver: ContentResolver
+
+ @Inject
+ lateinit var dataRepository: DataRepository
+
+ private val locationFine = Manifest.permission.ACCESS_FINE_LOCATION
+ private val locationCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
+ private val locationContract = ActivityResultContracts.RequestMultiplePermissions()
+ private val locationRequest = registerForActivityResult(locationContract) { permissions ->
when {
- permissions[locPermFine] == true -> updatePositionFromGPS()
- permissions[locPermCoarse] == true -> updatePositionFromGPS()
+ permissions[locationFine] == true -> locationHandler.setPositionFromLocation()
+ permissions[locationCoarse] == true -> locationHandler.setPositionFromNet()
else -> showSnack(getString(R.string.pref_pos_gps_error))
}
}
- private var _binding: FragmentSettingsBinding? = null
+ private val contentContract = ActivityResultContracts.GetContent()
+ private val contentRequest = registerForActivityResult(contentContract) { uri ->
+ lifecycleScope.launchWhenResumed {
+ @Suppress("BlockingMethodInNonBlockingContext")
+ resolver.openInputStream(uri)?.use { dataRepository.updateDataFromFile(it) }
+ }
+ }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- _binding = FragmentSettingsBinding.bind(view)
- _binding?.prefsBack?.setOnClickListener { findNavController().navigateUp() }
- setupAboutCard()
- setupDataCard()
- setupLocationCard()
- setupTrackingCard()
- setupOtherCard()
- setupWarrantyCard()
- }
-
- private fun setupAboutCard() {
- _binding?.prefsInfo?.let { binding ->
- binding.aboutVersion.text =
- String.format(getString(R.string.about_version), BuildConfig.VERSION_NAME)
- binding.aboutBtnGithub.setOnClickListener {
- gotoUrl("https://github.com/rt-bishop/Look4Sat/")
- }
- binding.aboutBtnDonate.setOnClickListener {
- gotoUrl("https://www.buymeacoffee.com/rtbishop")
- }
- binding.aboutBtnFdroid.setOnClickListener {
- gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
- }
+ val settingsBinding = FragmentSettingsBinding.bind(view)
+ settingsBinding.prefsBack.setOnClickListener { findNavController().navigateUp() }
+ setupAboutCard(settingsBinding)
+ setupDataCard(settingsBinding)
+ setupLocationCard(settingsBinding)
+ setupTrackingCard(settingsBinding)
+ setupOtherCard(settingsBinding)
+ setupWarrantyCard(settingsBinding)
+ locationHandler.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
+ stationPos?.let { handleStationPosition(it) }
}
}
- private fun setupDataCard() {
- _binding?.prefsData?.let { binding ->
- binding.updateBtnWeb.setOnClickListener {
- findNavController().navigateSafe(R.id.action_prefs_to_sources)
- }
- binding.updateBtnFile.setOnClickListener { filePicker.launch("*/*") }
- getNavResult>(R.id.nav_prefs, "sources") { sources ->
- viewModel.updateDataFromWeb(sources)
- }
+ private fun setupAboutCard(binding: FragmentSettingsBinding) {
+ binding.prefsInfo.aboutVersion.text =
+ String.format(getString(R.string.about_version), BuildConfig.VERSION_NAME)
+ binding.prefsInfo.aboutBtnGithub.setOnClickListener {
+ gotoUrl("https://github.com/rt-bishop/Look4Sat/")
+ }
+ binding.prefsInfo.aboutBtnDonate.setOnClickListener {
+ gotoUrl("https://www.buymeacoffee.com/rtbishop")
+ }
+ binding.prefsInfo.aboutBtnFdroid.setOnClickListener {
+ gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
}
}
- private fun setupLocationCard() {
- _binding?.prefsLocation?.let { binding ->
- binding.locationBtnGps.setOnClickListener {
- updatePositionFromGPS()
- }
- binding.locationBtnQth.setOnClickListener {
- val editText = EditText(requireActivity())
- AlertDialog.Builder(requireContext())
- .setTitle("Title")
- .setEditText(editText)
- .setPositiveButton("OK") { _, _ ->
- val editTextInput = editText.text.toString()
- updatePositionFromQth(editTextInput)
- }
- .setNeutralButton("Cancel", null)
- .create()
- .show()
- }
+ private fun setupDataCard(binding: FragmentSettingsBinding) {
+ binding.prefsData.updateBtnFile.setOnClickListener { contentRequest.launch("*/*") }
+ binding.prefsData.updateBtnWeb.setOnClickListener {
+ findNavController().navigateSafe(R.id.action_prefs_to_sources)
+ }
+ getNavResult>(R.id.nav_prefs, "sources") { sources ->
+ lifecycleScope.launchWhenResumed { dataRepository.updateDataFromWeb(sources) }
}
}
- private fun setupTrackingCard() {
- _binding?.prefsTracking?.let { binding ->
- binding.trackingSwitch.apply {
- isChecked = preferences.getRotatorEnabled()
- binding.trackingIp.isEnabled = isChecked
- binding.trackingIpEdit.setText(preferences.getRotatorIp())
- binding.trackingPort.isEnabled = isChecked
- binding.trackingPortEdit.setText(preferences.getRotatorPort())
- setOnCheckedChangeListener { _, isChecked ->
- preferences.setRotatorEnabled(isChecked)
- binding.trackingIp.isEnabled = isChecked
- binding.trackingPort.isEnabled = isChecked
+ private fun setupLocationCard(binding: FragmentSettingsBinding) {
+ binding.prefsLocation.locationBtnGps.setOnClickListener {
+ locationRequest.launch(arrayOf(locationFine, locationCoarse))
+ }
+ binding.prefsLocation.locationBtnQth.setOnClickListener {
+ val editText = EditText(requireActivity())
+ AlertDialog.Builder(requireContext())
+ .setTitle("Title")
+ .setEditText(editText)
+ .setPositiveButton("OK") { _, _ ->
+ val editTextInput = editText.text.toString()
+ locationHandler.setPositionFromQth(editTextInput)
}
- }
- binding.trackingIpEdit.doOnTextChanged { text, _, _, _ ->
- if (text.toString().isValidIPv4()) preferences.setRotatorIp(text.toString())
- }
- binding.trackingPortEdit.doOnTextChanged { text, _, _, _ ->
- if (text.toString().isValidPort()) preferences.setRotatorPort(text.toString())
- }
+ .setNeutralButton("Cancel", null)
+ .create()
+ .show()
}
}
- private fun setupOtherCard() {
- _binding?.prefsOther?.let { binding ->
- binding.otherSwitchUtc.apply {
- isChecked = preferences.getUseUTC()
- setOnCheckedChangeListener { _, isChecked -> preferences.setUseUTC(isChecked) }
- }
- binding.otherSwitchSweep.apply {
- isChecked = preferences.getShowSweep()
- setOnCheckedChangeListener { _, isChecked -> preferences.setShowSweep(isChecked) }
- }
- binding.otherSwitchSensors.apply {
- isChecked = preferences.getUseCompass()
- setOnCheckedChangeListener { _, isChecked -> preferences.setUseCompass(isChecked) }
+ private fun setupTrackingCard(binding: FragmentSettingsBinding) {
+ binding.prefsTracking.trackingSwitch.apply {
+ isChecked = preferences.getRotatorEnabled()
+ binding.prefsTracking.trackingIp.isEnabled = isChecked
+ binding.prefsTracking.trackingIpEdit.setText(preferences.getRotatorIp())
+ binding.prefsTracking.trackingPort.isEnabled = isChecked
+ binding.prefsTracking.trackingPortEdit.setText(preferences.getRotatorPort())
+ setOnCheckedChangeListener { _, isChecked ->
+ preferences.setRotatorEnabled(isChecked)
+ binding.prefsTracking.trackingIp.isEnabled = isChecked
+ binding.prefsTracking.trackingPort.isEnabled = isChecked
}
}
+ binding.prefsTracking.trackingIpEdit.doOnTextChanged { text, _, _, _ ->
+ if (text.toString().isValidIPv4()) preferences.setRotatorIp(text.toString())
+ }
+ binding.prefsTracking.trackingPortEdit.doOnTextChanged { text, _, _, _ ->
+ if (text.toString().isValidPort()) preferences.setRotatorPort(text.toString())
+ }
}
- private fun setupWarrantyCard() {
- _binding?.prefsWarranty?.let { binding ->
- binding.warrantyThanks.movementMethod = LinkMovementMethod.getInstance()
- binding.warrantyLicense.movementMethod = LinkMovementMethod.getInstance()
+ private fun setupOtherCard(binding: FragmentSettingsBinding) {
+ binding.prefsOther.otherSwitchUtc.apply {
+ isChecked = preferences.getUseUTC()
+ setOnCheckedChangeListener { _, isChecked -> preferences.setUseUTC(isChecked) }
+ }
+ binding.prefsOther.otherSwitchSweep.apply {
+ isChecked = preferences.getShowSweep()
+ setOnCheckedChangeListener { _, isChecked -> preferences.setShowSweep(isChecked) }
+ }
+ binding.prefsOther.otherSwitchSensors.apply {
+ isChecked = preferences.getUseCompass()
+ setOnCheckedChangeListener { _, isChecked -> preferences.setUseCompass(isChecked) }
}
}
- private fun updatePositionFromGPS() {
- val manager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
- val provider = LocationManager.NETWORK_PROVIDER
- val permission = Manifest.permission.ACCESS_COARSE_LOCATION
- val result = ContextCompat.checkSelfPermission(requireContext(), permission)
- if (result == PackageManager.PERMISSION_GRANTED) {
- if (manager.isProviderEnabled(provider)) {
- manager.requestLocationUpdates(provider, 0L, 0f, this)
- } else {
- showSnack(getString(R.string.pref_pos_gps_null))
- }
- } else locPermReq.launch(arrayOf(locPermFine, locPermCoarse))
+ private fun setupWarrantyCard(binding: FragmentSettingsBinding) {
+ binding.prefsWarranty.warrantyThanks.movementMethod = LinkMovementMethod.getInstance()
+ binding.prefsWarranty.warrantyLicense.movementMethod = LinkMovementMethod.getInstance()
}
- private fun updatePositionFromQth(qthString: String) {
- if (preferences.updatePositionFromQTH(qthString)) {
- showSnack(getString(R.string.pref_pos_success))
- } else {
- showSnack(getString(R.string.pref_pos_qth_error))
+ private fun handleStationPosition(position: DataState) {
+ when (position) {
+ is DataState.Success -> showSnack(getString(R.string.pref_pos_success))
+ is DataState.Error -> showSnack(position.message.toString())
+ DataState.Loading -> showSnack("Fetching position")
}
}
@@ -205,18 +192,4 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), LocationListener
private fun gotoUrl(url: String) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
}
-
- override fun onDestroyView() {
- _binding = null
- super.onDestroyView()
- }
-
- override fun onLocationChanged(location: Location) {
- val manager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
- manager.removeUpdates(this)
- val latitude = location.latitude.round(4)
- val longitude = location.longitude.round(4)
- preferences.updatePosition(latitude, longitude)
- showSnack(getString(R.string.pref_pos_success))
- }
}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt
deleted file mode 100644
index 19c5e03f..00000000
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsViewModel.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Look4Sat. Amateur radio satellite tracker and pass predictor.
- * Copyright (C) 2019-2021 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.presentation.settingsScreen
-
-import android.content.ContentResolver
-import android.net.Uri
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.rtbishop.look4sat.domain.DataRepository
-import com.rtbishop.look4sat.framework.PreferencesSource
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.CoroutineExceptionHandler
-import kotlinx.coroutines.launch
-import javax.inject.Inject
-
-@HiltViewModel
-class SettingsViewModel @Inject constructor(
- private val preferences: PreferencesSource,
- private val resolver: ContentResolver,
- private val dataRepository: DataRepository
-) : ViewModel() {
-
- private val coroutineHandler = CoroutineExceptionHandler { _, throwable ->
-// Timber.d(throwable)
-// _satData.value = DataState.Error(throwable)
- }
-
- fun updateDataFromFile(uri: Uri) {
- viewModelScope.launch(coroutineHandler) {
-// _satData.value = DataState.Loading
- runCatching {
- resolver.openInputStream(uri)?.use { stream ->
- dataRepository.updateDataFromFile(stream)
- }
- }.onFailure {
-// _satData.value = DataState.Error(it)
- }
- }
- }
-
- fun updateDataFromWeb(sources: List) {
- viewModelScope.launch(coroutineHandler) {
-// _satData.value = DataState.Loading
- dataRepository.updateDataFromWeb(sources)
- }
- }
-}
diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/sourcesScreen/SourcesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/sourcesScreen/SourcesDialog.kt
index 3d437630..b6d3e6b2 100644
--- a/app/src/main/java/com/rtbishop/look4sat/presentation/sourcesScreen/SourcesDialog.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/presentation/sourcesScreen/SourcesDialog.kt
@@ -25,7 +25,7 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.rtbishop.look4sat.R
-import com.rtbishop.look4sat.data.PreferencesHandler
+import com.rtbishop.look4sat.data.SettingsHandler
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.presentation.setNavResult
@@ -36,7 +36,7 @@ import javax.inject.Inject
class SourcesDialog : AppCompatDialogFragment() {
@Inject
- lateinit var preferences: PreferencesHandler
+ lateinit var settings: SettingsHandler
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_sources, group, false)
@@ -44,7 +44,7 @@ class SourcesDialog : AppCompatDialogFragment() {
override fun onViewCreated(view: View, state: Bundle?) {
super.onViewCreated(view, state)
- val sources = preferences.loadDataSources()
+ val sources = settings.loadDataSources()
val sourcesAdapter = SourcesAdapter().apply { setSources(sources.map { Source(it) }) }
DialogSourcesBinding.bind(view).apply {
dialog?.window?.setLayout(
diff --git a/build.gradle b/build.gradle
index e4f87bc7..b967de6f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,7 @@ buildscript {
timber_version = '5.0.1'
junit_version = '4.13.2'
mockito_version = '4.2.0'
- leak_canary_version = '2.7'
+ leak_canary_version = '2.8'
}
repositories {
google()
diff --git a/core/src/main/java/com/rtbishop/look4sat/data/DefaultRepository.kt b/core/src/main/java/com/rtbishop/look4sat/data/DefaultRepository.kt
index dabc07ed..5f1b3e09 100644
--- a/core/src/main/java/com/rtbishop/look4sat/data/DefaultRepository.kt
+++ b/core/src/main/java/com/rtbishop/look4sat/data/DefaultRepository.kt
@@ -32,7 +32,7 @@ class DefaultRepository(
private val dataParser: DataParser,
private val localSource: LocalDataSource,
private val remoteSource: RemoteDataSource,
- private val preferences: PreferencesHandler
+ private val settings: SettingsHandler
) : DataRepository {
override fun getSatelliteItems() = localSource.getSatelliteItems()
@@ -48,7 +48,7 @@ class DefaultRepository(
override suspend fun updateDataFromWeb(sources: List) {
coroutineScope {
launch {
- preferences.saveDataSources(sources)
+ settings.saveDataSources(sources)
}
launch {
val updateTimeMillis = measureTimeMillis {
@@ -78,7 +78,7 @@ class DefaultRepository(
println("Update from web took $updateTimeMillis ms")
}
launch {
- remoteSource.fetchFileStream(preferences.transmittersSource)?.let { inputStream ->
+ remoteSource.fetchFileStream(settings.transmittersSource)?.let { inputStream ->
val transmitters = dataParser.parseJSONStream(inputStream)
localSource.updateTransmitters(transmitters)
}
diff --git a/core/src/main/java/com/rtbishop/look4sat/data/PreferencesHandler.kt b/core/src/main/java/com/rtbishop/look4sat/data/SettingsHandler.kt
similarity index 97%
rename from core/src/main/java/com/rtbishop/look4sat/data/PreferencesHandler.kt
rename to core/src/main/java/com/rtbishop/look4sat/data/SettingsHandler.kt
index 7ca2796c..bbe4bfa5 100644
--- a/core/src/main/java/com/rtbishop/look4sat/data/PreferencesHandler.kt
+++ b/core/src/main/java/com/rtbishop/look4sat/data/SettingsHandler.kt
@@ -17,7 +17,7 @@
*/
package com.rtbishop.look4sat.data
-interface PreferencesHandler {
+interface SettingsHandler {
val defaultSources: List
get() = listOf(
diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/LocationHandler.kt b/core/src/main/java/com/rtbishop/look4sat/domain/LocationHandler.kt
new file mode 100644
index 00000000..70b24710
--- /dev/null
+++ b/core/src/main/java/com/rtbishop/look4sat/domain/LocationHandler.kt
@@ -0,0 +1,22 @@
+package com.rtbishop.look4sat.domain
+
+import com.rtbishop.look4sat.domain.model.DataState
+import com.rtbishop.look4sat.domain.predict.GeoPos
+import kotlinx.coroutines.flow.SharedFlow
+
+interface LocationHandler {
+
+ val stationPosition: SharedFlow>
+
+ fun getStationPosition(): GeoPos
+
+ fun setStationPosition(latitude: Double, longitude: Double)
+
+ fun setPositionFromLocation()
+
+ fun setPositionFromNet()
+
+ fun setPositionFromGps()
+
+ fun setPositionFromQth(qthString: String)
+}
diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/LocationProvider.kt b/core/src/main/java/com/rtbishop/look4sat/domain/LocationProvider.kt
deleted file mode 100644
index 8ec48454..00000000
--- a/core/src/main/java/com/rtbishop/look4sat/domain/LocationProvider.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.rtbishop.look4sat.domain
-
-import com.rtbishop.look4sat.domain.predict.GeoPos
-import kotlinx.coroutines.flow.SharedFlow
-
-interface LocationProvider {
-
- val updatedLocation: SharedFlow
-}
diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/model/DataState.kt b/core/src/main/java/com/rtbishop/look4sat/domain/model/DataState.kt
index b5263a17..8430df72 100644
--- a/core/src/main/java/com/rtbishop/look4sat/domain/model/DataState.kt
+++ b/core/src/main/java/com/rtbishop/look4sat/domain/model/DataState.kt
@@ -19,7 +19,6 @@ package com.rtbishop.look4sat.domain.model
sealed class DataState {
data class Success(val data: T) : DataState()
- data class Error(val error: Throwable) : DataState()
- object Empty : DataState()
+ data class Error(val message: String?) : DataState()
object Loading : DataState()
}
diff --git a/core/src/test/java/com/rtbishop/look4sat/DataParserTest.kt b/core/src/test/java/com/rtbishop/look4sat/DataParserTest.kt
index 4e245cf7..d38ffbfb 100644
--- a/core/src/test/java/com/rtbishop/look4sat/DataParserTest.kt
+++ b/core/src/test/java/com/rtbishop/look4sat/DataParserTest.kt
@@ -84,8 +84,6 @@ class DataParserTest {
fun `Given valid data streams parsed results match`() = runTest(testDispatcher) {
val csvResult = dataParser.parseCSVStream(validCSVStream)
val tleResult = dataParser.parseTLEStream(validTLEStream)
- println(csvResult)
- println(tleResult)
assert(csvResult == tleResult)
}