Further refactoring of Look4Sat core module classes

This commit is contained in:
Arty Bishop committed 2021-09-15 09:58:40 +01:00
1 parent 2c757a6b35
commit bceeb01194
46 files changed
+603 -572

No files matched your search

@@ -22,8 +22,8 @@ import android.hardware.GeomagneticField
import android.location.LocationManager
import androidx.core.content.edit
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
import com.rtbishop.look4sat.domain.predict4kotlin.StationPos
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.domain.StationPos
import com.rtbishop.look4sat.utility.round
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
@@ -31,7 +31,6 @@ import javax.inject.Inject
class PreferencesProvider @Inject constructor(
moshi: Moshi,
private val qthConverter: QthConverter,
private val locationManager: LocationManager,
private val preferences: SharedPreferences
) : PreferencesSource {
@@ -86,7 +85,7 @@ class PreferencesProvider @Inject constructor(
}
override fun positionToQTH(lat: Double, lon: Double): String? {
return qthConverter.positionToQTH(lat, lon)
return QthConverter.positionToQTH(lat, lon)
}
override fun loadStationPosition(): StationPos {
@@ -123,7 +122,7 @@ class PreferencesProvider @Inject constructor(
}
override fun updatePositionFromQTH(qthString: String): Boolean {
val position = qthConverter.qthToPosition(qthString) ?: return false
val position = QthConverter.qthToPosition(qthString) ?: return false
val stationPosition = StationPos(position.latitude, position.longitude, 0.0)
saveStationPosition(stationPosition)
return true
@@ -17,12 +17,12 @@
*/
package com.rtbishop.look4sat.framework.api
import com.rtbishop.look4sat.data.SatDataRemoteSource
import com.rtbishop.look4sat.domain.model.SatTrans
import com.rtbishop.look4sat.data.RemoteDataSource
import com.rtbishop.look4sat.domain.SatTrans
import com.rtbishop.look4sat.utility.DataMapper
import java.io.InputStream
class SatDataRemote(private val api: SatDataService) : SatDataRemoteSource {
class RemoteSource(private val api: SatelliteService) : RemoteDataSource {
override suspend fun fetchDataStream(url: String): InputStream? {
return api.fetchFileByUrl(url).body()?.byteStream()
@@ -24,7 +24,7 @@ import retrofit2.http.GET
import retrofit2.http.Streaming
import retrofit2.http.Url
interface SatDataService {
interface SatelliteService {
@Streaming
@GET
@@ -18,34 +18,34 @@
package com.rtbishop.look4sat.framework.db
import androidx.room.TypeConverter
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
import com.rtbishop.look4sat.domain.predict4kotlin.TLE
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.domain.TLE
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
object RoomConverters {
object Converters {
private lateinit var tleAdapter: JsonAdapter<TLE>
private lateinit var paramsAdapter: JsonAdapter<TLE>
fun initialize(moshi: Moshi) {
tleAdapter = moshi.adapter(TLE::class.java)
paramsAdapter = moshi.adapter(TLE::class.java)
}
@JvmStatic
@TypeConverter
fun tleToString(tle: TLE): String {
return tleAdapter.toJson(tle)
return paramsAdapter.toJson(tle)
}
@JvmStatic
@TypeConverter
fun tleFromString(string: String): TLE? {
return tleAdapter.fromJson(string)
return paramsAdapter.fromJson(string)
}
@JvmStatic
@TypeConverter
fun satFromString(string: String): Satellite? {
return tleAdapter.fromJson(string)?.createSat()
return paramsAdapter.fromJson(string)?.createSat()
}
}
@@ -17,42 +17,42 @@
*/
package com.rtbishop.look4sat.framework.db
import com.rtbishop.look4sat.data.SatDataLocalSource
import com.rtbishop.look4sat.domain.model.SatEntry
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.model.SatTrans
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
import com.rtbishop.look4sat.data.LocalDataSource
import com.rtbishop.look4sat.domain.SatEntry
import com.rtbishop.look4sat.domain.SatItem
import com.rtbishop.look4sat.domain.SatTrans
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.utility.DataMapper
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
class SatDataLocal(private val satDataDao: SatDataDao) : SatDataLocalSource {
class LocalSource(private val satelliteDao: SatelliteDao) : LocalDataSource {
override fun getSatItems(): Flow<List<SatItem>> {
return satDataDao.getSatItems()
return satelliteDao.getSatItems()
.map { satItems -> DataMapper.satItemsToDomainItems(satItems) }
}
override suspend fun getSelectedSatellites(): List<Satellite> {
return satDataDao.getSelectedSatellites()
return satelliteDao.getSelectedSatellites()
}
override suspend fun updateEntries(entries: List<SatEntry>) {
val satEntries = entries.map { entry -> DataMapper.domainEntryToSatEntry(entry) }
satDataDao.updateEntries(satEntries)
satelliteDao.updateEntries(satEntries)
}
override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
satDataDao.updateEntriesSelection(catNums, isSelected)
satelliteDao.updateEntriesSelection(catNums, isSelected)
}
override fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
return satDataDao.getSatTransmitters(catNum)
return satelliteDao.getSatTransmitters(catNum)
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
}
override suspend fun updateTransmitters(satelliteTrans: List<SatTrans>) {
val satTransList = DataMapper.domainTransListToSatTransList(satelliteTrans)
satDataDao.updateTransmitters(satTransList)
satelliteDao.updateTransmitters(satTransList)
}
}
@@ -21,11 +21,11 @@ import androidx.room.*
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem
import com.rtbishop.look4sat.framework.model.SatTrans
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
import com.rtbishop.look4sat.domain.Satellite
import kotlinx.coroutines.flow.Flow
@Dao
interface SatDataDao {
interface SatelliteDao {
@Transaction
@Query("SELECT catNum, name, isSelected FROM entries ORDER BY name ASC")
@@ -24,8 +24,8 @@ import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatTrans
@Database(entities = [SatEntry::class, SatTrans::class], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)
abstract class SatDataDb : RoomDatabase() {
@TypeConverters(Converters::class)
abstract class SatelliteDb : RoomDatabase() {
abstract fun satelliteDao(): SatDataDao
abstract fun satelliteDao(): SatelliteDao
}
@@ -1,32 +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
import com.rtbishop.look4sat.domain.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
data class SatData(
val pass: Satellite,
val catNum: Int,
val name: String,
val range: Double,
val altitude: Double,
val velocity: Double,
val qthLoc: String,
val osmPos: GeoPos
)
@@ -19,7 +19,7 @@ package com.rtbishop.look4sat.framework.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.rtbishop.look4sat.domain.predict4kotlin.TLE
import com.rtbishop.look4sat.domain.TLE
@Entity(tableName = "entries")
data class SatEntry(
@@ -22,14 +22,13 @@ import android.content.SharedPreferences
import android.location.LocationManager
import androidx.room.Room
import com.rtbishop.look4sat.data.*
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
import com.rtbishop.look4sat.framework.PreferencesProvider
import com.rtbishop.look4sat.framework.api.SatDataRemote
import com.rtbishop.look4sat.framework.api.SatDataService
import com.rtbishop.look4sat.framework.db.RoomConverters
import com.rtbishop.look4sat.framework.db.SatDataDao
import com.rtbishop.look4sat.framework.db.SatDataDb
import com.rtbishop.look4sat.framework.db.SatDataLocal
import com.rtbishop.look4sat.framework.api.RemoteSource
import com.rtbishop.look4sat.framework.api.SatelliteService
import com.rtbishop.look4sat.framework.db.Converters
import com.rtbishop.look4sat.framework.db.LocalSource
import com.rtbishop.look4sat.framework.db.SatelliteDao
import com.rtbishop.look4sat.framework.db.SatelliteDb
import com.squareup.moshi.Moshi
import dagger.Module
import dagger.Provides
@@ -45,12 +44,7 @@ import javax.net.ssl.HostnameVerifier
@Module
@InstallIn(SingletonComponent::class)
object SatDataModule {
@Provides
fun provideQthConverter(): QthConverter {
return QthConverter()
}
object SatelliteDataModule {
@Provides
fun provideMoshi(): Moshi {
@@ -61,56 +55,52 @@ object SatDataModule {
@Singleton
fun providePreferenceSource(
moshi: Moshi,
qthConverter: QthConverter,
locationManager: LocationManager,
preferences: SharedPreferences
): PreferencesSource {
return PreferencesProvider(moshi, qthConverter, locationManager, preferences)
return PreferencesProvider(moshi, locationManager, preferences)
}
@Provides
@Singleton
fun providePassesRepo(
preferencesSource: PreferencesSource,
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
): SatPassRepository {
return SatPassRepository(preferencesSource, defaultDispatcher)
fun providePassPredictor(@DefaultDispatcher dispatcher: CoroutineDispatcher): PassPredictor {
return PassPredictor(dispatcher)
}
@Provides
@Singleton
fun provideSatelliteRepo(
preferencesSource: PreferencesSource,
satLocalSource: SatDataLocalSource,
satRemoteSource: SatDataRemoteSource,
@IoDispatcher ioDispatcher: CoroutineDispatcher
): SatDataRepository {
return SatDataRepository(preferencesSource, satLocalSource, satRemoteSource, ioDispatcher)
localDataSource: LocalDataSource,
remoteDataSource: RemoteDataSource,
@IoDispatcher dispatcher: CoroutineDispatcher
): SatelliteRepo {
return SatelliteRepo(preferencesSource, localDataSource, remoteDataSource, dispatcher)
}
@Provides
fun provideLocalDataSource(satDataDao: SatDataDao): SatDataLocalSource {
return SatDataLocal(satDataDao)
fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalDataSource {
return LocalSource(satelliteDao)
}
@Provides
fun provideSatDataDao(db: SatDataDb): SatDataDao {
fun provideSatelliteDao(db: SatelliteDb): SatelliteDao {
return db.satelliteDao()
}
@Provides
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatDataDb {
RoomConverters.initialize(moshi)
return Room.databaseBuilder(context, SatDataDb::class.java, "SatelliteDb").build()
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatelliteDb {
Converters.initialize(moshi)
return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb").build()
}
@Provides
fun provideRemoteDataSource(satDataService: SatDataService): SatDataRemoteSource {
return SatDataRemote(satDataService)
fun provideRemoteDataSource(satelliteService: SatelliteService): RemoteDataSource {
return RemoteSource(satelliteService)
}
@Provides
fun provideSatDataService(): SatDataService {
fun provideSatelliteService(): SatelliteService {
val verifier = HostnameVerifier { _, _ -> true }
val httpClient = OkHttpClient.Builder().hostnameVerifier(verifier).build()
return Retrofit.Builder()
@@ -118,6 +108,6 @@ object SatDataModule {
.client(httpClient)
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create(SatDataService::class.java)
.create(SatelliteService::class.java)
}
}
@@ -23,7 +23,7 @@ import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.databinding.SatItemBinding
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.SatItem
class SatItemAdapter : RecyclerView.Adapter<SatItemAdapter.SatItemHolder>() {
@@ -28,7 +28,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.SatItem
import com.rtbishop.look4sat.framework.model.Result
import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.getNavResult
@@ -22,8 +22,8 @@ import android.net.Uri
import android.widget.SearchView
import androidx.lifecycle.*
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatDataRepository
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.domain.SatItem
import com.rtbishop.look4sat.framework.model.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collect
@@ -35,13 +35,13 @@ import javax.inject.Inject
class SatItemViewModel @Inject constructor(
private val preferencesSource: PreferencesSource,
private val resolver: ContentResolver,
private val satDataRepository: SatDataRepository,
private val satelliteRepo: SatelliteRepo,
) : ViewModel(), SatItemAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
private val transModes = MutableLiveData(satDataRepository.loadSelectedModes())
private val transModes = MutableLiveData(satelliteRepo.loadSelectedModes())
private val currentQuery = MutableLiveData(String())
private val itemsWithModes = transModes.switchMap { modes ->
liveData { satDataRepository.getSatItems().collect { emit(filterByModes(it, modes)) } }
liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } }
}
private val itemsWithQuery = currentQuery.switchMap { query ->
itemsWithModes.map { items -> Result.Success(filterByQuery(items, query)) }
@@ -57,7 +57,7 @@ class SatItemViewModel @Inject constructor(
_satData.value = Result.InProgress
runCatching {
resolver.openInputStream(uri)?.use { stream ->
satDataRepository.updateEntriesFromFile(stream)
satelliteRepo.updateEntriesFromFile(stream)
}
}.onFailure { _satData.value = Result.Error(it) }
}
@@ -68,7 +68,7 @@ class SatItemViewModel @Inject constructor(
_satData.value = Result.InProgress
try {
preferencesSource.saveTleSources(sources)
satDataRepository.updateEntriesFromWeb(sources)
satelliteRepo.updateEntriesFromWeb(sources)
} catch (exception: Exception) {
_satData.value = Result.Error(exception)
}
@@ -84,12 +84,12 @@ class SatItemViewModel @Inject constructor(
}
fun loadSelectedModes(): List<String> {
return satDataRepository.loadSelectedModes()
return satelliteRepo.loadSelectedModes()
}
fun saveSelectedModes(modes: List<String>) {
transModes.value = modes
satDataRepository.saveSelectedModes(modes)
satelliteRepo.saveSelectedModes(modes)
}
override fun onQueryTextSubmit(query: String): Boolean {
@@ -102,7 +102,7 @@ class SatItemViewModel @Inject constructor(
}
override fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
viewModelScope.launch { satDataRepository.updateEntriesSelection(catNums, isSelected) }
viewModelScope.launch { satelliteRepo.updateEntriesSelection(catNums, isSelected) }
}
private fun filterByModes(items: List<SatItem>, modes: List<String>): List<SatItem> {
@@ -29,9 +29,9 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentMapBinding
import com.rtbishop.look4sat.domain.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
import com.rtbishop.look4sat.framework.model.SatData
import com.rtbishop.look4sat.domain.GeoPos
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.domain.SatData
import dagger.hilt.android.AndroidEntryPoint
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@@ -89,7 +89,7 @@ class SatMapFragment : Fragment(R.layout.fragment_map) {
}
private fun setupObservers(binding: FragmentMapBinding) {
viewModel.stationPos.observe(viewLifecycleOwner, { renderStationPos(it, binding) })
viewModel.stationPosLiveData.observe(viewLifecycleOwner, { renderStationPos(it, binding) })
viewModel.satPositions.observe(viewLifecycleOwner, { renderSatPositions(it, binding) })
viewModel.satTrack.observe(viewLifecycleOwner, { renderSatTrack(it, binding) })
viewModel.satFootprint.observe(viewLifecycleOwner, { renderSatFootprint(it, binding) })
@@ -19,11 +19,12 @@ package com.rtbishop.look4sat.presentation.satMapScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatDataRepository
import com.rtbishop.look4sat.domain.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
import com.rtbishop.look4sat.domain.predict4kotlin.StationPos
import com.rtbishop.look4sat.framework.model.SatData
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.domain.GeoPos
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.domain.StationPos
import com.rtbishop.look4sat.domain.SatData
import com.rtbishop.look4sat.injection.DefaultDispatcher
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
@@ -35,19 +36,20 @@ import kotlin.math.sqrt
@HiltViewModel
class SatMapViewModel @Inject constructor(
private val satDataRepository: SatDataRepository,
private val preferencesSource: PreferencesSource,
private val satelliteRepo: SatelliteRepo,
private val passPredictor: PassPredictor,
private val preferences: PreferencesSource,
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
) : ViewModel() {
private val gsp = preferencesSource.loadStationPosition()
private val stationPos = preferences.loadStationPosition()
private var dataUpdateJob: Job? = null
private var allSatList = listOf<Satellite>()
private lateinit var selectedSat: Satellite
val stationPos = liveData {
val osmLat = clipLat(gsp.latitude)
val osmLon = clipLon(gsp.longitude)
val stationPosLiveData = liveData {
val osmLat = clipLat(stationPos.latitude)
val osmLon = clipLon(stationPos.longitude)
emit(GeoPos(osmLat, osmLon))
}
@@ -65,7 +67,7 @@ class SatMapViewModel @Inject constructor(
init {
viewModelScope.launch {
satDataRepository.getSelectedSatellites().also { selectedSatellites ->
satelliteRepo.getSelectedSatellites().also { selectedSatellites ->
if (selectedSatellites.isNotEmpty()) {
allSatList = selectedSatellites
selectSatellite(selectedSatellites.first())
@@ -75,7 +77,7 @@ class SatMapViewModel @Inject constructor(
}
fun shouldUseTextLabels(): Boolean {
return preferencesSource.shouldUseTextLabels()
return preferences.shouldUseTextLabels()
}
fun scrollSelection(decrement: Boolean) {
@@ -97,12 +99,12 @@ class SatMapViewModel @Inject constructor(
dataUpdateJob?.cancelAndJoin()
dataUpdateJob = launch {
val dateNow = Date()
setSelectedSatTrack(selectedSat, gsp, dateNow)
setSelectedSatTrack(selectedSat, stationPos, dateNow)
while (isActive) {
dateNow.time = System.currentTimeMillis()
setSatPositions(allSatList, gsp, dateNow)
setSelectedSatFootprint(selectedSat, gsp, dateNow)
setSelectedSatData(selectedSat, gsp, dateNow)
setSatPositions(allSatList, stationPos, dateNow)
setSelectedSatFootprint(selectedSat, stationPos, dateNow)
setSelectedSatData(selectedSat, stationPos, dateNow)
delay(updateFreq)
}
}
@@ -113,7 +115,7 @@ class SatMapViewModel @Inject constructor(
withContext(defaultDispatcher) {
val satPositions = mutableMapOf<Satellite, GeoPos>()
list.forEach { satellite ->
val satPos = satellite.getPredictor(gsp).getSatPos(date)
val satPos = satellite.getPosition(gsp, date.time)
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
satPositions[satellite] = GeoPos(osmLat, osmLon)
@@ -127,7 +129,7 @@ class SatMapViewModel @Inject constructor(
val satTracks = mutableListOf<List<GeoPos>>()
val currentTrack = mutableListOf<GeoPos>()
var oldLongitude = 0.0
sat.getPredictor(gsp).getPositions(date, 15, 0, 2.4).forEach { satPos ->
passPredictor.getPositions(sat, gsp, date, 15, 0, 2.4).forEach { satPos ->
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val currentPosition = GeoPos(osmLat, osmLon)
@@ -154,7 +156,7 @@ class SatMapViewModel @Inject constructor(
private suspend fun setSelectedSatFootprint(sat: Satellite, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satFootprint = sat.getPosition(gsp, date).getRangeCircle().map { rangePos ->
val satFootprint = sat.getPosition(gsp, date.time).getRangeCircle().map { rangePos ->
val osmLat = clipLat(rangePos.latitude)
val osmLon = clipLon(rangePos.longitude)
GeoPos(osmLat, osmLon)
@@ -165,12 +167,11 @@ class SatMapViewModel @Inject constructor(
private suspend fun setSelectedSatData(sat: Satellite, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satPos = sat.getPredictor(gsp).getSatPos(date)
val satPos = sat.getPosition(gsp, date.time)
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc =
preferencesSource.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
val qthLoc = preferences.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
val velocity = getOrbitalVelocity(satPos.altitude)
val satData = SatData(
sat, sat.params.catnum, sat.params.name, satPos.range,
@@ -27,7 +27,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.toTimerString
@@ -39,7 +39,7 @@ import javax.inject.Inject
class PassInfoFragment : Fragment(R.layout.fragment_polar) {
@Inject
lateinit var preferencesSource: PreferencesSource
lateinit var preferences: PreferencesSource
private val viewModel: PassInfoViewModel by viewModels()
private var passInfoView: PassInfoView? = null
@@ -72,10 +72,12 @@ class PassInfoFragment : Fragment(R.layout.fragment_polar) {
private fun setupObservers(satTransAdapter: SatTransAdapter, binding: FragmentPolarBinding) {
val catNum = requireArguments().getInt("catNum")
val aosTime = requireArguments().getLong("aosTime")
val stationPos = preferences.loadStationPosition()
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
passInfoView = PassInfoView(requireContext()).apply {
setShowAim(preferencesSource.shouldUseCompass())
setShowAim(preferences.shouldUseCompass())
setPass(pass)
setStationPos(stationPos)
}
binding.frame.addView(passInfoView)
observeTransmitters(pass, satTransAdapter, binding)
@@ -107,7 +109,8 @@ class PassInfoFragment : Fragment(R.layout.fragment_polar) {
private fun setPassText(satPass: SatPass, binding: FragmentPolarBinding) {
val dateNow = Date()
val timeNow = System.currentTimeMillis()
val satPos = satPass.predictor.getSatPos(dateNow)
val stationPos = preferences.loadStationPosition()
val satPos = satPass.satellite.getPosition(stationPos, dateNow.time)
val polarAz = getString(R.string.pat_azimuth)
val polarEl = getString(R.string.pat_elevation)
val polarRng = getString(R.string.pat_distance)
@@ -22,7 +22,8 @@ import android.graphics.*
import android.view.View
import androidx.core.content.ContextCompat
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.domain.StationPos
import java.util.*
import kotlin.math.cos
import kotlin.math.min
@@ -37,6 +38,7 @@ class PassInfoView(context: Context) : View(context) {
private val radarRadius = radarWidth * 0.48f
private val piDiv2 = Math.PI / 2.0
private val strokeSize = scale * 2f
private var stationPos: StationPos = StationPos(0.0, 0.0, 0.0)
private var radarColor = ContextCompat.getColor(context, R.color.greyLight)
private var radarCircleNum = 3
@@ -101,6 +103,10 @@ class PassInfoView(context: Context) : View(context) {
this.satPass = satPass
}
fun setStationPos(stationPos: StationPos) {
this.stationPos = stationPos
}
fun setShowAim(showAim: Boolean) {
shouldShowAim = showAim
}
@@ -170,7 +176,7 @@ class PassInfoView(context: Context) : View(context) {
}
private fun drawSatellite(canvas: Canvas, satPass: SatPass) {
val satPos = satPass.predictor.getSatPos(Date())
val satPos = satPass.satellite.getPosition(stationPos, Date().time)
if (satPos.elevation > 0) {
val satX = sph2CartX(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
val satY = sph2CartY(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
@@ -202,7 +208,7 @@ class PassInfoView(context: Context) : View(context) {
private fun createPassTrajectory(satPass: SatPass) {
var currentTime = satPass.aosTime
while (currentTime < satPass.losTime) {
val satPos = satPass.predictor.getSatPos(Date(currentTime))
val satPos = satPass.satellite.getPosition(stationPos, currentTime)
val passX = sph2CartX(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
val passY = sph2CartY(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
if (currentTime == satPass.aosTime) {
@@ -18,12 +18,12 @@
package com.rtbishop.look4sat.presentation.satPassInfoScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.data.SatPassRepository
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatDataRepository
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.injection.IoDispatcher
import com.rtbishop.look4sat.domain.model.SatTrans
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatTrans
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.framework.OrientationProvider
import com.rtbishop.look4sat.utility.round
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -37,19 +37,20 @@ import javax.inject.Inject
@HiltViewModel
class PassInfoViewModel @Inject constructor(
private val orientationProvider: OrientationProvider,
private val preferencesSource: PreferencesSource,
private val satPassRepository: SatPassRepository,
private val satDataRepository: SatDataRepository,
private val preferences: PreferencesSource,
private val passPredictor: PassPredictor,
private val satelliteRepo: SatelliteRepo,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : ViewModel(), OrientationProvider.OrientationListener {
private val stationPos = preferences.loadStationPosition()
private val _transmitters = MutableLiveData<List<SatTrans>>()
private val _orientation = MutableLiveData<Triple<Float, Float, Float>>()
val transmitters: LiveData<List<SatTrans>> = _transmitters
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
fun getPass(catNum: Int, aosTime: Long) = liveData {
satPassRepository.passes.collect { passes ->
passPredictor.passes.collect { passes ->
val pass = passes.find { it.catNum == catNum && it.aosTime == aosTime }
pass?.let { satPass ->
processTransmitters(satPass)
@@ -60,27 +61,27 @@ class PassInfoViewModel @Inject constructor(
}
fun enableSensor() {
if (preferencesSource.shouldUseCompass()) orientationProvider.startListening(this)
if (preferences.shouldUseCompass()) orientationProvider.startListening(this)
}
fun disableSensor() {
if (preferencesSource.shouldUseCompass()) orientationProvider.stopListening()
if (preferences.shouldUseCompass()) orientationProvider.stopListening()
}
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
_orientation.value = Triple(azimuth + preferencesSource.getMagDeclination(), pitch, roll)
_orientation.value = Triple(azimuth + preferences.getMagDeclination(), pitch, roll)
}
private fun initRotatorControl(satPass: SatPass) {
viewModelScope.launch {
val rotatorPrefs = preferencesSource.getRotatorServer()
val rotatorPrefs = preferences.getRotatorServer()
if (rotatorPrefs != null) {
runCatching {
withContext(ioDispatcher) {
val socket = Socket(rotatorPrefs.first, rotatorPrefs.second)
val writer = socket.getOutputStream().bufferedWriter()
while (isActive) {
val satPos = satPass.predictor.getSatPos(Date())
val satPos = satPass.satellite.getPosition(stationPos, Date().time)
val azimuth = Math.toDegrees(satPos.azimuth).round(1)
val elevation = Math.toDegrees(satPos.elevation).round(1)
writer.write("\\set_pos $azimuth $elevation")
@@ -97,16 +98,16 @@ class PassInfoViewModel @Inject constructor(
private fun processTransmitters(satPass: SatPass) {
viewModelScope.launch {
satDataRepository.getSatTransmitters(satPass.catNum).collect { transList ->
satelliteRepo.getSatTransmitters(satPass.catNum).collect { transList ->
while (isActive) {
val timeNow = Date()
val satPos = satPass.satellite.getPosition(stationPos, Date().time)
val copiedList = transList.map { it.copy() }
copiedList.forEach { transmitter ->
transmitter.downlink?.let {
transmitter.downlink = satPass.predictor.getDownlinkFreq(it, timeNow)
transmitter.downlink = satPos.getDownlinkFreq(it)
}
transmitter.uplink?.let {
transmitter.uplink = satPass.predictor.getUplinkFreq(it, timeNow)
transmitter.uplink = satPos.getUplinkFreq(it)
}
}
_transmitters.postValue(copiedList.map { it.copy() })
@@ -115,4 +116,4 @@ class PassInfoViewModel @Inject constructor(
}
}
}
}
}
@@ -24,7 +24,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.ItemTransBinding
import com.rtbishop.look4sat.domain.model.SatTrans
import com.rtbishop.look4sat.domain.SatTrans
import java.util.*
class SatTransAdapter : RecyclerView.Adapter<SatTransAdapter.TransHolder>() {
@@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.ItemPassGeoBinding
import com.rtbishop.look4sat.databinding.ItemPassLeoBinding
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatPass
import java.text.SimpleDateFormat
import java.util.*
@@ -29,7 +29,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentPassesBinding
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.framework.model.Result
import com.rtbishop.look4sat.utility.RecyclerDivider
import com.rtbishop.look4sat.utility.navigateSafe
@@ -22,9 +22,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatDataRepository
import com.rtbishop.look4sat.data.SatPassRepository
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.framework.model.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
@@ -33,8 +33,8 @@ import javax.inject.Inject
@HiltViewModel
class SatPassViewModel @Inject constructor(
private val satDataRepository: SatDataRepository,
private val satPassRepository: SatPassRepository,
private val satelliteRepo: SatelliteRepo,
private val passPredictor: PassPredictor,
private val preferencesSource: PreferencesSource
) : ViewModel() {
@@ -48,13 +48,14 @@ class SatPassViewModel @Inject constructor(
if (preferencesSource.isSetupDone()) {
viewModelScope.launch {
_passes.postValue(Result.InProgress)
satPassRepository.triggerCalculation(satDataRepository.getSelectedSatellites())
val stationPos = preferencesSource.loadStationPosition()
passPredictor.triggerCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
}
} else {
_isFirstLaunchDone.value = false
}
viewModelScope.launch {
satPassRepository.passes.collect { passes ->
passPredictor.passes.collect { passes ->
passesProcessing?.cancelAndJoin()
passesProcessing = viewModelScope.launch { tickPasses(passes) }
}
@@ -66,9 +67,10 @@ class SatPassViewModel @Inject constructor(
viewModelScope.launch {
_passes.postValue(Result.InProgress)
val defaultCatNums = listOf(43700, 25544, 25338, 28654, 33591, 40069, 27607, 24278)
satDataRepository.updateEntriesFromWeb(preferencesSource.loadDefaultSources())
satDataRepository.updateEntriesSelection(defaultCatNums, true)
satPassRepository.forceCalculation(satDataRepository.getSelectedSatellites())
val stationPos = preferencesSource.loadStationPosition()
satelliteRepo.updateEntriesFromWeb(preferencesSource.loadDefaultSources())
satelliteRepo.updateEntriesSelection(defaultCatNums, true)
passPredictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
preferencesSource.setSetupDone()
_isFirstLaunchDone.value = true
}
@@ -78,7 +80,8 @@ class SatPassViewModel @Inject constructor(
viewModelScope.launch {
_passes.postValue(Result.InProgress)
passesProcessing?.cancelAndJoin()
satPassRepository.forceCalculation(satDataRepository.getSelectedSatellites())
val stationPos = preferencesSource.loadStationPosition()
passPredictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
}
}
@@ -20,9 +20,9 @@ package com.rtbishop.look4sat.utility
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem
import com.rtbishop.look4sat.framework.model.SatTrans
import com.rtbishop.look4sat.domain.model.SatEntry as DomainEntry
import com.rtbishop.look4sat.domain.model.SatItem as DomainItem
import com.rtbishop.look4sat.domain.model.SatTrans as DomainTrans
import com.rtbishop.look4sat.domain.SatEntry as DomainEntry
import com.rtbishop.look4sat.domain.SatItem as DomainItem
import com.rtbishop.look4sat.domain.SatTrans as DomainTrans
object DataMapper {