mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Repositories refactoring and merge
This commit is contained in:
1 parent
1a59b5e3e1
commit
0110de8104
28 files changed
+309
-577
No files matched your search
@@ -23,7 +23,7 @@ import android.location.LocationManager
|
|||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import com.rtbishop.look4sat.data.*
|
import com.rtbishop.look4sat.data.*
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||||
import com.rtbishop.look4sat.framework.DefaultLocationSource
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import com.rtbishop.look4sat.framework.api.NetworkDataSource
|
import com.rtbishop.look4sat.framework.api.NetworkDataSource
|
||||||
import com.rtbishop.look4sat.framework.api.SatelliteService
|
import com.rtbishop.look4sat.framework.api.SatelliteService
|
||||||
import com.rtbishop.look4sat.framework.db.RoomConverters
|
import com.rtbishop.look4sat.framework.db.RoomConverters
|
||||||
@@ -52,20 +52,21 @@ object DataSourceModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideLocationSource(
|
fun providePreferenceSource(
|
||||||
|
qthConverter: QthConverter,
|
||||||
locationManager: LocationManager,
|
locationManager: LocationManager,
|
||||||
preferences: SharedPreferences
|
preferences: SharedPreferences
|
||||||
): LocationSource {
|
): PreferenceSource {
|
||||||
return DefaultLocationSource(locationManager, preferences)
|
return PreferencesProvider(qthConverter, locationManager, preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideLocationRepo(
|
fun providePassesRepo(
|
||||||
locationSource: LocationSource,
|
preferenceSource: PreferenceSource,
|
||||||
qthConverter: QthConverter
|
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
||||||
): LocationRepo {
|
): PassesRepo {
|
||||||
return LocationRepo(locationSource, qthConverter)
|
return PassesRepo(preferenceSource, defaultDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -39,18 +39,18 @@ object InteractorsModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideGetTransmittersForSatUseCase(satelliteRepo: SatelliteRepo): GetTransmittersForSat {
|
fun provideGetSatTransmittersUseCase(satelliteRepo: SatelliteRepo): GetSatTransmitters {
|
||||||
return GetTransmittersForSat(satelliteRepo)
|
return GetSatTransmitters(satelliteRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideImportDataFromStreamUseCase(satelliteRepo: SatelliteRepo): ImportDataFromStream {
|
fun provideUpdateEntriesFromFileUseCase(satelliteRepo: SatelliteRepo): UpdateEntriesFromFile {
|
||||||
return ImportDataFromStream(satelliteRepo)
|
return UpdateEntriesFromFile(satelliteRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideImportDataFromWebUseCase(satelliteRepo: SatelliteRepo): ImportDataFromWeb {
|
fun provideUpdateEntriesFromWebUseCase(satelliteRepo: SatelliteRepo): UpdateEntriesFromWeb {
|
||||||
return ImportDataFromWeb(satelliteRepo)
|
return UpdateEntriesFromWeb(satelliteRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
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.data.LocationSource
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
|
||||||
import com.rtbishop.look4sat.utility.round
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class DefaultLocationSource @Inject constructor(
|
|
||||||
private val locationManager: LocationManager,
|
|
||||||
private val preferences: SharedPreferences
|
|
||||||
) : LocationSource {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val keyLatitude = "stationLat"
|
|
||||||
const val keyLongitude = "stationLon"
|
|
||||||
const val keyAltitude = "stationAlt"
|
|
||||||
const val keyPositionGPS = "setPositionGPS"
|
|
||||||
const val keyPositionQTH = "setPositionQTH"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLastKnownLocation(): StationPosition? {
|
|
||||||
return try {
|
|
||||||
val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
|
|
||||||
if (location == null) null
|
|
||||||
else {
|
|
||||||
val latitude = location.latitude.round(4)
|
|
||||||
val longitude = location.longitude.round(4)
|
|
||||||
val altitude = location.altitude.round(1)
|
|
||||||
return StationPosition(latitude, longitude, altitude)
|
|
||||||
}
|
|
||||||
} catch (exception: SecurityException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMagDeclination(position: StationPosition): Float {
|
|
||||||
val lat = position.latitude.toFloat()
|
|
||||||
val lon = position.longitude.toFloat()
|
|
||||||
val alt = position.altitude.toFloat()
|
|
||||||
return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadStationPosition(): StationPosition {
|
|
||||||
val defaultSP = "0.0"
|
|
||||||
val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
|
|
||||||
val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
|
|
||||||
val altitude = preferences.getString(keyAltitude, null) ?: defaultSP
|
|
||||||
return StationPosition(latitude.toDouble(), longitude.toDouble(), altitude.toDouble())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveStationPosition(position: StationPosition) {
|
|
||||||
preferences.edit {
|
|
||||||
putString(keyLatitude, position.latitude.toString())
|
|
||||||
putString(keyLongitude, position.longitude.toString())
|
|
||||||
putString(keyAltitude, position.altitude.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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.data.PreferenceSource
|
||||||
|
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||||
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
|
import com.rtbishop.look4sat.utility.round
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PreferencesProvider @Inject constructor(
|
||||||
|
private val qthConverter: QthConverter,
|
||||||
|
private val locationManager: LocationManager,
|
||||||
|
private val preferences: SharedPreferences
|
||||||
|
) : PreferenceSource {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val keyModes = "satModes"
|
||||||
|
const val keyCompass = "compass"
|
||||||
|
const val keyTextLabels = "shouldUseTextLabels"
|
||||||
|
const val keyTimeUTC = "timeUTC"
|
||||||
|
const val keyHoursAhead = "hoursAhead"
|
||||||
|
const val keyMinElevation = "minElevation"
|
||||||
|
const val keyIsFirstLaunch = "shouldShowSplash"
|
||||||
|
const val keyRotator = "isRotatorEnabled"
|
||||||
|
const val keyRotatorAddress = "rotatorAddress"
|
||||||
|
const val keyRotatorPort = "rotatorPort"
|
||||||
|
const val keyLatitude = "stationLat"
|
||||||
|
const val keyLongitude = "stationLon"
|
||||||
|
const val keyAltitude = "stationAlt"
|
||||||
|
const val keyPositionGPS = "setPositionGPS"
|
||||||
|
const val keyPositionQTH = "setPositionQTH"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun positionToQTH(lat: Double, lon: Double): String? {
|
||||||
|
return qthConverter.positionToQTH(lat, lon)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadStationPosition(): StationPosition {
|
||||||
|
val defaultSP = "0.0"
|
||||||
|
val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
|
||||||
|
val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
|
||||||
|
val altitude = preferences.getString(keyAltitude, null) ?: defaultSP
|
||||||
|
return StationPosition(latitude.toDouble(), longitude.toDouble(), altitude.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveStationPosition(position: StationPosition) {
|
||||||
|
preferences.edit {
|
||||||
|
putString(keyLatitude, position.latitude.toString())
|
||||||
|
putString(keyLongitude, position.longitude.toString())
|
||||||
|
putString(keyAltitude, position.altitude.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override 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 altitude = location.altitude.round(1)
|
||||||
|
val stationPosition = StationPosition(latitude, longitude, altitude)
|
||||||
|
saveStationPosition(stationPosition)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch (exception: SecurityException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updatePositionFromQTH(qthString: String): Boolean {
|
||||||
|
val position = qthConverter.qthToPosition(qthString) ?: return false
|
||||||
|
val stationPosition = StationPosition(position.latitude, position.longitude, 0.0)
|
||||||
|
saveStationPosition(stationPosition)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMagDeclination(): Float {
|
||||||
|
val stationPosition = loadStationPosition()
|
||||||
|
val lat = stationPosition.latitude.toFloat()
|
||||||
|
val lon = stationPosition.longitude.toFloat()
|
||||||
|
val alt = stationPosition.altitude.toFloat()
|
||||||
|
return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHoursAhead(): Int {
|
||||||
|
return preferences.getInt(keyHoursAhead, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMinElevation(): Double {
|
||||||
|
return preferences.getInt(keyMinElevation, 16).toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldUseTextLabels(): Boolean {
|
||||||
|
return preferences.getBoolean(keyTextLabels, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldUseUTC(): Boolean {
|
||||||
|
return preferences.getBoolean(keyTimeUTC, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldUseCompass(): Boolean {
|
||||||
|
return preferences.getBoolean(keyCompass, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isFirstLaunch(): Boolean {
|
||||||
|
return preferences.getBoolean(keyIsFirstLaunch, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setFirstLaunchDone() {
|
||||||
|
preferences.edit { putBoolean(keyIsFirstLaunch, false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveModesSelection(modes: List<String>) {
|
||||||
|
val modesSet = modes.toSet()
|
||||||
|
preferences.edit {
|
||||||
|
putStringSet(keyModes, modesSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadModesSelection(): List<String> {
|
||||||
|
preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
|
||||||
|
return modesSet.toList().sorted()
|
||||||
|
}
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRotatorServer(): Pair<String, Int>? {
|
||||||
|
return if (preferences.getBoolean(keyRotator, false)) {
|
||||||
|
val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
|
||||||
|
val port = preferences.getString(keyRotatorPort, null) ?: "4096"
|
||||||
|
Pair(address, port.toInt())
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,124 +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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.framework
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import com.rtbishop.look4sat.framework.model.TleSource
|
|
||||||
import com.squareup.moshi.Moshi
|
|
||||||
import com.squareup.moshi.Types
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class PrefsManager @Inject constructor(private val preferences: SharedPreferences, moshi: Moshi) {
|
|
||||||
|
|
||||||
private val sourcesType = Types.newParameterizedType(List::class.java, TleSource::class.java)
|
|
||||||
private val sourcesAdapter = moshi.adapter<List<TleSource>>(sourcesType)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val keySources = "sourcesListJson"
|
|
||||||
const val keyModes = "satModes"
|
|
||||||
const val keyCompass = "compass"
|
|
||||||
const val keyTextLabels = "shouldUseTextLabels"
|
|
||||||
const val keyTimeUTC = "timeUTC"
|
|
||||||
const val keyHoursAhead = "hoursAhead"
|
|
||||||
const val keyMinElevation = "minElevation"
|
|
||||||
const val keyIsFirstLaunch = "shouldShowSplash"
|
|
||||||
const val keyRotator = "isRotatorEnabled"
|
|
||||||
const val keyRotatorAddress = "rotatorAddress"
|
|
||||||
const val keyRotatorPort = "rotatorPort"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getHoursAhead(): Int {
|
|
||||||
return preferences.getInt(keyHoursAhead, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMinElevation(): Double {
|
|
||||||
return preferences.getInt(keyMinElevation, 16).toDouble()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldUseTextLabels(): Boolean {
|
|
||||||
return preferences.getBoolean(keyTextLabels, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldUseUTC(): Boolean {
|
|
||||||
return preferences.getBoolean(keyTimeUTC, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldUseCompass(): Boolean {
|
|
||||||
return preferences.getBoolean(keyCompass, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isFirstLaunch(): Boolean {
|
|
||||||
return preferences.getBoolean(keyIsFirstLaunch, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setFirstLaunchDone() {
|
|
||||||
preferences.edit { putBoolean(keyIsFirstLaunch, false) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadTleSources(): List<TleSource> {
|
|
||||||
return try {
|
|
||||||
val sourcesString = preferences.getString(keySources, String())
|
|
||||||
if (sourcesString.isNullOrEmpty()) {
|
|
||||||
loadDefaultSources()
|
|
||||||
} else {
|
|
||||||
sourcesAdapter.fromJson(sourcesString) ?: loadDefaultSources()
|
|
||||||
}
|
|
||||||
} catch (exception: ClassCastException) {
|
|
||||||
loadDefaultSources()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveTleSources(sources: List<TleSource>) {
|
|
||||||
val sourcesJson = sourcesAdapter.toJson(sources)
|
|
||||||
preferences.edit { putString(keySources, sourcesJson) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadDefaultSources(): List<TleSource> {
|
|
||||||
return listOf(
|
|
||||||
TleSource("https://celestrak.com/NORAD/elements/active.txt"),
|
|
||||||
TleSource("https://amsat.org/tle/current/nasabare.txt"),
|
|
||||||
TleSource("https://www.prismnet.com/~mmccants/tles/classfd.zip"),
|
|
||||||
TleSource("https://www.prismnet.com/~mmccants/tles/inttles.zip")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveModesSelection(modes: List<String>) {
|
|
||||||
val modesSet = modes.toSet()
|
|
||||||
preferences.edit {
|
|
||||||
putStringSet(keyModes, modesSet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadModesSelection(): List<String> {
|
|
||||||
preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
|
|
||||||
return modesSet.toList().sorted()
|
|
||||||
}
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getRotatorServer(): Pair<String, Int>? {
|
|
||||||
return if (preferences.getBoolean(keyRotator, false)) {
|
|
||||||
val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
|
|
||||||
val port = preferences.getString(keyRotatorPort, null) ?: "4096"
|
|
||||||
Pair(address, port.toInt())
|
|
||||||
} else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ class RoomDataSource(private val satelliteDao: SatelliteDao) : LocalDataSource {
|
|||||||
satelliteDao.updateEntriesSelection(catNums, isSelected)
|
satelliteDao.updateEntriesSelection(catNums, isSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>> {
|
override fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||||
return satelliteDao.getSatTransmitters(catNum)
|
return satelliteDao.getSatTransmitters(catNum)
|
||||||
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
|
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.framework.model
|
|
||||||
|
|
||||||
class TleSource(var url: String = String())
|
|
||||||
@@ -25,7 +25,7 @@ import androidx.navigation.fragment.NavHostFragment
|
|||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import com.rtbishop.look4sat.utility.navigateSafe
|
import com.rtbishop.look4sat.utility.navigateSafe
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -34,7 +34,7 @@ import javax.inject.Inject
|
|||||||
class Look4SatActivity : AppCompatActivity() {
|
class Look4SatActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var prefsManager: PrefsManager
|
lateinit var preferenceSource: PreferencesProvider
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -45,8 +45,8 @@ class Look4SatActivity : AppCompatActivity() {
|
|||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
|
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
|
||||||
binding.navBottom.setupWithNavController(navHost.navController)
|
binding.navBottom.setupWithNavController(navHost.navController)
|
||||||
if (prefsManager.isFirstLaunch()) {
|
if (preferenceSource.isFirstLaunch()) {
|
||||||
prefsManager.setFirstLaunchDone()
|
preferenceSource.setFirstLaunchDone()
|
||||||
navHost.navController.navigateSafe(R.id.nav_dialog_splash)
|
navHost.navController.navigateSafe(R.id.nav_dialog_splash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-20
@@ -22,18 +22,14 @@ import android.view.View
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
|
||||||
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
import com.rtbishop.look4sat.framework.model.TleSource
|
import com.rtbishop.look4sat.framework.model.Result
|
||||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
import com.rtbishop.look4sat.utility.getNavResult
|
|
||||||
import com.rtbishop.look4sat.utility.navigateSafe
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@@ -42,7 +38,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
|||||||
private val viewModel: EntriesViewModel by viewModels()
|
private val viewModel: EntriesViewModel by viewModels()
|
||||||
private val contentContract = ActivityResultContracts.GetContent()
|
private val contentContract = ActivityResultContracts.GetContent()
|
||||||
private val filePicker = registerForActivityResult(contentContract) { uri ->
|
private val filePicker = registerForActivityResult(contentContract) { uri ->
|
||||||
uri?.let { viewModel.importSatDataFromFile(uri) }
|
uri?.let { viewModel.updateEntriesFromFile(uri) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -62,9 +58,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
|||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light))
|
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light))
|
||||||
}
|
}
|
||||||
importWeb.setOnClickListener {
|
importWeb.setOnClickListener { viewModel.updateEntriesFromWeb(null) }
|
||||||
findNavController().navigateSafe(R.id.action_entries_to_sources)
|
|
||||||
}
|
|
||||||
importFile.setOnClickListener { filePicker.launch("*/*") }
|
importFile.setOnClickListener { filePicker.launch("*/*") }
|
||||||
selectMode.setOnClickListener { viewModel.createModesDialog(requireContext()).show() }
|
selectMode.setOnClickListener { viewModel.createModesDialog(requireContext()).show() }
|
||||||
selectAll.setOnClickListener { viewModel.selectCurrentItems() }
|
selectAll.setOnClickListener { viewModel.selectCurrentItems() }
|
||||||
@@ -73,9 +67,6 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
|||||||
viewModel.satData.observe(viewLifecycleOwner, { satData ->
|
viewModel.satData.observe(viewLifecycleOwner, { satData ->
|
||||||
handleSatData(satData, binding, entriesAdapter)
|
handleSatData(satData, binding, entriesAdapter)
|
||||||
})
|
})
|
||||||
getNavResult<List<String>>(R.id.nav_entries, "sources") { navResult ->
|
|
||||||
handleNavResult(navResult)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSatData(
|
private fun handleSatData(
|
||||||
@@ -97,15 +88,11 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
|||||||
is Result.Error -> {
|
is Result.Error -> {
|
||||||
binding.entriesProgress.visibility = View.INVISIBLE
|
binding.entriesProgress.visibility = View.INVISIBLE
|
||||||
binding.entriesRecycler.visibility = View.VISIBLE
|
binding.entriesRecycler.visibility = View.VISIBLE
|
||||||
Snackbar.make(requireView(), R.string.entries_update_error, Snackbar.LENGTH_SHORT)
|
val errorMsg = getString(R.string.entries_update_error)
|
||||||
.setAnchorView(R.id.nav_bottom).show()
|
Snackbar.make(requireView(), errorMsg, Snackbar.LENGTH_SHORT).apply {
|
||||||
|
setAnchorView(R.id.nav_bottom)
|
||||||
|
}.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNavResult(result: List<String>) {
|
|
||||||
result.map { sourceUrl -> TleSource(sourceUrl) }.let { sources ->
|
|
||||||
viewModel.importSatDataFromSources(sources)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+16
-29
@@ -26,32 +26,29 @@ import androidx.lifecycle.*
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.Result
|
||||||
import com.rtbishop.look4sat.framework.model.TleSource
|
|
||||||
import com.rtbishop.look4sat.interactors.GetSatItems
|
import com.rtbishop.look4sat.interactors.GetSatItems
|
||||||
import com.rtbishop.look4sat.interactors.ImportDataFromStream
|
import com.rtbishop.look4sat.interactors.UpdateEntriesFromFile
|
||||||
import com.rtbishop.look4sat.interactors.ImportDataFromWeb
|
import com.rtbishop.look4sat.interactors.UpdateEntriesFromWeb
|
||||||
import com.rtbishop.look4sat.interactors.UpdateEntriesSelection
|
import com.rtbishop.look4sat.interactors.UpdateEntriesSelection
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class EntriesViewModel @Inject constructor(
|
class EntriesViewModel @Inject constructor(
|
||||||
private val prefsManager: PrefsManager,
|
private val preferenceSource: PreferencesProvider,
|
||||||
private val resolver: ContentResolver,
|
private val resolver: ContentResolver,
|
||||||
private val getSatItems: GetSatItems,
|
private val getSatItems: GetSatItems,
|
||||||
private val importDataFromStream: ImportDataFromStream,
|
private val updateEntriesFromFile: UpdateEntriesFromFile,
|
||||||
private val importDataFromWeb: ImportDataFromWeb,
|
private val updateEntriesFromWeb: UpdateEntriesFromWeb,
|
||||||
private val updateEntriesSelection: UpdateEntriesSelection,
|
private val updateEntriesSelection: UpdateEntriesSelection,
|
||||||
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
private val transModes = MutableLiveData(prefsManager.loadModesSelection())
|
private val transModes = MutableLiveData(preferenceSource.loadModesSelection())
|
||||||
private val currentQuery = MutableLiveData(String())
|
private val currentQuery = MutableLiveData(String())
|
||||||
private val itemsWithModes = transModes.switchMap { modes ->
|
private val itemsWithModes = transModes.switchMap { modes ->
|
||||||
liveData { getSatItems().collect { emit(filterByModes(it, modes)) } }
|
liveData { getSatItems().collect { emit(filterByModes(it, modes)) } }
|
||||||
@@ -65,32 +62,22 @@ class EntriesViewModel @Inject constructor(
|
|||||||
private var shouldSelectAll = true
|
private var shouldSelectAll = true
|
||||||
val satData: LiveData<Result<List<SatItem>>> = _satData
|
val satData: LiveData<Result<List<SatItem>>> = _satData
|
||||||
|
|
||||||
fun importSatDataFromFile(uri: Uri) {
|
fun updateEntriesFromFile(uri: Uri) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_satData.value = Result.InProgress
|
_satData.value = Result.InProgress
|
||||||
runCatching {
|
runCatching {
|
||||||
resolver.openInputStream(uri)?.use { stream ->
|
resolver.openInputStream(uri)?.use { stream -> updateEntriesFromFile(stream) }
|
||||||
importDataFromStream(stream)
|
|
||||||
}
|
|
||||||
}.onFailure { _satData.value = Result.Error(it) }
|
}.onFailure { _satData.value = Result.Error(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun importSatDataFromSources(sources: List<TleSource>) {
|
fun updateEntriesFromWeb(sources: List<String>?) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_satData.value = Result.InProgress
|
_satData.value = Result.InProgress
|
||||||
val satSources = if (sources.isNotEmpty()) sources
|
runCatching {
|
||||||
else prefsManager.loadDefaultSources()
|
if (sources == null) updateEntriesFromWeb()
|
||||||
val updateMillis = measureTimeMillis {
|
else updateEntriesFromWeb(sources)
|
||||||
try {
|
}.onFailure { _satData.value = Result.Error(it) }
|
||||||
prefsManager.saveTleSources(satSources)
|
|
||||||
importDataFromWeb(satSources.map { it.url })
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
_satData.value = Result.Error(exception)
|
|
||||||
Timber.d(exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timber.d("Update from WEB took $updateMillis ms")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +98,7 @@ class EntriesViewModel @Inject constructor(
|
|||||||
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
|
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
|
||||||
)
|
)
|
||||||
val savedModes = BooleanArray(modes.size)
|
val savedModes = BooleanArray(modes.size)
|
||||||
val selectedModes = prefsManager.loadModesSelection().toMutableList()
|
val selectedModes = preferenceSource.loadModesSelection().toMutableList()
|
||||||
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
|
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(context).apply {
|
val dialogBuilder = MaterialAlertDialogBuilder(context).apply {
|
||||||
setTitle(context.getString(R.string.modes_title))
|
setTitle(context.getString(R.string.modes_title))
|
||||||
@@ -123,7 +110,7 @@ class EntriesViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
setPositiveButton(context.getString(android.R.string.ok)) { _, _ ->
|
setPositiveButton(context.getString(android.R.string.ok)) { _, _ ->
|
||||||
transModes.value = selectedModes
|
transModes.value = selectedModes
|
||||||
prefsManager.saveModesSelection(selectedModes)
|
preferenceSource.saveModesSelection(selectedModes)
|
||||||
}
|
}
|
||||||
setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ ->
|
setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
|||||||
@@ -18,14 +18,13 @@
|
|||||||
package com.rtbishop.look4sat.presentation.mapScreen
|
package com.rtbishop.look4sat.presentation.mapScreen
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import com.rtbishop.look4sat.data.LocationRepo
|
import com.rtbishop.look4sat.data.PreferenceSource
|
||||||
import com.rtbishop.look4sat.di.DefaultDispatcher
|
import com.rtbishop.look4sat.di.DefaultDispatcher
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Position
|
import com.rtbishop.look4sat.domain.predict4kotlin.Position
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
import com.rtbishop.look4sat.framework.model.SatData
|
import com.rtbishop.look4sat.framework.model.SatData
|
||||||
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -38,12 +37,11 @@ import kotlin.math.sqrt
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MapViewModel @Inject constructor(
|
class MapViewModel @Inject constructor(
|
||||||
private val getSelectedSatellites: GetSelectedSatellites,
|
private val getSelectedSatellites: GetSelectedSatellites,
|
||||||
private val prefsManager: PrefsManager,
|
private val preferenceSource: PreferenceSource,
|
||||||
private val locationRepo: LocationRepo,
|
|
||||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val gsp = locationRepo.getStationPosition()
|
private val gsp = preferenceSource.loadStationPosition()
|
||||||
private var dataUpdateJob: Job? = null
|
private var dataUpdateJob: Job? = null
|
||||||
private var allSatList = listOf<Satellite>()
|
private var allSatList = listOf<Satellite>()
|
||||||
private lateinit var selectedSat: Satellite
|
private lateinit var selectedSat: Satellite
|
||||||
@@ -78,7 +76,7 @@ class MapViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shouldUseTextLabels(): Boolean {
|
fun shouldUseTextLabels(): Boolean {
|
||||||
return prefsManager.shouldUseTextLabels()
|
return preferenceSource.shouldUseTextLabels()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollSelection(decrement: Boolean) {
|
fun scrollSelection(decrement: Boolean) {
|
||||||
@@ -172,7 +170,8 @@ class MapViewModel @Inject constructor(
|
|||||||
val osmLat = getOsmLat(Math.toDegrees(satPos.latitude))
|
val osmLat = getOsmLat(Math.toDegrees(satPos.latitude))
|
||||||
val osmLon = getOsmLon(Math.toDegrees(satPos.longitude))
|
val osmLon = getOsmLon(Math.toDegrees(satPos.longitude))
|
||||||
val osmPos = Position(osmLat, osmLon)
|
val osmPos = Position(osmLat, osmLon)
|
||||||
val qthLoc = locationRepo.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
val qthLoc =
|
||||||
|
preferenceSource.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
||||||
val velocity = getOrbitalVelocity(satPos.altitude)
|
val velocity = getOrbitalVelocity(satPos.altitude)
|
||||||
val satData = SatData(
|
val satData = SatData(
|
||||||
sat, sat.tle.catnum, sat.tle.name, satPos.range,
|
sat, sat.tle.catnum, sat.tle.name, satPos.range,
|
||||||
|
|||||||
+4
-4
@@ -22,10 +22,10 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.Result
|
||||||
import com.rtbishop.look4sat.utility.PassesRepo
|
import com.rtbishop.look4sat.data.PassesRepo
|
||||||
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
@@ -35,7 +35,7 @@ import javax.inject.Inject
|
|||||||
class PassesViewModel @Inject constructor(
|
class PassesViewModel @Inject constructor(
|
||||||
private val getSelectedSatellites: GetSelectedSatellites,
|
private val getSelectedSatellites: GetSelectedSatellites,
|
||||||
private val passesRepo: PassesRepo,
|
private val passesRepo: PassesRepo,
|
||||||
private val prefsManager: PrefsManager
|
private val preferenceSource: PreferencesProvider
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
||||||
@@ -64,7 +64,7 @@ class PassesViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shouldUseUTC(): Boolean {
|
fun shouldUseUTC(): Boolean {
|
||||||
return prefsManager.shouldUseUTC()
|
return preferenceSource.shouldUseUTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun tickPasses(passes: List<SatPass>) = withContext(Dispatchers.Default) {
|
private suspend fun tickPasses(passes: List<SatPass>) = withContext(Dispatchers.Default) {
|
||||||
|
|||||||
+10
-12
@@ -18,14 +18,13 @@
|
|||||||
package com.rtbishop.look4sat.presentation.polarScreen
|
package com.rtbishop.look4sat.presentation.polarScreen
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import com.rtbishop.look4sat.data.LocationRepo
|
import com.rtbishop.look4sat.data.PreferenceSource
|
||||||
import com.rtbishop.look4sat.di.IoDispatcher
|
import com.rtbishop.look4sat.di.IoDispatcher
|
||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import com.rtbishop.look4sat.interactors.GetTransmittersForSat
|
import com.rtbishop.look4sat.interactors.GetSatTransmitters
|
||||||
import com.rtbishop.look4sat.framework.OrientationProvider
|
import com.rtbishop.look4sat.framework.OrientationProvider
|
||||||
import com.rtbishop.look4sat.utility.PassesRepo
|
import com.rtbishop.look4sat.data.PassesRepo
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import com.rtbishop.look4sat.utility.round
|
import com.rtbishop.look4sat.utility.round
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -37,11 +36,10 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PolarViewModel @Inject constructor(
|
class PolarViewModel @Inject constructor(
|
||||||
private val locationRepo: LocationRepo,
|
|
||||||
private val orientationProvider: OrientationProvider,
|
private val orientationProvider: OrientationProvider,
|
||||||
private val prefsManager: PrefsManager,
|
private val preferenceSource: PreferenceSource,
|
||||||
private val passesRepo: PassesRepo,
|
private val passesRepo: PassesRepo,
|
||||||
private val getTransmittersForSat: GetTransmittersForSat,
|
private val getSatTransmitters: GetSatTransmitters,
|
||||||
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
||||||
) : ViewModel(), OrientationProvider.OrientationListener {
|
) : ViewModel(), OrientationProvider.OrientationListener {
|
||||||
|
|
||||||
@@ -62,20 +60,20 @@ class PolarViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun enableSensor() {
|
fun enableSensor() {
|
||||||
if (prefsManager.shouldUseCompass()) orientationProvider.startListening(this)
|
if (preferenceSource.shouldUseCompass()) orientationProvider.startListening(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableSensor() {
|
fun disableSensor() {
|
||||||
if (prefsManager.shouldUseCompass()) orientationProvider.stopListening()
|
if (preferenceSource.shouldUseCompass()) orientationProvider.stopListening()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
||||||
_orientation.value = Triple(azimuth + locationRepo.getMagDeclination(), pitch, roll)
|
_orientation.value = Triple(azimuth + preferenceSource.getMagDeclination(), pitch, roll)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initRotatorControl(satPass: SatPass) {
|
private fun initRotatorControl(satPass: SatPass) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val rotatorPrefs = prefsManager.getRotatorServer()
|
val rotatorPrefs = preferenceSource.getRotatorServer()
|
||||||
if (rotatorPrefs != null) {
|
if (rotatorPrefs != null) {
|
||||||
runCatching {
|
runCatching {
|
||||||
withContext(ioDispatcher) {
|
withContext(ioDispatcher) {
|
||||||
@@ -99,7 +97,7 @@ class PolarViewModel @Inject constructor(
|
|||||||
|
|
||||||
private fun processTransmitters(satPass: SatPass) {
|
private fun processTransmitters(satPass: SatPass) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
getTransmittersForSat(satPass.catNum).collect { transList ->
|
getSatTransmitters(satPass.catNum).collect { transList ->
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val timeNow = Date()
|
val timeNow = Date()
|
||||||
val copiedList = transList.map { it.copy() }
|
val copiedList = transList.map { it.copy() }
|
||||||
|
|||||||
@@ -30,9 +30,8 @@ import androidx.preference.Preference
|
|||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.LocationRepo
|
import com.rtbishop.look4sat.data.PreferenceSource
|
||||||
import com.rtbishop.look4sat.framework.DefaultLocationSource
|
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -40,10 +39,7 @@ import javax.inject.Inject
|
|||||||
class PrefsFragment : PreferenceFragmentCompat() {
|
class PrefsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var locationRepo: LocationRepo
|
lateinit var preferenceSource: PreferenceSource
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefsManager: PrefsManager
|
|
||||||
|
|
||||||
private val requestPermissionLauncher =
|
private val requestPermissionLauncher =
|
||||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||||
@@ -61,20 +57,20 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
findPreference<Preference>(DefaultLocationSource.keyPositionGPS)?.apply {
|
findPreference<Preference>(PreferencesProvider.keyPositionGPS)?.apply {
|
||||||
setOnPreferenceClickListener {
|
setOnPreferenceClickListener {
|
||||||
updatePositionFromGPS()
|
updatePositionFromGPS()
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findPreference<Preference>(DefaultLocationSource.keyPositionQTH)?.apply {
|
findPreference<Preference>(PreferencesProvider.keyPositionQTH)?.apply {
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
updatePositionFromQth(newValue.toString())
|
updatePositionFromQth(newValue.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findPreference<EditTextPreference>(PrefsManager.keyRotatorAddress)?.apply {
|
findPreference<EditTextPreference>(PreferencesProvider.keyRotatorAddress)?.apply {
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
if (Patterns.IP_ADDRESS.matcher(newValue.toString()).matches()) {
|
if (Patterns.IP_ADDRESS.matcher(newValue.toString()).matches()) {
|
||||||
return@setOnPreferenceChangeListener true
|
return@setOnPreferenceChangeListener true
|
||||||
@@ -85,7 +81,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findPreference<EditTextPreference>(PrefsManager.keyRotatorPort)?.apply {
|
findPreference<EditTextPreference>(PreferencesProvider.keyRotatorPort)?.apply {
|
||||||
setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER }
|
setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER }
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val portValue = newValue.toString()
|
val portValue = newValue.toString()
|
||||||
@@ -100,7 +96,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePositionFromQth(qthString: String): Boolean {
|
private fun updatePositionFromQth(qthString: String): Boolean {
|
||||||
return if (locationRepo.updatePositionFromQTH(qthString)) {
|
return if (preferenceSource.updatePositionFromQTH(qthString)) {
|
||||||
showSnack(getString(R.string.pref_pos_success))
|
showSnack(getString(R.string.pref_pos_success))
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -113,7 +109,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
|||||||
val locPermString = Manifest.permission.ACCESS_FINE_LOCATION
|
val locPermString = Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
||||||
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
||||||
if (locationRepo.updatePositionFromGPS()) {
|
if (preferenceSource.updatePositionFromGPS()) {
|
||||||
showSnack(getString(R.string.pref_pos_success))
|
showSnack(getString(R.string.pref_pos_success))
|
||||||
} else showSnack(getString(R.string.pref_pos_gps_null))
|
} else showSnack(getString(R.string.pref_pos_gps_null))
|
||||||
} else requestPermissionLauncher.launch(locPermString)
|
} else requestPermissionLauncher.launch(locPermString)
|
||||||
|
|||||||
@@ -1,70 +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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.presentation.sourcesDialog
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.rtbishop.look4sat.databinding.ItemTleSourceBinding
|
|
||||||
import com.rtbishop.look4sat.framework.model.TleSource
|
|
||||||
|
|
||||||
class SourcesAdapter(private val sources: MutableList<TleSource> = mutableListOf()) :
|
|
||||||
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
|
|
||||||
|
|
||||||
fun getSources(): List<TleSource> {
|
|
||||||
return sources.filter { it.url.contains("https://") }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSources(list: List<TleSource>) {
|
|
||||||
sources.clear()
|
|
||||||
sources.addAll(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addSource() {
|
|
||||||
sources.add(TleSource())
|
|
||||||
notifyItemInserted(itemCount - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TleSourceHolder {
|
|
||||||
val binding = ItemTleSourceBinding
|
|
||||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
|
||||||
return TleSourceHolder(binding)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: TleSourceHolder, position: Int) {
|
|
||||||
holder.bind(sources[position])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return sources.size
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class TleSourceHolder(private val binding: ItemTleSourceBinding) :
|
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
|
||||||
|
|
||||||
fun bind(source: TleSource) {
|
|
||||||
binding.tleSourceUrl.setText(source.url)
|
|
||||||
binding.tleSourceUrl.doOnTextChanged { text, _, _, _ -> source.url = text.toString() }
|
|
||||||
binding.tleSourceInputLayout.setEndIconOnClickListener {
|
|
||||||
sources.remove(source)
|
|
||||||
notifyItemRemoved(adapterPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.rtbishop.look4sat.presentation.sourcesDialog
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import com.rtbishop.look4sat.R
|
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
|
|
||||||
import com.rtbishop.look4sat.utility.setNavResult
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class SourcesDialog : AppCompatDialogFragment() {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefsManager: PrefsManager
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
|
|
||||||
return inflater.inflate(R.layout.dialog_sources, group, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, state: Bundle?) {
|
|
||||||
super.onViewCreated(view, state)
|
|
||||||
val sourcesAdapter = SourcesAdapter().apply { setSources(prefsManager.loadTleSources()) }
|
|
||||||
DialogSourcesBinding.bind(view).apply {
|
|
||||||
dialog?.window?.setLayout(
|
|
||||||
WindowManager.LayoutParams.MATCH_PARENT,
|
|
||||||
WindowManager.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
sourcesRecycler.apply {
|
|
||||||
adapter = sourcesAdapter
|
|
||||||
layoutManager = LinearLayoutManager(requireContext())
|
|
||||||
}
|
|
||||||
sourceBtnAdd.setOnClickListener {
|
|
||||||
sourcesAdapter.addSource()
|
|
||||||
}
|
|
||||||
sourcesBtnPos.setOnClickListener {
|
|
||||||
setNavResult("sources", sourcesAdapter.getSources().map { it.url })
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
sourcesBtnNeg.setOnClickListener { dismiss() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,13 +19,9 @@ package com.rtbishop.look4sat.utility
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.Navigator
|
import androidx.navigation.Navigator
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
fun Long.toTimerString(): String {
|
fun Long.toTimerString(): String {
|
||||||
@@ -53,26 +49,3 @@ fun NavController.navigateSafe(
|
|||||||
navigate(resId, args, navOptions, navExtras)
|
navigate(resId, args, navOptions, navExtras)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Fragment.setNavResult(key: String, value: T) {
|
|
||||||
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
|
|
||||||
val navBackStackEntry = findNavController().getBackStackEntry(id)
|
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
|
||||||
if (event == Lifecycle.Event.ON_RESUME
|
|
||||||
&& navBackStackEntry.savedStateHandle.contains(key)
|
|
||||||
) {
|
|
||||||
val result = navBackStackEntry.savedStateHandle.get<T>(key)
|
|
||||||
result?.let(onResult)
|
|
||||||
navBackStackEntry.savedStateHandle.remove<T>(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
navBackStackEntry.lifecycle.addObserver(observer)
|
|
||||||
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
|
|
||||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
|
||||||
navBackStackEntry.lifecycle.removeObserver(observer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -16,13 +16,6 @@
|
|||||||
app:exitAnim="@anim/nav_default_exit_anim"
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||||
<action
|
|
||||||
android:id="@+id/action_entries_to_sources"
|
|
||||||
app:destination="@id/nav_dialog_sources"
|
|
||||||
app:enterAnim="@anim/nav_default_enter_anim"
|
|
||||||
app:exitAnim="@anim/nav_default_exit_anim"
|
|
||||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
|
||||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
@@ -66,10 +59,6 @@
|
|||||||
android:id="@+id/nav_info"
|
android:id="@+id/nav_info"
|
||||||
android:name="com.rtbishop.look4sat.presentation.infoScreen.InfoFragment"
|
android:name="com.rtbishop.look4sat.presentation.infoScreen.InfoFragment"
|
||||||
tools:layout="@layout/fragment_info" />
|
tools:layout="@layout/fragment_info" />
|
||||||
<dialog
|
|
||||||
android:id="@+id/nav_dialog_sources"
|
|
||||||
android:name="com.rtbishop.look4sat.presentation.sourcesDialog.SourcesDialog"
|
|
||||||
tools:layout="@layout/dialog_sources" />
|
|
||||||
<dialog
|
<dialog
|
||||||
android:id="@+id/nav_dialog_splash"
|
android:id="@+id/nav_dialog_splash"
|
||||||
android:name="com.rtbishop.look4sat.presentation.splashDialog.SplashDialog"
|
android:name="com.rtbishop.look4sat.presentation.splashDialog.SplashDialog"
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ interface LocalDataSource {
|
|||||||
|
|
||||||
fun getSatItems(): Flow<List<SatItem>>
|
fun getSatItems(): Flow<List<SatItem>>
|
||||||
|
|
||||||
|
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>>
|
||||||
|
|
||||||
suspend fun getSelectedSatellites(): List<Satellite>
|
suspend fun getSelectedSatellites(): List<Satellite>
|
||||||
|
|
||||||
suspend fun updateEntries(entries: List<SatEntry>)
|
suspend fun updateEntries(entries: List<SatEntry>)
|
||||||
|
|
||||||
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
|
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
|
||||||
|
|
||||||
fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>>
|
|
||||||
|
|
||||||
suspend fun updateTransmitters(satelliteTrans: List<SatTrans>)
|
suspend fun updateTransmitters(satelliteTrans: List<SatTrans>)
|
||||||
}
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.rtbishop.look4sat.data
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
|
||||||
|
|
||||||
class LocationRepo(
|
|
||||||
private val locationSource: LocationSource,
|
|
||||||
private val qthConverter: QthConverter
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun getStationPosition(): StationPosition {
|
|
||||||
return locationSource.loadStationPosition()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMagDeclination(): Float {
|
|
||||||
return locationSource.getMagDeclination(getStationPosition())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun positionToQTH(lat: Double, lon: Double): String? {
|
|
||||||
return qthConverter.positionToQTH(lat, lon)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updatePositionFromGPS(): Boolean {
|
|
||||||
val stationPosition = locationSource.getLastKnownLocation() ?: return false
|
|
||||||
locationSource.saveStationPosition(stationPosition)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updatePositionFromQTH(qthString: String): Boolean {
|
|
||||||
val position = qthConverter.qthToPosition(qthString) ?: return false
|
|
||||||
val stationPosition = StationPosition(position.latitude, position.longitude, 0.0)
|
|
||||||
locationSource.saveStationPosition(stationPosition)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.rtbishop.look4sat.data
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
|
||||||
|
|
||||||
interface LocationSource {
|
|
||||||
|
|
||||||
fun getLastKnownLocation(): StationPosition?
|
|
||||||
|
|
||||||
fun getMagDeclination(position: StationPosition): Float
|
|
||||||
|
|
||||||
fun loadStationPosition(): StationPosition
|
|
||||||
|
|
||||||
fun saveStationPosition(position: StationPosition)
|
|
||||||
}
|
|
||||||
+8
-15
@@ -15,26 +15,19 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.rtbishop.look4sat.data.LocationRepo
|
|
||||||
import com.rtbishop.look4sat.di.DefaultDispatcher
|
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||||
import com.rtbishop.look4sat.framework.PrefsManager
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
class PassesRepo(
|
||||||
class PassesRepo @Inject constructor(
|
private val preferenceSource: PreferenceSource,
|
||||||
private val locationRepo: LocationRepo,
|
private val defaultDispatcher: CoroutineDispatcher
|
||||||
private val prefsManager: PrefsManager,
|
|
||||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
|
||||||
) {
|
) {
|
||||||
private val _passes = MutableSharedFlow<List<SatPass>>(replay = 1)
|
private val _passes = MutableSharedFlow<List<SatPass>>(replay = 1)
|
||||||
private var selectedSatellites = emptyList<Satellite>()
|
private var selectedSatellites = emptyList<Satellite>()
|
||||||
@@ -64,15 +57,15 @@ class PassesRepo @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getPasses(satellite: Satellite, refDate: Date): List<SatPass> {
|
private fun getPasses(satellite: Satellite, refDate: Date): List<SatPass> {
|
||||||
val predictor = satellite.getPredictor(locationRepo.getStationPosition())
|
val predictor = satellite.getPredictor(preferenceSource.loadStationPosition())
|
||||||
return predictor.getPasses(refDate, prefsManager.getHoursAhead(), true)
|
return predictor.getPasses(refDate, preferenceSource.getHoursAhead(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterPasses(passes: List<SatPass>, refDate: Date): List<SatPass> {
|
private fun filterPasses(passes: List<SatPass>, refDate: Date): List<SatPass> {
|
||||||
val timeFuture = Date(refDate.time + (prefsManager.getHoursAhead() * 3600 * 1000))
|
val timeFuture = Date(refDate.time + (preferenceSource.getHoursAhead() * 3600 * 1000))
|
||||||
return passes.filter { it.losDate.after(refDate) }
|
return passes.filter { it.losDate.after(refDate) }
|
||||||
.filter { it.aosDate.before(timeFuture) }
|
.filter { it.aosDate.before(timeFuture) }
|
||||||
.filter { it.maxElevation > prefsManager.getMinElevation() }
|
.filter { it.maxElevation > preferenceSource.getMinElevation() }
|
||||||
.sortedBy { it.aosDate }
|
.sortedBy { it.aosDate }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||||
|
|
||||||
|
interface PreferenceSource {
|
||||||
|
|
||||||
|
fun positionToQTH(lat: Double, lon: Double): String?
|
||||||
|
|
||||||
|
fun loadStationPosition(): StationPosition
|
||||||
|
|
||||||
|
fun saveStationPosition(position: StationPosition)
|
||||||
|
|
||||||
|
fun updatePositionFromGPS(): Boolean
|
||||||
|
|
||||||
|
fun updatePositionFromQTH(qthString: String): Boolean
|
||||||
|
|
||||||
|
fun getMagDeclination(): Float
|
||||||
|
|
||||||
|
fun getHoursAhead(): Int
|
||||||
|
|
||||||
|
fun getMinElevation(): Double
|
||||||
|
|
||||||
|
fun shouldUseTextLabels(): Boolean
|
||||||
|
|
||||||
|
fun shouldUseUTC(): Boolean
|
||||||
|
|
||||||
|
fun shouldUseCompass(): Boolean
|
||||||
|
|
||||||
|
fun isFirstLaunch(): Boolean
|
||||||
|
|
||||||
|
fun setFirstLaunchDone()
|
||||||
|
|
||||||
|
fun saveModesSelection(modes: List<String>)
|
||||||
|
|
||||||
|
fun loadModesSelection(): List<String>
|
||||||
|
|
||||||
|
fun getRotatorServer(): Pair<String, Int>?
|
||||||
|
}
|
||||||
@@ -22,24 +22,23 @@ class SatelliteRepo(
|
|||||||
return localSource.getSatItems()
|
return localSource.getSatItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>> {
|
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||||
return localSource.getTransmittersForSat(catNum)
|
return localSource.getSatTransmitters(catNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSelectedSatellites(): List<Satellite> {
|
suspend fun getSelectedSatellites(): List<Satellite> {
|
||||||
return localSource.getSelectedSatellites()
|
return localSource.getSelectedSatellites()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun importDataFromStream(stream: InputStream) = withContext(ioDispatcher) {
|
suspend fun updateEntriesFromFile(stream: InputStream) = withContext(ioDispatcher) {
|
||||||
val importedEntries = Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
localSource.updateEntries(importSatEntries(stream))
|
||||||
localSource.updateEntries(importedEntries)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun importDataFromWeb(sources: List<String>) {
|
suspend fun updateEntriesFromWeb(sources: List<String>) {
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
launch(ioDispatcher) {
|
launch(ioDispatcher) {
|
||||||
val importedEntries = mutableListOf<SatEntry>()
|
|
||||||
val streams = mutableListOf<InputStream>()
|
val streams = mutableListOf<InputStream>()
|
||||||
|
val entries = mutableListOf<SatEntry>()
|
||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
remoteSource.fetchDataStream(source)?.let { stream ->
|
remoteSource.fetchDataStream(source)?.let { stream ->
|
||||||
if (source.contains(".zip", true)) {
|
if (source.contains(".zip", true)) {
|
||||||
@@ -50,11 +49,8 @@ class SatelliteRepo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
streams.forEach { stream ->
|
streams.forEach { stream -> entries.addAll(importSatEntries(stream)) }
|
||||||
val entries = Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
localSource.updateEntries(entries)
|
||||||
importedEntries.addAll(entries)
|
|
||||||
}
|
|
||||||
localSource.updateEntries(importedEntries)
|
|
||||||
}
|
}
|
||||||
launch(ioDispatcher) {
|
launch(ioDispatcher) {
|
||||||
val transmitters = remoteSource.fetchTransmitters().filter { it.isAlive }
|
val transmitters = remoteSource.fetchTransmitters().filter { it.isAlive }
|
||||||
@@ -66,4 +62,8 @@ class SatelliteRepo(
|
|||||||
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||||
localSource.updateEntriesSelection(catNums, isSelected)
|
localSource.updateEntriesSelection(catNums, isSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun importSatEntries(stream: InputStream): List<SatEntry> {
|
||||||
|
return Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -4,9 +4,9 @@ import com.rtbishop.look4sat.data.SatelliteRepo
|
|||||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
class GetTransmittersForSat(private val satelliteRepo: SatelliteRepo) {
|
class GetSatTransmitters(private val satelliteRepo: SatelliteRepo) {
|
||||||
|
|
||||||
operator fun invoke(catNum: Int): Flow<List<SatTrans>> {
|
operator fun invoke(catNum: Int): Flow<List<SatTrans>> {
|
||||||
return satelliteRepo.getTransmittersForSat(catNum)
|
return satelliteRepo.getSatTransmitters(catNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.rtbishop.look4sat.interactors
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
|
||||||
|
|
||||||
class ImportDataFromWeb(private val satelliteRepo: SatelliteRepo) {
|
|
||||||
|
|
||||||
suspend operator fun invoke(sources: List<String>) {
|
|
||||||
satelliteRepo.importDataFromWeb(sources)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -3,9 +3,9 @@ package com.rtbishop.look4sat.interactors
|
|||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class ImportDataFromStream(private val satelliteRepo: SatelliteRepo) {
|
class UpdateEntriesFromFile(private val satelliteRepo: SatelliteRepo) {
|
||||||
|
|
||||||
suspend operator fun invoke(stream: InputStream) {
|
suspend operator fun invoke(stream: InputStream) {
|
||||||
satelliteRepo.importDataFromStream(stream)
|
satelliteRepo.updateEntriesFromFile(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.rtbishop.look4sat.interactors
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||||
|
|
||||||
|
class UpdateEntriesFromWeb(private val satelliteRepo: SatelliteRepo) {
|
||||||
|
|
||||||
|
private val defaultSources = listOf(
|
||||||
|
"https://celestrak.com/NORAD/elements/active.txt",
|
||||||
|
"https://amsat.org/tle/current/nasabare.txt",
|
||||||
|
"https://www.prismnet.com/~mmccants/tles/classfd.zip",
|
||||||
|
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend operator fun invoke(sources: List<String> = defaultSources) {
|
||||||
|
satelliteRepo.updateEntriesFromWeb(sources)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user