From 549a915b2452e88f9f92476816247fa3497b2507 Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Sun, 17 Sep 2023 11:46:45 +0100 Subject: [PATCH] Slightly changed classes structure for readability --- .../com/rtbishop/look4sat/MainApplication.kt | 2 +- .../com/rtbishop/look4sat/MainContainer.kt | 33 +++------ .../look4sat/presentation/map/MapScreen.kt | 12 ++-- .../look4sat/presentation/map/MapViewModel.kt | 44 ++++++------ .../presentation/passes/PassesScreen.kt | 12 ++-- .../presentation/passes/PassesState.kt | 4 +- .../presentation/passes/PassesViewModel.kt | 4 +- .../look4sat/presentation/radar/RadarData.kt | 4 +- .../presentation/radar/RadarScreen.kt | 2 +- .../look4sat/presentation/radar/RadarView.kt | 8 +-- .../presentation/radar/RadarViewModel.kt | 50 ++++++------- .../{dao/StorageDao.kt => Look4SatDao.kt} | 9 ++- .../{MainDatabase.kt => Look4SatDb.kt} | 5 +- .../look4sat/data/database/entity/SatEntry.kt | 15 +++- .../look4sat/data/database/entity/SatItem.kt | 20 ------ .../look4sat/data/database/entity/SatRadio.kt | 3 +- .../look4sat/data/repository/DatabaseRepo.kt | 31 ++++---- .../look4sat/data/repository/SatelliteRepo.kt | 45 ++++++------ .../look4sat/data/repository/SelectionRepo.kt | 3 +- .../SensorsRepo.kt} | 10 +-- .../look4sat/data/source/FileSource.kt | 16 ----- .../look4sat/data/source/LocalSource.kt | 60 ++++++++-------- .../look4sat/data/source/RemoteSource.kt | 24 +++++-- .../look4sat/domain/model/SatEntry.kt | 22 ------ .../rtbishop/look4sat/domain/model/SatItem.kt | 2 +- .../look4sat/domain/model/SatRadio.kt | 3 +- .../look4sat/domain/predict/Constants.kt | 20 ++++++ ...epSpaceSatellite.kt => DeepSpaceObject.kt} | 2 +- ...arEarthSatellite.kt => NearEarthObject.kt} | 2 +- .../look4sat/domain/predict/OrbitalData.kt | 19 +++-- .../{Satellite.kt => OrbitalObject.kt} | 71 +++++++------------ .../predict/{SatPass.kt => OrbitalPass.kt} | 10 +-- .../predict/{SatPos.kt => OrbitalPos.kt} | 2 +- .../domain/repository/ISatelliteRepo.kt | 18 ++--- .../ISensorsRepo.kt} | 4 +- .../domain/repository/ISettingsRepo.kt | 31 -------- .../look4sat/domain/source/IFileSource.kt | 24 ------- .../look4sat/domain/source/ILocalSource.kt | 8 +-- .../look4sat/domain/source/IRemoteSource.kt | 3 +- .../look4sat/domain/source/Sources.kt | 33 +++++++++ 40 files changed, 309 insertions(+), 381 deletions(-) rename data/src/main/java/com/rtbishop/look4sat/data/database/{dao/StorageDao.kt => Look4SatDao.kt} (90%) rename data/src/main/java/com/rtbishop/look4sat/data/database/{MainDatabase.kt => Look4SatDb.kt} (93%) delete mode 100644 data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatItem.kt rename data/src/main/java/com/rtbishop/look4sat/data/{source/SensorSource.kt => repository/SensorsRepo.kt} (91%) delete mode 100644 data/src/main/java/com/rtbishop/look4sat/data/source/FileSource.kt delete mode 100644 domain/src/main/java/com/rtbishop/look4sat/domain/model/SatEntry.kt create mode 100644 domain/src/main/java/com/rtbishop/look4sat/domain/predict/Constants.kt rename domain/src/main/java/com/rtbishop/look4sat/domain/predict/{DeepSpaceSatellite.kt => DeepSpaceObject.kt} (99%) rename domain/src/main/java/com/rtbishop/look4sat/domain/predict/{NearEarthSatellite.kt => NearEarthObject.kt} (99%) rename domain/src/main/java/com/rtbishop/look4sat/domain/predict/{Satellite.kt => OrbitalObject.kt} (88%) rename domain/src/main/java/com/rtbishop/look4sat/domain/predict/{SatPass.kt => OrbitalPass.kt} (82%) rename domain/src/main/java/com/rtbishop/look4sat/domain/predict/{SatPos.kt => OrbitalPos.kt} (99%) rename domain/src/main/java/com/rtbishop/look4sat/domain/{source/ISensorSource.kt => repository/ISensorsRepo.kt} (66%) delete mode 100644 domain/src/main/java/com/rtbishop/look4sat/domain/source/IFileSource.kt create mode 100644 domain/src/main/java/com/rtbishop/look4sat/domain/source/Sources.kt diff --git a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt index de17c141..b3457a89 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainApplication.kt @@ -35,7 +35,7 @@ class MainApplication : Application() { enableStrictMode() super.onCreate() container = MainContainer(this) - container.mainScope.launch { checkAutoUpdate() } + container.appScope.launch { checkAutoUpdate() } } private suspend fun checkAutoUpdate() { diff --git a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt index b87edbdd..23620a6e 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainContainer.kt @@ -6,25 +6,23 @@ import android.hardware.Sensor import android.hardware.SensorManager import android.location.LocationManager import androidx.room.Room -import com.rtbishop.look4sat.data.database.MainDatabase +import com.rtbishop.look4sat.data.database.Look4SatDb import com.rtbishop.look4sat.data.framework.BluetoothReporter import com.rtbishop.look4sat.data.framework.NetworkReporter import com.rtbishop.look4sat.data.repository.DatabaseRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo import com.rtbishop.look4sat.data.repository.SelectionRepo +import com.rtbishop.look4sat.data.repository.SensorsRepo import com.rtbishop.look4sat.data.repository.SettingsRepo -import com.rtbishop.look4sat.data.source.FileSource import com.rtbishop.look4sat.data.source.LocalSource import com.rtbishop.look4sat.data.source.RemoteSource -import com.rtbishop.look4sat.data.source.SensorSource import com.rtbishop.look4sat.domain.repository.IDatabaseRepo import com.rtbishop.look4sat.domain.repository.ISatelliteRepo import com.rtbishop.look4sat.domain.repository.ISelectionRepo +import com.rtbishop.look4sat.domain.repository.ISensorsRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo -import com.rtbishop.look4sat.domain.source.IFileSource import com.rtbishop.look4sat.domain.source.ILocalSource import com.rtbishop.look4sat.domain.source.IRemoteSource -import com.rtbishop.look4sat.domain.source.ISensorSource import com.rtbishop.look4sat.domain.utility.DataParser import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope @@ -37,7 +35,8 @@ import org.osmdroid.config.Configuration class MainContainer(private val context: Context) { private val localSource = provideLocalSource() - val mainScope = provideMainScope() + private val mainHandler = CoroutineExceptionHandler { _, error -> println("MainHandler: $error") } + val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler) val settingsRepo = provideSettingsRepo() val selectionRepo = provideSelectionRepo() val satelliteRepo = provideSatelliteRepo() @@ -52,40 +51,30 @@ class MainContainer(private val context: Context) { return NetworkReporter(CoroutineScope(Dispatchers.IO)) } - fun provideSensorSource(): ISensorSource { + fun provideSensorsRepo(): ISensorsRepo { val manager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor = manager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) - return SensorSource(manager, sensor) + return SensorsRepo(manager, sensor) } private fun provideDatabaseRepo(): IDatabaseRepo { val dataParser = DataParser(Dispatchers.Default) - val fileSource = provideFileSource() val remoteSource = provideRemoteSource() - return DatabaseRepo(Dispatchers.Default, dataParser, fileSource, localSource, remoteSource, settingsRepo) - } - - private fun provideFileSource(): IFileSource { - return FileSource(context.contentResolver, Dispatchers.IO) + return DatabaseRepo(Dispatchers.Default, dataParser, localSource, remoteSource, settingsRepo) } private fun provideLocalSource(): ILocalSource { - val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDBv313").apply { + val database = Room.databaseBuilder(context, Look4SatDb::class.java, "Look4SatDBv313").apply { // addMigrations(MIGRATION_1_2) fallbackToDestructiveMigration() }.build() - return LocalSource(database.storageDao()) - } - - private fun provideMainScope(): CoroutineScope { - val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") } - return CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler) + return LocalSource(database.look4SatDao()) } private fun provideRemoteSource(): IRemoteSource { val cache = Cache(context.cacheDir, MainApplication.MAX_OKHTTP_CACHE_SIZE) val httpClient = OkHttpClient.Builder().cache(cache).build() - return RemoteSource(httpClient, Dispatchers.IO) + return RemoteSource(context.contentResolver, httpClient, Dispatchers.IO) } private fun provideSatelliteRepo(): ISatelliteRepo { diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt index 5a259e2c..40c2604d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt @@ -29,8 +29,8 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.rtbishop.look4sat.R import com.rtbishop.look4sat.domain.predict.GeoPos -import com.rtbishop.look4sat.domain.predict.SatPos -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalObject +import com.rtbishop.look4sat.domain.predict.OrbitalPos import org.osmdroid.tileprovider.tilesource.XYTileSource import org.osmdroid.util.GeoPoint import org.osmdroid.views.CustomZoomButtonsController @@ -69,7 +69,7 @@ fun MapScreen() { val positions = viewModel.positions.collectAsState(initial = null) val satTrack = viewModel.track.collectAsState(initial = null) val footprint = viewModel.footprint.collectAsState(initial = null) - val positionClick = { satellite: Satellite -> viewModel.selectSatellite(satellite) } + val positionClick = { orbitalObject: OrbitalObject -> viewModel.selectSatellite(orbitalObject) } Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) { ElevatedCard(modifier = Modifier.fillMaxSize()) { MapView(modifier = Modifier.fillMaxSize()) { mapView -> @@ -97,7 +97,7 @@ private fun setStationPosition(stationPos: GeoPos, mapView: MapView) { } } -private fun setPositions(posMap: Map, mapView: MapView, action: (Satellite) -> Unit) { +private fun setPositions(posMap: Map, mapView: MapView, action: (OrbitalObject) -> Unit) { val markers = FolderOverlay() try { posMap.entries.forEach { @@ -156,8 +156,8 @@ private fun setSatelliteTrack(satTrack: List>, mapView: MapView) { // mapView.controller.animateTo(center) } -private fun setFootprint(satPos: SatPos, mapView: MapView) { - val footprintPoints = satPos.getRangeCircle().map { GeoPoint(it.latitude, it.longitude) } +private fun setFootprint(orbitalPos: OrbitalPos, mapView: MapView) { + val footprintPoints = orbitalPos.getRangeCircle().map { GeoPoint(it.latitude, it.longitude) } try { val footprintOverlay = Polyline().apply { outlinePaint.set(footprintPaint) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt index 1f7e5d7a..57b74929 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapViewModel.kt @@ -24,8 +24,8 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.rtbishop.look4sat.MainApplication import com.rtbishop.look4sat.domain.predict.GeoPos -import com.rtbishop.look4sat.domain.predict.SatPos -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalObject +import com.rtbishop.look4sat.domain.predict.OrbitalPos import com.rtbishop.look4sat.domain.repository.ISatelliteRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo import com.rtbishop.look4sat.domain.utility.clipLat @@ -51,7 +51,7 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet private var allSatellites = satelliteRepo.satellites.value private var dataUpdateJob: Job? = null private var dataUpdateRate = 1000L - private var selectedSatellite: Satellite? = null + private var selectedOrbitalObject: OrbitalObject? = null val stationPosition = flow { val osmLat = clipLat(stationPos.latitude) @@ -62,14 +62,14 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet private val _track = MutableSharedFlow>>() val track: SharedFlow>> = _track - private val _footprint = MutableSharedFlow() - val footprint: SharedFlow = _footprint + private val _footprint = MutableSharedFlow() + val footprint: SharedFlow = _footprint private val _mapData = MutableSharedFlow() // val mapData: SharedFlow = _mapData - private val _positions = MutableSharedFlow>() - val positions: SharedFlow> = _positions + private val _positions = MutableSharedFlow>() + val positions: SharedFlow> = _positions // fun scrollSelection(decrement: Boolean) { // if (allSatellites.isNotEmpty()) { @@ -88,37 +88,37 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet if (allSatellites.isNotEmpty()) { if (catnum == -1) { allPasses.find { pass -> pass.progress < 100 && !pass.isDeepSpace } - ?.let { pass -> selectSatellite(pass.satellite) } + ?.let { pass -> selectSatellite(pass.orbitalObject) } } else { allSatellites.find { it.data.catnum == catnum }?.let { selectSatellite(it) } } } } - fun selectSatellite(satellite: Satellite, updateFreq: Long = dataUpdateRate) { - selectedSatellite = satellite + fun selectSatellite(orbitalObject: OrbitalObject, updateFreq: Long = dataUpdateRate) { + selectedOrbitalObject = orbitalObject viewModelScope.launch { dataUpdateJob?.cancelAndJoin() dataUpdateJob = launch { val dateNow = Date() - getSatTrack(satellite, stationPos, dateNow) + getSatTrack(orbitalObject, stationPos, dateNow) while (isActive) { dateNow.time = System.currentTimeMillis() getPositions(allSatellites, stationPos, dateNow) - getSatFootprint(satellite, stationPos, dateNow) - getSatData(satellite, stationPos, dateNow) + getSatFootprint(orbitalObject, stationPos, dateNow) + getSatData(orbitalObject, stationPos, dateNow) delay(updateFreq) } } } } - private suspend fun getSatTrack(satellite: Satellite, pos: GeoPos, date: Date) { + private suspend fun getSatTrack(orbitalObject: OrbitalObject, pos: GeoPos, date: Date) { val satTracks = mutableListOf>() val currentTrack = mutableListOf() - val endDate = Date(date.time + (satellite.data.orbitalPeriod * 2.4 * 60000L).toLong()) + val endDate = Date(date.time + (orbitalObject.data.orbitalPeriod * 2.4 * 60000L).toLong()) var oldLongitude = 0.0 - satelliteRepo.getTrack(satellite, pos, date.time, endDate.time).forEach { satPos -> + satelliteRepo.getTrack(orbitalObject, pos, date.time, endDate.time).forEach { satPos -> val osmLat = clipLat(satPos.latitude.toDegrees()) val osmLon = clipLon(satPos.longitude.toDegrees()) val currentPosition = GeoPos(osmLat, osmLon) @@ -142,9 +142,9 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet _track.emit(satTracks) } - private suspend fun getPositions(satellites: List, pos: GeoPos, date: Date) { - val positions = mutableMapOf() - satellites.forEach { satellite -> + private suspend fun getPositions(orbitalObjects: List, pos: GeoPos, date: Date) { + val positions = mutableMapOf() + orbitalObjects.forEach { satellite -> val satPos = satelliteRepo.getPosition(satellite, pos, date.time) val osmLat = clipLat(satPos.latitude.toDegrees()) val osmLon = clipLon(satPos.longitude.toDegrees()) @@ -153,12 +153,12 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet _positions.emit(positions) } - private suspend fun getSatFootprint(satellite: Satellite, pos: GeoPos, date: Date) { - val satPos = satelliteRepo.getPosition(satellite, pos, date.time) + private suspend fun getSatFootprint(orbitalObject: OrbitalObject, pos: GeoPos, date: Date) { + val satPos = satelliteRepo.getPosition(orbitalObject, pos, date.time) _footprint.emit(satPos) } - private suspend fun getSatData(sat: Satellite, pos: GeoPos, date: Date) { + private suspend fun getSatData(sat: OrbitalObject, pos: GeoPos, date: Date) { var aosTime = 0L.toTimerString() allPasses.find { pass -> pass.catNum == sat.data.catnum && pass.progress < 100 } ?.let { satPass -> diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt index 4d689d92..fecee83c 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt @@ -36,9 +36,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.rtbishop.look4sat.R -import com.rtbishop.look4sat.domain.predict.NearEarthSatellite +import com.rtbishop.look4sat.domain.predict.NearEarthObject import com.rtbishop.look4sat.domain.predict.OrbitalData -import com.rtbishop.look4sat.domain.predict.SatPass +import com.rtbishop.look4sat.domain.predict.OrbitalPass import com.rtbishop.look4sat.presentation.MainTheme import com.rtbishop.look4sat.presentation.components.PullRefreshIndicator import com.rtbishop.look4sat.presentation.components.PullRefreshState @@ -114,13 +114,13 @@ private fun PassPreview() { val data = OrbitalData( "Satellite", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 45000, 0.0 ) - val satellite = NearEarthSatellite(data) - val pass = SatPass(1L, 0.0, 10L, 180.0, 850, 45.0, satellite, 0.5f) + val satellite = NearEarthObject(data) + val pass = OrbitalPass(1L, 0.0, 10L, 180.0, 850, 45.0, satellite, 0.5f) MainTheme { Pass(pass = pass, { _, _ -> }) } } @Composable -private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modifier = Modifier) { +private fun Pass(pass: OrbitalPass, navToRadar: (Int, Long) -> Unit, modifier: Modifier = Modifier) { Surface(color = MaterialTheme.colorScheme.background, modifier = modifier) { Surface(modifier = Modifier .padding(bottom = 2.dp) @@ -207,7 +207,7 @@ private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modif @OptIn(ExperimentalFoundationApi::class) @Composable private fun PassesCard( - refreshState: PullRefreshState, isRefreshing: Boolean, passes: List, navToRadar: (Int, Long) -> Unit + refreshState: PullRefreshState, isRefreshing: Boolean, passes: List, navToRadar: (Int, Long) -> Unit ) { ElevatedCard(modifier = Modifier.fillMaxSize()) { Box(Modifier.pullRefresh(refreshState)) { diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesState.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesState.kt index ec0da19e..41cfb46f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesState.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesState.kt @@ -1,6 +1,6 @@ package com.rtbishop.look4sat.presentation.passes -import com.rtbishop.look4sat.domain.predict.SatPass +import com.rtbishop.look4sat.domain.predict.OrbitalPass data class PassesState( val isDialogShown: Boolean, @@ -12,7 +12,7 @@ data class PassesState( val hours: Int, val elevation: Double, val modes: List, - val itemsList: List, + val itemsList: List, val takeAction: (PassesAction) -> Unit ) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt index c8ba1e61..90535c28 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesViewModel.kt @@ -26,7 +26,7 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.rtbishop.look4sat.MainApplication import com.rtbishop.look4sat.domain.model.PassesSettings -import com.rtbishop.look4sat.domain.predict.SatPass +import com.rtbishop.look4sat.domain.predict.OrbitalPass import com.rtbishop.look4sat.domain.repository.ISatelliteRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo import com.rtbishop.look4sat.domain.utility.toTimerString @@ -99,7 +99,7 @@ class PassesViewModel( satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes) } - private fun setPassInfo(passes: List, timeNow: Long) { + private fun setPassInfo(passes: List, timeNow: Long) { if (passes.isEmpty()) return try { val nextPass = passes.first { it.aosTime.minus(timeNow) > 0 } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarData.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarData.kt index 7a27df5b..a8a0325d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarData.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarData.kt @@ -17,6 +17,6 @@ */ package com.rtbishop.look4sat.presentation.radar -import com.rtbishop.look4sat.domain.predict.SatPos +import com.rtbishop.look4sat.domain.predict.OrbitalPos -data class RadarData(val satPos: SatPos, val satTrack: List = emptyList()) +data class RadarData(val orbitalPos: OrbitalPos, val satTrack: List = emptyList()) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt index 069e381f..79cd7d24 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt @@ -69,7 +69,7 @@ fun RadarScreen() { ) { viewModel.radarData.value?.let { data -> RadarViewCompose( - item = data.satPos, + item = data.orbitalPos, items = data.satTrack, azimElev = viewModel.orientation.value ) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarView.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarView.kt index 0fff1ea9..b0d467c3 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarView.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarView.kt @@ -29,14 +29,14 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.drawText import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.unit.sp +import com.rtbishop.look4sat.domain.predict.OrbitalPos import com.rtbishop.look4sat.domain.predict.PI_2 -import com.rtbishop.look4sat.domain.predict.SatPos import com.rtbishop.look4sat.domain.utility.toRadians import kotlin.math.cos import kotlin.math.sin @Composable -fun RadarViewCompose(item: SatPos, items: List, azimElev: Pair) { +fun RadarViewCompose(item: OrbitalPos, items: List, azimElev: Pair) { val radarColor = Color(0xFFDCDCDC) val primaryColor = Color(0xFFFFE082) val secondaryColor = Color(0xFFDC0000) @@ -92,7 +92,7 @@ private fun DrawScope.drawTrack(path: Path, effect: PathEffect, color: Color, ef drawPath(path, effectColor, style = Stroke(pathEffect = effect)) } -private fun DrawScope.drawPosition(item: SatPos, radius: Float, posRadius: Float, color: Color) { +private fun DrawScope.drawPosition(item: OrbitalPos, radius: Float, posRadius: Float, color: Color) { val satX = sph2CartX(item.azimuth, item.elevation, radius.toDouble()) val satY = sph2CartY(item.azimuth, item.elevation, radius.toDouble()) drawCircle(color, 16f, center.copy(satX, -satY)) @@ -122,7 +122,7 @@ private fun DrawScope.drawSweep(center: Offset, degrees: Float, radius: Float, c rotate(-90 + degrees, center) { drawCircle(brush, radius, style = Fill) } } -private fun createTrackPath(positions: List, radius: Float): Path { +private fun createTrackPath(positions: List, radius: Float): Path { val trackPath = Path() positions.forEachIndexed { index, satPos -> val passX = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble()) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt index ce8556d4..87b09292 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarViewModel.kt @@ -32,12 +32,12 @@ import com.rtbishop.look4sat.data.framework.BluetoothReporter import com.rtbishop.look4sat.data.framework.NetworkReporter import com.rtbishop.look4sat.domain.model.SatRadio import com.rtbishop.look4sat.domain.predict.GeoPos -import com.rtbishop.look4sat.domain.predict.SatPass -import com.rtbishop.look4sat.domain.predict.SatPos -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalObject +import com.rtbishop.look4sat.domain.predict.OrbitalPass +import com.rtbishop.look4sat.domain.predict.OrbitalPos import com.rtbishop.look4sat.domain.repository.ISatelliteRepo +import com.rtbishop.look4sat.domain.repository.ISensorsRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo -import com.rtbishop.look4sat.domain.source.ISensorSource import com.rtbishop.look4sat.domain.utility.round import com.rtbishop.look4sat.domain.utility.toDegrees import kotlinx.coroutines.delay @@ -51,20 +51,20 @@ class RadarViewModel( private val networkReporter: NetworkReporter, private val satelliteRepo: ISatelliteRepo, private val settingsRepo: ISettingsRepo, - private val sensorSource: ISensorSource + private val sensorsRepo: ISensorsRepo ) : ViewModel() { private val stationPos = settingsRepo.stationPosition.value private val magDeclination = getMagDeclination(stationPos) val transmitters = mutableStateOf>(emptyList()) val radarData = mutableStateOf(null) - val orientation = mutableStateOf(sensorSource.orientation.value) + val orientation = mutableStateOf(sensorsRepo.orientation.value) init { if (settingsRepo.otherSettings.value.stateOfSensors) { viewModelScope.launch { - sensorSource.enableSensor() - sensorSource.orientation.collect { data -> + sensorsRepo.enableSensor() + sensorsRepo.orientation.collect { data -> orientation.value = Pair(data.first + magDeclination, data.second) } } @@ -72,7 +72,7 @@ class RadarViewModel( } override fun onCleared() { - sensorSource.disableSensor() + sensorsRepo.disableSensor() super.onCleared() } @@ -89,10 +89,10 @@ class RadarViewModel( while (isActive) { val timeNow = System.currentTimeMillis() val satPos = - satelliteRepo.getPosition(satPass.satellite, stationPos, timeNow) - sendPassData(satPass, satPos, satPass.satellite) + satelliteRepo.getPosition(satPass.orbitalObject, stationPos, timeNow) + sendPassData(satPass, satPos, satPass.orbitalObject) sendPassDataBT(satPos) - processRadios(transmitters, satPass.satellite, timeNow) + processRadios(transmitters, satPass.orbitalObject, timeNow) delay(1000) } } @@ -109,33 +109,33 @@ class RadarViewModel( return GeomagneticField(latitude, longitude, geoPos.altitude.toFloat(), time).declination } - private fun sendPassData(satPass: SatPass, satPos: SatPos, satellite: Satellite) { + private fun sendPassData(orbitalPass: OrbitalPass, orbitalPos: OrbitalPos, orbitalObject: OrbitalObject) { viewModelScope.launch { - var track: List = emptyList() - if (!satPass.isDeepSpace) { + var track: List = emptyList() + if (!orbitalPass.isDeepSpace) { track = satelliteRepo.getTrack( - satellite, stationPos, satPass.aosTime, satPass.losTime + orbitalObject, stationPos, orbitalPass.aosTime, orbitalPass.losTime ) } if (settingsRepo.getRotatorState()) { val server = settingsRepo.getRotatorAddress() val port = settingsRepo.getRotatorPort().toInt() - val azimuth = satPos.azimuth.toDegrees().round(1) - val elevation = satPos.elevation.toDegrees().round(1) + val azimuth = orbitalPos.azimuth.toDegrees().round(1) + val elevation = orbitalPos.elevation.toDegrees().round(1) networkReporter.reportRotation(server, port, azimuth, elevation) } - radarData.value = RadarData(satPos, track) + radarData.value = RadarData(orbitalPos, track) } } - private fun sendPassDataBT(satPos: SatPos) { + private fun sendPassDataBT(orbitalPos: OrbitalPos) { viewModelScope.launch { if (settingsRepo.getBluetoothState()) { val btDevice = settingsRepo.getBluetoothAddress() if (bluetoothReporter.isConnected()) { val format = settingsRepo.getBluetoothFormat() - val azimuth = satPos.azimuth.toDegrees().round(0).toInt() - val elevation = satPos.elevation.toDegrees().round(0).toInt() + val azimuth = orbitalPos.azimuth.toDegrees().round(0).toInt() + val elevation = orbitalPos.elevation.toDegrees().round(0).toInt() bluetoothReporter.reportRotation(format, azimuth, elevation) } else if (!bluetoothReporter.isConnecting()) { Log.i("BTReporter", "BTReporter: Attempting to connect...") @@ -145,10 +145,10 @@ class RadarViewModel( } } - private fun processRadios(radios: List, satellite: Satellite, time: Long) { + private fun processRadios(radios: List, orbitalObject: OrbitalObject, time: Long) { viewModelScope.launch { delay(125) - val list = satelliteRepo.getRadios(satellite, stationPos, radios, time) + val list = satelliteRepo.getRadios(orbitalObject, stationPos, radios, time) transmitters.value = list } } @@ -164,7 +164,7 @@ class RadarViewModel( container.provideNetworkReporter(), container.satelliteRepo, container.settingsRepo, - container.provideSensorSource() + container.provideSensorsRepo() ) } } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/database/dao/StorageDao.kt b/data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDao.kt similarity index 90% rename from data/src/main/java/com/rtbishop/look4sat/data/database/dao/StorageDao.kt rename to data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDao.kt index 07231779..2d4a293e 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/database/dao/StorageDao.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDao.kt @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.rtbishop.look4sat.data.database.dao +package com.rtbishop.look4sat.data.database import androidx.room.Dao import androidx.room.Insert @@ -23,17 +23,16 @@ import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Transaction import com.rtbishop.look4sat.data.database.entity.SatEntry -import com.rtbishop.look4sat.data.database.entity.SatItem import com.rtbishop.look4sat.data.database.entity.SatRadio +import com.rtbishop.look4sat.domain.model.SatItem @Dao -interface StorageDao { +interface Look4SatDao { @Query("SELECT COUNT(*) FROM entries") suspend fun getEntriesTotal(): Int - //@Transaction - @Query("SELECT catnum, name FROM entries ORDER BY name ASC") + @Query("SELECT catnum, name, 0 as isSelected FROM entries ORDER BY name ASC") suspend fun getEntriesList(): List @Transaction diff --git a/data/src/main/java/com/rtbishop/look4sat/data/database/MainDatabase.kt b/data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDb.kt similarity index 93% rename from data/src/main/java/com/rtbishop/look4sat/data/database/MainDatabase.kt rename to data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDb.kt index e0a972bf..7d978f6e 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/database/MainDatabase.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/database/Look4SatDb.kt @@ -19,13 +19,12 @@ package com.rtbishop.look4sat.data.database import androidx.room.Database import androidx.room.RoomDatabase -import com.rtbishop.look4sat.data.database.dao.StorageDao import com.rtbishop.look4sat.data.database.entity.SatEntry import com.rtbishop.look4sat.data.database.entity.SatRadio @Database(entities = [SatEntry::class, SatRadio::class], version = 1, exportSchema = false) -abstract class MainDatabase : RoomDatabase() { - abstract fun storageDao(): StorageDao +abstract class Look4SatDb : RoomDatabase() { + abstract fun look4SatDao(): Look4SatDao } //val MIGRATION_1_2 = object : Migration(1, 2) { diff --git a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatEntry.kt b/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatEntry.kt index 15a975c2..76c39caf 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatEntry.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatEntry.kt @@ -17,9 +17,18 @@ */ package com.rtbishop.look4sat.data.database.entity -import androidx.room.Embedded import androidx.room.Entity -import com.rtbishop.look4sat.domain.predict.OrbitalData @Entity(tableName = "entries", primaryKeys = ["catnum"]) -data class SatEntry(@Embedded val data: OrbitalData, var comment: String? = null) +data class SatEntry( + val name: String, + val epoch: Double, + val meanmo: Double, + val eccn: Double, + val incl: Double, + val raan: Double, + val argper: Double, + val meanan: Double, + val catnum: Int, + val bstar: Double +) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatItem.kt b/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatItem.kt deleted file mode 100644 index c67f0711..00000000 --- a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatItem.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.rtbishop.look4sat.data.database.entity - -data class SatItem(val catnum: Int, val name: String) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatRadio.kt b/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatRadio.kt index 5f04a703..fe7ddb50 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatRadio.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/database/entity/SatRadio.kt @@ -32,6 +32,5 @@ data class SatRadio( var uplinkHigh: Long?, val uplinkMode: String?, val isInverted: Boolean, - val catnum: Int?, - var comment: String? = null + val catnum: Int? ) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt index 0b444925..ec24465e 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/DatabaseRepo.kt @@ -18,15 +18,14 @@ package com.rtbishop.look4sat.data.repository import com.rtbishop.look4sat.domain.model.DatabaseState -import com.rtbishop.look4sat.domain.model.SatEntry import com.rtbishop.look4sat.domain.model.SatRadio +import com.rtbishop.look4sat.domain.predict.OrbitalData import com.rtbishop.look4sat.domain.repository.IDatabaseRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo -import com.rtbishop.look4sat.domain.source.IFileSource import com.rtbishop.look4sat.domain.source.ILocalSource import com.rtbishop.look4sat.domain.source.IRemoteSource +import com.rtbishop.look4sat.domain.source.Sources import com.rtbishop.look4sat.domain.utility.DataParser -import java.io.InputStream import java.util.zip.ZipInputStream import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async @@ -35,32 +34,31 @@ import kotlinx.coroutines.withContext class DatabaseRepo( private val dispatcher: CoroutineDispatcher, private val dataParser: DataParser, - private val fileSource: IFileSource, private val localSource: ILocalSource, private val remoteSource: IRemoteSource, private val settingsRepo: ISettingsRepo ) : IDatabaseRepo { override suspend fun updateFromFile(uri: String) = withContext(dispatcher) { - val importedSatellites = fileSource.getFileStream(uri)?.let { importSatellites(it) } + val importedSatellites = remoteSource.getFileStream(uri)?.let { dataParser.parseTLEStream(it) } importedSatellites?.let { localSource.insertEntries(it) } setUpdateSuccessful(System.currentTimeMillis()) } override suspend fun updateFromRemote() = withContext(dispatcher) { - val importedEntries = mutableListOf() + val importedEntries = mutableListOf() val importedRadios = mutableListOf() // fetch - val jobsMap = settingsRepo.satelliteSourcesMap.mapValues { async { remoteSource.getRemoteStream(it.value) } } - val jobRadios = async { remoteSource.getRemoteStream(settingsRepo.radioSourceUrl) } + val jobsMap = Sources.satelliteDataUrls.mapValues { async { remoteSource.getNetworkStream(it.value) } } + val jobRadios = async { remoteSource.getNetworkStream(Sources.radioDataUrl) } // parse jobsMap.mapValues { job -> job.value.await() }.forEach { entry -> entry.value?.let { stream -> when (val type = entry.key) { "Amsat", "R4UAB" -> { // parse tle stream - val satellites = importSatellites(stream) - val catnums = satellites.map { it.data.catnum } + val satellites = dataParser.parseTLEStream(stream) + val catnums = satellites.map { it.catnum } settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } @@ -68,17 +66,16 @@ class DatabaseRepo( "McCants", "Classified" -> { // unzip and parse tle stream val unzipped = ZipInputStream(stream).apply { nextEntry } - val satellites = importSatellites(unzipped) - val catnums = satellites.map { it.data.catnum } + val satellites = dataParser.parseTLEStream(unzipped) + val catnums = satellites.map { it.catnum } settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } else -> { // parse csv stream - val parsed = dataParser.parseCSVStream(stream) - val satellites = parsed.map { data -> SatEntry(data) } - val catnums = satellites.map { it.data.catnum } + val satellites = dataParser.parseCSVStream(stream) + val catnums = satellites.map { it.catnum } settingsRepo.setSatelliteTypeIds(type, catnums) importedEntries.addAll(satellites) } @@ -103,8 +100,4 @@ class DatabaseRepo( val numberOfSatellites = localSource.getEntriesTotal() settingsRepo.updateDatabaseState(DatabaseState(numberOfRadios, numberOfSatellites, timestamp)) } - - private suspend fun importSatellites(stream: InputStream): List { - return dataParser.parseTLEStream(stream).map { data -> SatEntry(data) } - } } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt index 5ec57cf2..44c0969f 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt @@ -19,9 +19,9 @@ package com.rtbishop.look4sat.data.repository import com.rtbishop.look4sat.domain.model.SatRadio import com.rtbishop.look4sat.domain.predict.GeoPos -import com.rtbishop.look4sat.domain.predict.SatPass -import com.rtbishop.look4sat.domain.predict.SatPos -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalObject +import com.rtbishop.look4sat.domain.predict.OrbitalPass +import com.rtbishop.look4sat.domain.predict.OrbitalPos import com.rtbishop.look4sat.domain.repository.ISatelliteRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo import com.rtbishop.look4sat.domain.source.ILocalSource @@ -39,11 +39,11 @@ class SatelliteRepo( private val settingsRepo: ISettingsRepo ) : ISatelliteRepo { - private val _passes = MutableStateFlow>(emptyList()) - override val passes: StateFlow> = _passes + private val _passes = MutableStateFlow>(emptyList()) + override val passes: StateFlow> = _passes - private val _satellites = MutableStateFlow>(emptyList()) - override val satellites: StateFlow> = _satellites + private val _satellites = MutableStateFlow>(emptyList()) + override val satellites: StateFlow> = _satellites override suspend fun getRadiosWithId(id: Int) = localStorage.getRadiosWithId(id) @@ -55,13 +55,13 @@ class SatelliteRepo( } } - override suspend fun getPosition(sat: Satellite, pos: GeoPos, time: Long): SatPos { + override suspend fun getPosition(sat: OrbitalObject, pos: GeoPos, time: Long): OrbitalPos { return withContext(dispatcher) { sat.getPosition(pos, time) } } - override suspend fun getTrack(sat: Satellite, pos: GeoPos, start: Long, end: Long): List { + override suspend fun getTrack(sat: OrbitalObject, pos: GeoPos, start: Long, end: Long): List { return withContext(dispatcher) { - val positions = mutableListOf() + val positions = mutableListOf() var currentTime = start while (currentTime < end) { positions.add(sat.getPosition(pos, currentTime)) @@ -71,7 +71,12 @@ class SatelliteRepo( } } - override suspend fun getRadios(sat: Satellite, pos: GeoPos, radios: List, time: Long): List { + override suspend fun getRadios( + sat: OrbitalObject, + pos: GeoPos, + radios: List, + time: Long + ): List { return withContext(dispatcher) { val satPos = sat.getPosition(pos, time) val copiedList = radios.map { it.copy() } @@ -83,7 +88,7 @@ class SatelliteRepo( } } - override suspend fun processPasses(passList: List, time: Long): List { + override suspend fun processPasses(passList: List, time: Long): List { return withContext(dispatcher) { passList.forEach { pass -> if (!pass.isDeepSpace) { @@ -102,7 +107,7 @@ class SatelliteRepo( override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List) { if (_satellites.value.isNotEmpty()) { withContext(dispatcher) { - val newPasses = mutableListOf() + val newPasses = mutableListOf() val idsWithModes = localStorage.getIdsWithModes(modes) _satellites.value.forEach { satellite -> if (idsWithModes.isEmpty() || satellite.data.catnum in idsWithModes) { @@ -116,8 +121,8 @@ class SatelliteRepo( } } - private fun Satellite.getPasses(pos: GeoPos, time: Long, hours: Int): List { - val passes = mutableListOf() + private fun OrbitalObject.getPasses(pos: GeoPos, time: Long, hours: Int): List { + val passes = mutableListOf() val endDate = time + hours * 60L * 60L * 1000L val quarterOrbitMin = (this.data.orbitalPeriod / 4.0).toInt() var startDate = time @@ -141,23 +146,23 @@ class SatelliteRepo( return passes } - private fun List.filter(time: Long, hoursAhead: Int, minElev: Double): List { + private fun List.filter(time: Long, hoursAhead: Int, minElev: Double): List { val timeFuture = time + (hoursAhead * 60L * 60L * 1000L) return this.filter { it.losTime > time }.filter { it.aosTime < timeFuture } .filter { it.maxElevation > minElev }.sortedBy { it.aosTime } } - private fun getGeoPass(sat: Satellite, pos: GeoPos, time: Long): SatPass { + private fun getGeoPass(sat: OrbitalObject, pos: GeoPos, time: Long): OrbitalPass { val satPos = sat.getPosition(pos, time) val aos = time - 24 * 60L * 60L * 1000L val los = time + 24 * 60L * 60L * 1000L // val tca = (aos + los) / 2 val az = satPos.azimuth.toDegrees().round(1) val elev = satPos.elevation.toDegrees().round(1) val alt = satPos.altitude - return SatPass(aos, az, los, az, alt.toInt(), elev, sat) + return OrbitalPass(aos, az, los, az, alt.toInt(), elev, sat) } - private fun getLeoPass(sat: Satellite, pos: GeoPos, time: Long, rewind: Boolean): SatPass { + private fun getLeoPass(sat: OrbitalObject, pos: GeoPos, time: Long, rewind: Boolean): OrbitalPass { val quarterOrbitMin = (sat.data.orbitalPeriod / 4.0).toInt() var calendarTimeMillis = time var elevation: Double @@ -229,6 +234,6 @@ class SatelliteRepo( val los = satPos.time // val tca = (aos + los) / 2 val losAz = satPos.azimuth.toDegrees().round(1) val elev = maxElevation.toDegrees().round(1) - return SatPass(aos, aosAz, los, losAz, alt.toInt(), elev, sat) + return OrbitalPass(aos, aosAz, los, losAz, alt.toInt(), elev, sat) } } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt index 3f65f2d3..692a01aa 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SelectionRepo.kt @@ -4,6 +4,7 @@ import com.rtbishop.look4sat.domain.model.SatItem import com.rtbishop.look4sat.domain.repository.ISelectionRepo import com.rtbishop.look4sat.domain.repository.ISettingsRepo import com.rtbishop.look4sat.domain.source.ILocalSource +import com.rtbishop.look4sat.domain.source.Sources import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -30,7 +31,7 @@ class SelectionRepo( override fun getCurrentType() = currentType.value - override fun getTypesList() = settingsRepo.satelliteSourcesMap.keys.sorted() + override fun getTypesList() = Sources.satelliteDataUrls.keys.sorted() override suspend fun getEntriesFlow() = withContext(dispatcher) { val selectedIds = settingsRepo.selectedIds.value diff --git a/data/src/main/java/com/rtbishop/look4sat/data/source/SensorSource.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SensorsRepo.kt similarity index 91% rename from data/src/main/java/com/rtbishop/look4sat/data/source/SensorSource.kt rename to data/src/main/java/com/rtbishop/look4sat/data/repository/SensorsRepo.kt index 89122f74..df56eb82 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/source/SensorSource.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SensorsRepo.kt @@ -15,20 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.rtbishop.look4sat.data.source +package com.rtbishop.look4sat.data.repository import android.hardware.Sensor import android.hardware.SensorEvent import android.hardware.SensorEventListener import android.hardware.SensorManager import com.rtbishop.look4sat.domain.predict.RAD2DEG -import com.rtbishop.look4sat.domain.source.ISensorSource +import com.rtbishop.look4sat.domain.repository.ISensorsRepo +import kotlin.math.round import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlin.math.round -class SensorSource(private val sensorManager: SensorManager, private val sensor: Sensor?) : - SensorEventListener, ISensorSource { +class SensorsRepo(private val sensorManager: SensorManager, private val sensor: Sensor?) : + SensorEventListener, ISensorsRepo { private val _orientation = MutableStateFlow(Pair(0f, 0f)) private val rotationMatrix = FloatArray(9) diff --git a/data/src/main/java/com/rtbishop/look4sat/data/source/FileSource.kt b/data/src/main/java/com/rtbishop/look4sat/data/source/FileSource.kt deleted file mode 100644 index 7ef2a1d6..00000000 --- a/data/src/main/java/com/rtbishop/look4sat/data/source/FileSource.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.rtbishop.look4sat.data.source - -import android.content.ContentResolver -import android.net.Uri -import com.rtbishop.look4sat.domain.source.IFileSource -import java.io.InputStream -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext - -class FileSource( - private val contentResolver: ContentResolver, private val dispatcher: CoroutineDispatcher -) : IFileSource { - override suspend fun getFileStream(uri: String): InputStream? { - return withContext(dispatcher) { contentResolver.openInputStream(Uri.parse(uri)) } - } -} diff --git a/data/src/main/java/com/rtbishop/look4sat/data/source/LocalSource.kt b/data/src/main/java/com/rtbishop/look4sat/data/source/LocalSource.kt index 728fbfb9..d1e308a7 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/source/LocalSource.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/source/LocalSource.kt @@ -18,75 +18,75 @@ package com.rtbishop.look4sat.data.source import com.rtbishop.look4sat.data.database.entity.SatEntry as FrameworkEntry -import com.rtbishop.look4sat.data.database.entity.SatItem as FrameworkItem import com.rtbishop.look4sat.data.database.entity.SatRadio as FrameworkRadio -import com.rtbishop.look4sat.domain.model.SatEntry as DomainEntry -import com.rtbishop.look4sat.domain.model.SatItem as DomainItem import com.rtbishop.look4sat.domain.model.SatRadio as DomainRadio -import com.rtbishop.look4sat.data.database.dao.StorageDao +import com.rtbishop.look4sat.data.database.Look4SatDao import com.rtbishop.look4sat.domain.model.SatRadio -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalData +import com.rtbishop.look4sat.domain.predict.OrbitalObject import com.rtbishop.look4sat.domain.source.ILocalSource -class LocalSource(private val storageDao: StorageDao) : ILocalSource { +class LocalSource(private val look4SatDao: Look4SatDao) : ILocalSource { //region # Entries region - override suspend fun getEntriesTotal() = storageDao.getEntriesTotal() + override suspend fun getEntriesTotal() = look4SatDao.getEntriesTotal() - override suspend fun getEntriesList(): List { - return storageDao.getEntriesList().toDomainItems() - } + override suspend fun getEntriesList() = look4SatDao.getEntriesList() - override suspend fun getEntriesWithIds(ids: List): List { - val selectedSatellites = mutableListOf() + override suspend fun getEntriesWithIds(ids: List): List { + val selectedOrbitalObjects = mutableListOf() ids.chunked(999).forEach { idsPart -> - val entries = storageDao.getEntriesWithIds(idsPart) - selectedSatellites.addAll(entries.map { entry -> entry.data.getSatellite() }) + val entries = look4SatDao.getEntriesWithIds(idsPart) + selectedOrbitalObjects.addAll(entries.toDomain().map { entry -> entry.getObject() }) } - return selectedSatellites + return selectedOrbitalObjects } - override suspend fun insertEntries(entries: List) { - storageDao.insertEntries(entries.toFrameworkEntries()) - } + override suspend fun insertEntries(entries: List) = look4SatDao.insertEntries(entries.toEntity()) - override suspend fun deleteEntries() = storageDao.deleteEntries() + override suspend fun deleteEntries() = look4SatDao.deleteEntries() - override suspend fun getIdsWithModes(modes: List) = storageDao.getIdsWithModes(modes) + override suspend fun getIdsWithModes(modes: List) = look4SatDao.getIdsWithModes(modes) - private fun DomainEntry.toFramework() = FrameworkEntry(this.data, this.comment) + private fun FrameworkEntry.toDomain() = OrbitalData( + this.name, this.epoch, this.meanmo, this.eccn, this.incl, + this.raan, this.argper, this.meanan, this.catnum, this.bstar + ) - private fun FrameworkItem.toDomain() = DomainItem(this.catnum, this.name, false) + private fun OrbitalData.toEntity() = FrameworkEntry( + this.name, this.epoch, this.meanmo, this.eccn, this.incl, + this.raan, this.argper, this.meanan, this.catnum, this.bstar + ) - private fun List.toFrameworkEntries() = this.map { entry -> entry.toFramework() } + private fun List.toEntity() = this.map { item -> item.toEntity() } - private fun List.toDomainItems() = this.map { item -> item.toDomain() } + private fun List.toDomain() = this.map { item -> item.toDomain() } //endregion //region # Radios region - override suspend fun getRadiosTotal() = storageDao.getRadiosTotal() + override suspend fun getRadiosTotal() = look4SatDao.getRadiosTotal() override suspend fun getRadiosWithId(id: Int): List { - return storageDao.getRadiosWithId(id).toDomainRadios() + return look4SatDao.getRadiosWithId(id).toDomainRadios() } override suspend fun insertRadios(radios: List) { - storageDao.insertRadios(radios.toFrameworkRadios()) + look4SatDao.insertRadios(radios.toFrameworkRadios()) } - override suspend fun deleteRadios() = storageDao.deleteRadios() + override suspend fun deleteRadios() = look4SatDao.deleteRadios() private fun DomainRadio.toFramework() = FrameworkRadio( this.uuid, this.info, this.isAlive, this.downlinkLow, this.downlinkHigh, this.downlinkMode, - this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum, this.comment + this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum ) private fun FrameworkRadio.toDomain() = DomainRadio( this.uuid, this.info, this.isAlive, this.downlinkLow, this.downlinkHigh, this.downlinkMode, - this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum, this.comment + this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum ) private fun List.toFrameworkRadios() = this.map { radio -> radio.toFramework() } diff --git a/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt b/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt index 5a82a5d4..f2d097c2 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/source/RemoteSource.kt @@ -17,6 +17,8 @@ */ package com.rtbishop.look4sat.data.source +import android.content.ContentResolver +import android.net.Uri import com.rtbishop.look4sat.domain.source.IRemoteSource import java.io.InputStream import kotlinx.coroutines.CoroutineDispatcher @@ -25,15 +27,27 @@ import okhttp3.OkHttpClient import okhttp3.Request class RemoteSource( - private val httpClient: OkHttpClient, private val dispatcher: CoroutineDispatcher + private val contentResolver: ContentResolver, + private val httpClient: OkHttpClient, + private val dispatcher: CoroutineDispatcher ) : IRemoteSource { - override suspend fun getRemoteStream(url: String): InputStream? = withContext(dispatcher) { + override suspend fun getFileStream(uri: String): InputStream? = withContext(dispatcher) { try { - val request = Request.Builder().url(url).build() - httpClient.newCall(request).execute().body?.byteStream() + val fileUri = Uri.parse(uri) + contentResolver.openInputStream(fileUri) } catch (exception: Exception) { - println("RemoteSource fetching stream exception: $exception") + println("RemoteSource file stream exception: $exception") + null + } + } + + override suspend fun getNetworkStream(url: String): InputStream? = withContext(dispatcher) { + try { + val networkRequest = Request.Builder().url(url).build() + httpClient.newCall(networkRequest).execute().body?.byteStream() + } catch (exception: Exception) { + println("RemoteSource network stream exception: $exception") null } } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatEntry.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatEntry.kt deleted file mode 100644 index 6c0580c7..00000000 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatEntry.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.rtbishop.look4sat.domain.model - -import com.rtbishop.look4sat.domain.predict.OrbitalData - -data class SatEntry(val data: OrbitalData, var comment: String? = null) diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatItem.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatItem.kt index 450a2b80..19f70f1b 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatItem.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatItem.kt @@ -17,4 +17,4 @@ */ package com.rtbishop.look4sat.domain.model -data class SatItem(val catnum: Int, val name: String, val isSelected: Boolean) +data class SatItem(val catnum: Int, val name: String, val isSelected: Boolean = false) diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatRadio.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatRadio.kt index 420bdd55..314fd277 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatRadio.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/model/SatRadio.kt @@ -28,6 +28,5 @@ data class SatRadio( var uplinkHigh: Long?, val uplinkMode: String?, val isInverted: Boolean, - val catnum: Int?, - var comment: String? = null + val catnum: Int? ) diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/Constants.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/Constants.kt new file mode 100644 index 00000000..9260db76 --- /dev/null +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/Constants.kt @@ -0,0 +1,20 @@ +package com.rtbishop.look4sat.domain.predict + +const val ASTRONOMICAL_UNIT = 1.49597870691E8 +const val DEG2RAD = 0.017453292519943295 +const val RAD2DEG = 57.29577951308232 +const val EARTH_RADIUS = 6378.137 +const val EPSILON = 1.0E-12 +const val FLAT_FACT = 3.35281066474748E-3 +const val J3_HARMONIC = -2.53881E-6 +const val MIN_PER_DAY = 1.44E3 +const val SEC_PER_DAY = 8.6400E4 +const val SOLAR_RADIUS = 6.96000E5 +const val SPEED_OF_LIGHT = 2.99792458E8 +const val PI = 3.141592653589793 +const val PI_2 = PI / 2.0 +const val TWO_PI = PI * 2.0 +const val TWO_THIRDS = 2.0 / 3.0 +const val CK2 = 5.413079E-4 +const val CK4 = 6.209887E-7 +const val XKE = 7.43669161E-2 diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceSatellite.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceObject.kt similarity index 99% rename from domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceSatellite.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceObject.kt index 1fb69237..76b6c379 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceSatellite.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/DeepSpaceObject.kt @@ -25,7 +25,7 @@ import kotlin.math.pow import kotlin.math.sin import kotlin.math.sqrt -class DeepSpaceSatellite(data: OrbitalData) : Satellite(data) { +class DeepSpaceObject(data: OrbitalData) : OrbitalObject(data) { private val c1: Double private val c4: Double diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthSatellite.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthObject.kt similarity index 99% rename from domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthSatellite.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthObject.kt index 7c9e6098..d13d7ac9 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthSatellite.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/NearEarthObject.kt @@ -24,7 +24,7 @@ import kotlin.math.pow import kotlin.math.sin import kotlin.math.sqrt -class NearEarthSatellite(data: OrbitalData) : Satellite(data) { +class NearEarthObject(data: OrbitalData) : OrbitalObject(data) { private val aodp: Double private val aycof: Double diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalData.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalData.kt index 7f7e249d..1f6d3f21 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalData.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalData.kt @@ -27,15 +27,14 @@ data class OrbitalData( val argper: Double, val meanan: Double, val catnum: Int, - val bstar: Double, - val xincl: Double = incl * DEG2RAD, - val xnodeo: Double = raan * DEG2RAD, - val omegao: Double = argper * DEG2RAD, - val xmo: Double = meanan * DEG2RAD, - val xno: Double = meanmo * TWO_PI / MIN_PER_DAY, - val orbitalPeriod: Double = MIN_PER_DAY / meanmo, - // Space objects are classified as NearEarth (period < 225 min) or DeepSpace (period >= 225 min) - val isDeepSpace: Boolean = orbitalPeriod >= 225.0 + val bstar: Double ) { - fun getSatellite(): Satellite = if (isDeepSpace) DeepSpaceSatellite(this) else NearEarthSatellite(this) + val xincl: Double = incl * DEG2RAD + val xnodeo: Double = raan * DEG2RAD + val omegao: Double = argper * DEG2RAD + val xmo: Double = meanan * DEG2RAD + val xno: Double = meanmo * TWO_PI / MIN_PER_DAY + val orbitalPeriod: Double = MIN_PER_DAY / meanmo + val isDeepSpace: Boolean = orbitalPeriod >= 225.0 // NearEarth (period < 225 min) or DeepSpace (period >= 225 min) + fun getObject(): OrbitalObject = if (isDeepSpace) DeepSpaceObject(this) else NearEarthObject(this) } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalObject.kt similarity index 88% rename from domain/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalObject.kt index 340725a7..60cde6f6 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalObject.kt @@ -30,30 +30,11 @@ import kotlin.math.pow import kotlin.math.sin import kotlin.math.sqrt -const val ASTRONOMICAL_UNIT = 1.49597870691E8 -const val DEG2RAD = 0.017453292519943295 -const val RAD2DEG = 57.29577951308232 -const val EARTH_RADIUS = 6378.137 -const val EPSILON = 1.0E-12 -const val FLAT_FACT = 3.35281066474748E-3 -const val J3_HARMONIC = -2.53881E-6 -const val MIN_PER_DAY = 1.44E3 -const val SEC_PER_DAY = 8.6400E4 -const val SOLAR_RADIUS = 6.96000E5 -const val SPEED_OF_LIGHT = 2.99792458E8 -const val PI = 3.141592653589793 -const val PI_2 = PI / 2.0 -const val TWO_PI = PI * 2.0 -const val TWO_THIRDS = 2.0 / 3.0 -const val CK2 = 5.413079E-4 -const val CK4 = 6.209887E-7 -const val XKE = 7.43669161E-2 - -abstract class Satellite(val data: OrbitalData) { +abstract class OrbitalObject(val data: OrbitalData) { private val position = Vector4() private val velocity = Vector4() - private var satPos = SatPos() + private var orbitalPos = OrbitalPos() private var eclipseDepth = 0.0 private var gsPosTheta = 0.0 private var julUTC = 0.0 @@ -72,8 +53,8 @@ abstract class Satellite(val data: OrbitalData) { } } - fun getPosition(pos: GeoPos, time: Long): SatPos { - satPos = SatPos() + fun getPosition(pos: GeoPos, time: Long): OrbitalPos { + orbitalPos = OrbitalPos() // Date/time at which the position and velocity were calculated julUTC = calcCurrentDaynum(time) + 2444238.5 // Convert satellite's epoch time to Julian and calculate time since epoch in minutes @@ -88,10 +69,10 @@ abstract class Satellite(val data: OrbitalData) { // Angles in rads, dist in km, vel in km/S. Calculate sat Az, El, Range and Range-rate. calculateObs(julUTC, position, velocity, pos, squintVector) calculateLatLonAlt(julUTC) - satPos.time = time - satPos.eclipsed = isEclipsed() - satPos.eclipseDepth = eclipseDepth - return satPos + orbitalPos.time = time + orbitalPos.eclipsed = isEclipsed() + orbitalPos.eclipseDepth = eclipseDepth + return orbitalPos } private fun calcCurrentDaynum(now: Long): Double { @@ -118,8 +99,8 @@ abstract class Satellite(val data: OrbitalData) { } private fun calculateSDP4orSGP4(tsince: Double) { - if (data.isDeepSpace) (this as DeepSpaceSatellite).calculateSDP4(tsince) - else (this as NearEarthSatellite).calculateSGP4(tsince) + if (data.isDeepSpace) (this as DeepSpaceObject).calculateSDP4(tsince) + else (this as NearEarthObject).calculateSGP4(tsince) } // Converts the sat position and velocity vectors to km and km/sec @@ -164,13 +145,13 @@ abstract class Satellite(val data: OrbitalData) { var azim = atan(-topE / topS) if (topS > 0.0) azim += PI if (azim < 0.0) azim += TWO_PI - satPos.azimuth = azim - satPos.elevation = asin(topZ / range.w) - satPos.distance = range.w - satPos.distanceRate = dot(range, rgvel) / range.w - var elevation = satPos.elevation / TWO_PI * 360.0 + orbitalPos.azimuth = azim + orbitalPos.elevation = asin(topZ / range.w) + orbitalPos.distance = range.w + orbitalPos.distanceRate = dot(range, rgvel) / range.w + var elevation = orbitalPos.elevation / TWO_PI * 360.0 if (elevation > 90) elevation = 180 - elevation - satPos.aboveHorizon = elevation - 0 > EPSILON + orbitalPos.aboveHorizon = elevation - 0 > EPSILON } // Returns the ECI position and velocity of the observer @@ -196,26 +177,26 @@ abstract class Satellite(val data: OrbitalData) { // Calculate the geodetic position of an object given its ECI pos and time private fun calculateLatLonAlt(time: Double) { - satPos.theta = atan2(position.y, position.x) - satPos.longitude = mod2PI(satPos.theta - thetaGJD(time)) + orbitalPos.theta = atan2(position.y, position.x) + orbitalPos.longitude = mod2PI(orbitalPos.theta - thetaGJD(time)) val r = sqrt(sqr(position.x) + sqr(position.y)) val e2 = FLAT_FACT * (2.0 - FLAT_FACT) - satPos.latitude = atan2(position.z, r) + orbitalPos.latitude = atan2(position.z, r) var phi: Double var c: Double var i = 0 var converged: Boolean do { - phi = satPos.latitude + phi = orbitalPos.latitude c = invert(sqrt(1.0 - e2 * sqr(sin(phi)))) - satPos.latitude = atan2(position.z + EARTH_RADIUS * c * e2 * sin(phi), r) - converged = abs(satPos.latitude - phi) < EPSILON + orbitalPos.latitude = atan2(position.z + EARTH_RADIUS * c * e2 * sin(phi), r) + converged = abs(orbitalPos.latitude - phi) < EPSILON } while (i++ < 10 && !converged) - satPos.altitude = r / cos(satPos.latitude) - EARTH_RADIUS * c - var temp = satPos.latitude + orbitalPos.altitude = r / cos(orbitalPos.latitude) - EARTH_RADIUS * c + var temp = orbitalPos.latitude if (temp > PI_2) { temp -= TWO_PI - satPos.latitude = temp + orbitalPos.latitude = temp } } @@ -302,7 +283,7 @@ abstract class Satellite(val data: OrbitalData) { internal fun calculatePhase(xlt: Double, xnode: Double, omgadf: Double) { var phaseValue = xlt - xnode - omgadf + TWO_PI if (phaseValue < 0.0) phaseValue += TWO_PI - satPos.phase = mod2PI(phaseValue) + orbitalPos.phase = mod2PI(phaseValue) } // Sets perigee and checks and adjusts the calculation if the perigee is less tan 156KM diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPass.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPass.kt similarity index 82% rename from domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPass.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPass.kt index f939fce4..a3ed7ea1 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPass.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPass.kt @@ -17,17 +17,17 @@ */ package com.rtbishop.look4sat.domain.predict -data class SatPass( +data class OrbitalPass( val aosTime: Long = 0L, val aosAzimuth: Double = 90.0, val losTime: Long = 0L, val losAzimuth: Double = 270.0, val altitude: Int = 1000, val maxElevation: Double = 75.0, - val satellite: Satellite, + val orbitalObject: OrbitalObject, var progress: Float = 0.0f ) { - val catNum: Int = satellite.data.catnum - val name: String = satellite.data.name - val isDeepSpace: Boolean = satellite.data.isDeepSpace + val catNum: Int = orbitalObject.data.catnum + val name: String = orbitalObject.data.name + val isDeepSpace: Boolean = orbitalObject.data.isDeepSpace } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPos.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPos.kt similarity index 99% rename from domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPos.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPos.kt index 623fc276..41162fa8 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/predict/SatPos.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/predict/OrbitalPos.kt @@ -25,7 +25,7 @@ import kotlin.math.pow import kotlin.math.sin import kotlin.math.sqrt -data class SatPos( +data class OrbitalPos( var azimuth: Double = 0.0, var elevation: Double = 0.0, var latitude: Double = 0.0, diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISatelliteRepo.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISatelliteRepo.kt index f4327deb..c1447162 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISatelliteRepo.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISatelliteRepo.kt @@ -2,19 +2,19 @@ package com.rtbishop.look4sat.domain.repository import com.rtbishop.look4sat.domain.model.SatRadio import com.rtbishop.look4sat.domain.predict.GeoPos -import com.rtbishop.look4sat.domain.predict.SatPass -import com.rtbishop.look4sat.domain.predict.SatPos -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalObject +import com.rtbishop.look4sat.domain.predict.OrbitalPass +import com.rtbishop.look4sat.domain.predict.OrbitalPos import kotlinx.coroutines.flow.StateFlow interface ISatelliteRepo { - val passes: StateFlow> - val satellites: StateFlow> + val passes: StateFlow> + val satellites: StateFlow> suspend fun getRadiosWithId(id: Int): List suspend fun initRepository() - suspend fun getPosition(sat: Satellite, pos: GeoPos, time: Long): SatPos - suspend fun getTrack(sat: Satellite, pos: GeoPos, start: Long, end: Long): List - suspend fun getRadios(sat: Satellite, pos: GeoPos, radios: List, time: Long): List - suspend fun processPasses(passList: List, time: Long): List + suspend fun getPosition(sat: OrbitalObject, pos: GeoPos, time: Long): OrbitalPos + suspend fun getTrack(sat: OrbitalObject, pos: GeoPos, start: Long, end: Long): List + suspend fun getRadios(sat: OrbitalObject, pos: GeoPos, radios: List, time: Long): List + suspend fun processPasses(passList: List, time: Long): List suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List) } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/source/ISensorSource.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISensorsRepo.kt similarity index 66% rename from domain/src/main/java/com/rtbishop/look4sat/domain/source/ISensorSource.kt rename to domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISensorsRepo.kt index 89dcd864..5167630f 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/source/ISensorSource.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISensorsRepo.kt @@ -1,8 +1,8 @@ -package com.rtbishop.look4sat.domain.source +package com.rtbishop.look4sat.domain.repository import kotlinx.coroutines.flow.StateFlow -interface ISensorSource { +interface ISensorsRepo { val orientation: StateFlow> fun enableSensor() fun disableSensor() diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt index 5496e96f..ba2230dd 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/repository/ISettingsRepo.kt @@ -25,37 +25,6 @@ import kotlinx.coroutines.flow.StateFlow interface ISettingsRepo { - val radioSourceUrl: String get() = "https://db.satnogs.org/api/transmitters/?format=json" - val satelliteSourcesMap: Map - get() = mapOf( - "All" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=csv", - "Amsat" to "https://amsat.org/tle/current/nasabare.txt", - "Amateur" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=amateur&FORMAT=csv", - "Classified" to "https://www.mmccants.org/tles/classfd.zip", - "Cubesat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=cubesat&FORMAT=csv", - "Education" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=education&FORMAT=csv", - "Engineer" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=engineering&FORMAT=csv", - "Geostationary" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=geo&FORMAT=csv", - "Globalstar" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=globalstar&FORMAT=csv", - "GNSS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=gnss&FORMAT=csv", - "Intelsat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=intelsat&FORMAT=csv", - "Iridium" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=iridium-NEXT&FORMAT=csv", - "McCants" to "https://www.mmccants.org/tles/inttles.zip", - "Military" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=military&FORMAT=csv", - "New" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=csv", - "OneWeb" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=csv", - "Orbcomm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=orbcomm&FORMAT=csv", - "R4UAB" to "https://r4uab.ru/satonline.txt", - "Resource" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=resource&FORMAT=csv", - "SatNOGS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=satnogs&FORMAT=csv", - "Science" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=science&FORMAT=csv", - "Spire" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=spire&FORMAT=csv", - "Starlink" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=starlink&FORMAT=csv", - "Swarm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=swarm&FORMAT=csv", - "Weather" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=weather&FORMAT=csv", - "X-Comm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv" - ) - //region # Satellites selection settings val selectedIds: StateFlow> fun setSelectedIds(ids: List) diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/source/IFileSource.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/source/IFileSource.kt deleted file mode 100644 index 6f398346..00000000 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/source/IFileSource.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.rtbishop.look4sat.domain.source - -import java.io.InputStream - -interface IFileSource { - suspend fun getFileStream(uri: String): InputStream? -} diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/source/ILocalSource.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/source/ILocalSource.kt index 185f2f3a..26337100 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/source/ILocalSource.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/source/ILocalSource.kt @@ -17,16 +17,16 @@ */ package com.rtbishop.look4sat.domain.source -import com.rtbishop.look4sat.domain.model.SatEntry import com.rtbishop.look4sat.domain.model.SatItem import com.rtbishop.look4sat.domain.model.SatRadio -import com.rtbishop.look4sat.domain.predict.Satellite +import com.rtbishop.look4sat.domain.predict.OrbitalData +import com.rtbishop.look4sat.domain.predict.OrbitalObject interface ILocalSource { suspend fun getEntriesTotal(): Int suspend fun getEntriesList(): List - suspend fun getEntriesWithIds(ids: List): List - suspend fun insertEntries(entries: List) + suspend fun getEntriesWithIds(ids: List): List + suspend fun insertEntries(entries: List) suspend fun deleteEntries() suspend fun getIdsWithModes(modes: List): List suspend fun getRadiosTotal(): Int diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/source/IRemoteSource.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/source/IRemoteSource.kt index 84ffbd33..574bf00b 100644 --- a/domain/src/main/java/com/rtbishop/look4sat/domain/source/IRemoteSource.kt +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/source/IRemoteSource.kt @@ -20,5 +20,6 @@ package com.rtbishop.look4sat.domain.source import java.io.InputStream interface IRemoteSource { - suspend fun getRemoteStream(url: String): InputStream? + suspend fun getFileStream(uri: String): InputStream? + suspend fun getNetworkStream(url: String): InputStream? } diff --git a/domain/src/main/java/com/rtbishop/look4sat/domain/source/Sources.kt b/domain/src/main/java/com/rtbishop/look4sat/domain/source/Sources.kt new file mode 100644 index 00000000..5356464a --- /dev/null +++ b/domain/src/main/java/com/rtbishop/look4sat/domain/source/Sources.kt @@ -0,0 +1,33 @@ +package com.rtbishop.look4sat.domain.source + +object Sources { + const val radioDataUrl = "https://db.satnogs.org/api/transmitters/?format=json" + val satelliteDataUrls = mapOf( + "All" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=csv", + "Amsat" to "https://amsat.org/tle/current/nasabare.txt", + "Amateur" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=amateur&FORMAT=csv", + "Classified" to "https://www.mmccants.org/tles/classfd.zip", + "Cubesat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=cubesat&FORMAT=csv", + "Education" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=education&FORMAT=csv", + "Engineer" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=engineering&FORMAT=csv", + "Geostationary" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=geo&FORMAT=csv", + "Globalstar" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=globalstar&FORMAT=csv", + "GNSS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=gnss&FORMAT=csv", + "Intelsat" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=intelsat&FORMAT=csv", + "Iridium" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=iridium-NEXT&FORMAT=csv", + "McCants" to "https://www.mmccants.org/tles/inttles.zip", + "Military" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=military&FORMAT=csv", + "New" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=csv", + "OneWeb" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=csv", + "Orbcomm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=orbcomm&FORMAT=csv", + "R4UAB" to "https://r4uab.ru/satonline.txt", + "Resource" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=resource&FORMAT=csv", + "SatNOGS" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=satnogs&FORMAT=csv", + "Science" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=science&FORMAT=csv", + "Spire" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=spire&FORMAT=csv", + "Starlink" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=starlink&FORMAT=csv", + "Swarm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=swarm&FORMAT=csv", + "Weather" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=weather&FORMAT=csv", + "X-Comm" to "https://celestrak.org/NORAD/elements/gp.php?GROUP=x-comm&FORMAT=csv" + ) +}