kopia lustrzana https://github.com/rt-bishop/Look4Sat
Added more frequency data fields to Radio class
rodzic
3e978a3ec5
commit
e6f3e554fa
|
@ -30,7 +30,7 @@ android {
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composeOptions { kotlinCompilerExtensionVersion = "1.5.2" }
|
composeOptions { kotlinCompilerExtensionVersion = "1.5.3" }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -43,21 +43,21 @@ dependencies {
|
||||||
ksp("androidx.room:room-compiler:2.5.2")
|
ksp("androidx.room:room-compiler:2.5.2")
|
||||||
|
|
||||||
implementation("androidx.activity:activity-compose:1.7.2")
|
implementation("androidx.activity:activity-compose:1.7.2")
|
||||||
implementation("androidx.compose.animation:animation:1.5.0")
|
implementation("androidx.compose.animation:animation:1.5.1")
|
||||||
implementation("androidx.compose.compiler:compiler:1.5.2")
|
implementation("androidx.compose.compiler:compiler:1.5.3")
|
||||||
implementation("androidx.compose.material3:material3:1.1.1")
|
implementation("androidx.compose.material3:material3:1.1.1")
|
||||||
implementation("androidx.compose.runtime:runtime:1.5.0")
|
implementation("androidx.compose.runtime:runtime:1.5.1")
|
||||||
implementation("androidx.compose.ui:ui-tooling-preview:1.5.0")
|
implementation("androidx.compose.ui:ui-tooling-preview:1.5.1")
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
|
||||||
implementation("androidx.navigation:navigation-compose:2.7.1")
|
implementation("androidx.navigation:navigation-compose:2.7.2")
|
||||||
|
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.10.0")
|
implementation("com.squareup.okhttp3:okhttp:4.10.0")
|
||||||
implementation("org.osmdroid:osmdroid-android:6.1.16")
|
implementation("org.osmdroid:osmdroid-android:6.1.17")
|
||||||
debugImplementation("androidx.compose.ui:ui-tooling:1.5.0")
|
debugImplementation("androidx.compose.ui:ui-tooling:1.5.1")
|
||||||
debugImplementation("androidx.compose.ui:ui-test-manifest:1.5.0")
|
debugImplementation("androidx.compose.ui:ui-test-manifest:1.5.1")
|
||||||
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
testImplementation("io.mockk:mockk:1.13.7")
|
testImplementation("io.mockk:mockk:1.13.7")
|
||||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
|
||||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.5.0")
|
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.5.1")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.hardware.Sensor
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import com.rtbishop.look4sat.data.database.MIGRATION_1_2
|
|
||||||
import com.rtbishop.look4sat.data.database.MainDatabase
|
import com.rtbishop.look4sat.data.database.MainDatabase
|
||||||
import com.rtbishop.look4sat.data.framework.BluetoothReporter
|
import com.rtbishop.look4sat.data.framework.BluetoothReporter
|
||||||
import com.rtbishop.look4sat.data.framework.NetworkReporter
|
import com.rtbishop.look4sat.data.framework.NetworkReporter
|
||||||
|
@ -71,8 +70,8 @@ class MainContainer(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun provideLocalSource(): ILocalSource {
|
private fun provideLocalSource(): ILocalSource {
|
||||||
val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb").apply {
|
val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDBv313").apply {
|
||||||
addMigrations(MIGRATION_1_2)
|
// addMigrations(MIGRATION_1_2)
|
||||||
fallbackToDestructiveMigration()
|
fallbackToDestructiveMigration()
|
||||||
}.build()
|
}.build()
|
||||||
return LocalSource(database.storageDao())
|
return LocalSource(database.storageDao())
|
||||||
|
|
|
@ -27,6 +27,8 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.PlatformTextStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
@ -59,35 +61,50 @@ fun PassesScreen(uiState: PassesState, navToRadar: (Int, Long) -> Unit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
ElevatedCard(modifier = Modifier.height(52.dp)) {
|
TopBar(nextId = uiState.nextId, nextName = uiState.nextName, nextTime = uiState.nextTime, toggleDialog)
|
||||||
Row(
|
PassesCard(refreshState, uiState.isRefreshing, uiState.itemsList, navToRadar)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
}
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
}
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
@Composable
|
||||||
IconButton(onClick = { toggleDialog() }) {
|
@Preview(showBackground = true)
|
||||||
Icon(
|
private fun TopBarPreview() {
|
||||||
painter = painterResource(id = R.drawable.ic_filter),
|
MainTheme { TopBar(nextId = 45555, nextName = "Stuff", nextTime = "88:88:88") {} }
|
||||||
contentDescription = null
|
}
|
||||||
)
|
|
||||||
}
|
@Composable
|
||||||
Column(verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)) {
|
private fun TopBar(nextId: Int, nextName: String, nextTime: String, toggleDialog: () -> Unit) {
|
||||||
Text(text = "Next - Id:${uiState.nextId}", maxLines = 1, overflow = TextOverflow.Ellipsis)
|
ElevatedCard(modifier = Modifier.height(48.dp)) {
|
||||||
Text(text = uiState.nextName, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
Row(
|
||||||
}
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_sputnik),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.padding(12.dp)
|
||||||
|
)
|
||||||
|
Column(verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)) {
|
||||||
Text(
|
Text(
|
||||||
text = uiState.nextTime,
|
text = "AOS - Id:$nextId",
|
||||||
fontSize = 36.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
textAlign = TextAlign.End,
|
maxLines = 1,
|
||||||
modifier = Modifier
|
overflow = TextOverflow.Ellipsis
|
||||||
.weight(1f)
|
|
||||||
.padding(bottom = 2.dp, end = 8.dp)
|
|
||||||
)
|
)
|
||||||
|
Text(text = nextName, fontWeight = FontWeight.Medium, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = nextTime,
|
||||||
|
fontSize = 32.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
style = TextStyle(platformStyle = PlatformTextStyle(includeFontPadding = false))
|
||||||
|
)
|
||||||
|
IconButton(onClick = { toggleDialog() }) {
|
||||||
|
Icon(painter = painterResource(id = R.drawable.ic_filter), contentDescription = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PassesCard(refreshState, uiState.isRefreshing, uiState.itemsList, navToRadar)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +115,7 @@ private fun PassPreview() {
|
||||||
"Satellite", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 45000, 0.0
|
"Satellite", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 45000, 0.0
|
||||||
)
|
)
|
||||||
val satellite = NearEarthSatellite(data)
|
val satellite = NearEarthSatellite(data)
|
||||||
val pass = SatPass(1L, 25.0, 10L, 75.0, 850, 45.0, satellite, 0.5f)
|
val pass = SatPass(1L, 0.0, 10L, 180.0, 850, 45.0, satellite, 0.5f)
|
||||||
MainTheme { Pass(pass = pass, { _, _ -> }) }
|
MainTheme { Pass(pass = pass, { _, _ -> }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,17 +166,21 @@ private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modif
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.pass_aosAz, pass.aosAzimuth),
|
text = stringResource(id = R.string.pass_aosAz, pass.aosAzimuth),
|
||||||
fontSize = 15.sp
|
textAlign = TextAlign.Start,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.pass_altitude, pass.altitude),
|
text = stringResource(id = R.string.pass_altitude, pass.altitude),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
fontSize = 15.sp,
|
fontSize = 15.sp,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(2f)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.pass_losAz, pass.losAzimuth),
|
text = stringResource(id = R.string.pass_losAz, pass.losAzimuth),
|
||||||
fontSize = 15.sp
|
textAlign = TextAlign.End,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
|
@ -168,10 +189,7 @@ private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modif
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
val deepTime = stringResource(id = R.string.pass_placeholder)
|
val deepTime = stringResource(id = R.string.pass_placeholder)
|
||||||
Text(
|
Text(text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.aosTime)), fontSize = 15.sp)
|
||||||
text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.aosTime)),
|
|
||||||
fontSize = 15.sp
|
|
||||||
)
|
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
progress = if (pass.isDeepSpace) 1f else pass.progress,
|
progress = if (pass.isDeepSpace) 1f else pass.progress,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -179,10 +197,7 @@ private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modif
|
||||||
.padding(top = 3.dp),
|
.padding(top = 3.dp),
|
||||||
trackColor = MaterialTheme.colorScheme.inverseSurface
|
trackColor = MaterialTheme.colorScheme.inverseSurface
|
||||||
)
|
)
|
||||||
Text(
|
Text(text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.losTime)), fontSize = 15.sp)
|
||||||
text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.losTime)),
|
|
||||||
fontSize = 15.sp
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,10 +207,7 @@ private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modif
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun PassesCard(
|
private fun PassesCard(
|
||||||
refreshState: PullRefreshState,
|
refreshState: PullRefreshState, isRefreshing: Boolean, passes: List<SatPass>, navToRadar: (Int, Long) -> Unit
|
||||||
isRefreshing: Boolean,
|
|
||||||
passes: List<SatPass>,
|
|
||||||
navToRadar: (Int, Long) -> Unit
|
|
||||||
) {
|
) {
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||||
Box(Modifier.pullRefresh(refreshState)) {
|
Box(Modifier.pullRefresh(refreshState)) {
|
||||||
|
|
|
@ -121,13 +121,13 @@ private fun TransmitterItem(radio: SatRadio) {
|
||||||
}
|
}
|
||||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.radio_downlink, radio.downlink ?: 0L),
|
text = stringResource(id = R.string.radio_downlink, radio.downlinkLow ?: 0L),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
fontSize = 15.sp,
|
fontSize = 15.sp,
|
||||||
modifier = Modifier.weight(0.5f)
|
modifier = Modifier.weight(0.5f)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.radio_uplink, radio.uplink ?: 0L),
|
text = stringResource(id = R.string.radio_uplink, radio.uplinkLow ?: 0L),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
fontSize = 15.sp,
|
fontSize = 15.sp,
|
||||||
modifier = Modifier.weight(0.5f)
|
modifier = Modifier.weight(0.5f)
|
||||||
|
@ -139,7 +139,7 @@ private fun TransmitterItem(radio: SatRadio) {
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = radio.mode ?: "",
|
text = radio.downlinkMode ?: "",
|
||||||
fontSize = 15.sp
|
fontSize = 15.sp
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.1.1" apply false
|
id("com.android.application") version "8.1.1" apply false
|
||||||
id("com.android.library") version "8.1.1" apply false
|
id("com.android.library") version "8.1.1" apply false
|
||||||
id("com.google.devtools.ksp") version "1.9.0-1.0.13" apply false
|
id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
|
id("org.jetbrains.kotlin.android") version "1.9.10" apply false
|
||||||
id("org.jetbrains.kotlin.jvm") version "1.9.0" apply false
|
id("org.jetbrains.kotlin.jvm") version "1.9.10" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("clean", Delete::class.java) {
|
tasks.register("clean", Delete::class.java) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":domain"))
|
implementation(project(":domain"))
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.10.1")
|
implementation("androidx.core:core-ktx:1.12.0")
|
||||||
implementation("androidx.room:room-runtime:2.5.2")
|
implementation("androidx.room:room-runtime:2.5.2")
|
||||||
implementation("androidx.room:room-ktx:2.5.2")
|
implementation("androidx.room:room-ktx:2.5.2")
|
||||||
ksp("androidx.room:room-compiler:2.5.2")
|
ksp("androidx.room:room-compiler:2.5.2")
|
||||||
|
|
|
@ -19,23 +19,20 @@ package com.rtbishop.look4sat.data.database
|
||||||
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
import com.rtbishop.look4sat.data.database.dao.StorageDao
|
import com.rtbishop.look4sat.data.database.dao.StorageDao
|
||||||
import com.rtbishop.look4sat.data.database.entity.SatEntry
|
import com.rtbishop.look4sat.data.database.entity.SatEntry
|
||||||
import com.rtbishop.look4sat.data.database.entity.SatRadio
|
import com.rtbishop.look4sat.data.database.entity.SatRadio
|
||||||
|
|
||||||
@Database(entities = [SatEntry::class, SatRadio::class], version = 2, exportSchema = false)
|
@Database(entities = [SatEntry::class, SatRadio::class], version = 1, exportSchema = false)
|
||||||
abstract class MainDatabase : RoomDatabase() {
|
abstract class MainDatabase : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun storageDao(): StorageDao
|
abstract fun storageDao(): StorageDao
|
||||||
}
|
}
|
||||||
|
|
||||||
val MIGRATION_1_2 = object : Migration(1, 2) {
|
//val MIGRATION_1_2 = object : Migration(1, 2) {
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
// override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
database.execSQL("CREATE TABLE entries_backup (name TEXT NOT NULL, epoch REAL NOT NULL, meanmo REAL NOT NULL, eccn REAL NOT NULL, incl REAL NOT NULL, raan REAL NOT NULL, argper REAL NOT NULL, meanan REAL NOT NULL, catnum INTEGER NOT NULL, bstar REAL NOT NULL, xincl REAL NOT NULL, xnodeo REAL NOT NULL, omegao REAL NOT NULL, xmo REAL NOT NULL, xno REAL NOT NULL, orbitalPeriod REAL NOT NULL, isDeepSpace INTEGER NOT NULL, comment TEXT, PRIMARY KEY(catnum))")
|
// database.execSQL("CREATE TABLE entries_backup (name TEXT NOT NULL, epoch REAL NOT NULL, meanmo REAL NOT NULL, eccn REAL NOT NULL, incl REAL NOT NULL, raan REAL NOT NULL, argper REAL NOT NULL, meanan REAL NOT NULL, catnum INTEGER NOT NULL, bstar REAL NOT NULL, xincl REAL NOT NULL, xnodeo REAL NOT NULL, omegao REAL NOT NULL, xmo REAL NOT NULL, xno REAL NOT NULL, orbitalPeriod REAL NOT NULL, isDeepSpace INTEGER NOT NULL, comment TEXT, PRIMARY KEY(catnum))")
|
||||||
database.execSQL("INSERT INTO entries_backup (name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar, xincl, xnodeo, omegao, xmo, xno, orbitalPeriod, isDeepSpace, comment) SELECT name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar, xincl, xnodeo, omegao, xmo, xno, 1440 / meanmo, 1440 / meanmo >= 225.0, comment FROM entries")
|
// database.execSQL("INSERT INTO entries_backup (name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar, xincl, xnodeo, omegao, xmo, xno, orbitalPeriod, isDeepSpace, comment) SELECT name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar, xincl, xnodeo, omegao, xmo, xno, 1440 / meanmo, 1440 / meanmo >= 225.0, comment FROM entries")
|
||||||
database.execSQL("DROP TABLE entries")
|
// database.execSQL("DROP TABLE entries")
|
||||||
database.execSQL("ALTER TABLE entries_backup RENAME TO entries")
|
// database.execSQL("ALTER TABLE entries_backup RENAME TO entries")
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
|
@ -46,7 +46,7 @@ interface StorageDao {
|
||||||
@Query("DELETE FROM entries")
|
@Query("DELETE FROM entries")
|
||||||
suspend fun deleteEntries()
|
suspend fun deleteEntries()
|
||||||
|
|
||||||
@Query("SELECT catnum FROM radios WHERE mode IN (:modes)")
|
@Query("SELECT catnum FROM radios WHERE downlinkMode IN (:modes)")
|
||||||
suspend fun getIdsWithModes(modes: List<String>): List<Int>
|
suspend fun getIdsWithModes(modes: List<String>): List<Int>
|
||||||
|
|
||||||
@Query("SELECT COUNT(*) FROM radios")
|
@Query("SELECT COUNT(*) FROM radios")
|
||||||
|
|
|
@ -17,14 +17,4 @@
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.data.database.entity
|
package com.rtbishop.look4sat.data.database.entity
|
||||||
|
|
||||||
data class SatItem(
|
data class SatItem(val catnum: Int, val name: String)
|
||||||
val catnum: Int,
|
|
||||||
val name: String
|
|
||||||
// @Relation(
|
|
||||||
// parentColumn = "catnum",
|
|
||||||
// entity = SatRadio::class,
|
|
||||||
// entityColumn = "catnum",
|
|
||||||
// projection = ["mode"]
|
|
||||||
// )
|
|
||||||
// val modes: List<String>
|
|
||||||
)
|
|
||||||
|
|
|
@ -25,9 +25,12 @@ data class SatRadio(
|
||||||
@PrimaryKey val uuid: String,
|
@PrimaryKey val uuid: String,
|
||||||
val info: String,
|
val info: String,
|
||||||
val isAlive: Boolean,
|
val isAlive: Boolean,
|
||||||
var downlink: Long?,
|
var downlinkLow: Long?,
|
||||||
var uplink: Long?,
|
var downlinkHigh: Long?,
|
||||||
val mode: String?,
|
val downlinkMode: String?,
|
||||||
|
var uplinkLow: Long?,
|
||||||
|
var uplinkHigh: Long?,
|
||||||
|
val uplinkMode: String?,
|
||||||
val isInverted: Boolean,
|
val isInverted: Boolean,
|
||||||
val catnum: Int?,
|
val catnum: Int?,
|
||||||
var comment: String? = null
|
var comment: String? = null
|
||||||
|
|
|
@ -76,8 +76,8 @@ class SatelliteRepo(
|
||||||
val satPos = sat.getPosition(pos, time)
|
val satPos = sat.getPosition(pos, time)
|
||||||
val copiedList = radios.map { it.copy() }
|
val copiedList = radios.map { it.copy() }
|
||||||
copiedList.forEach { transmitter ->
|
copiedList.forEach { transmitter ->
|
||||||
transmitter.downlink?.let { transmitter.downlink = satPos.getDownlinkFreq(it) }
|
transmitter.downlinkLow?.let { transmitter.downlinkLow = satPos.getDownlinkFreq(it) }
|
||||||
transmitter.uplink?.let { transmitter.uplink = satPos.getUplinkFreq(it) }
|
transmitter.uplinkLow?.let { transmitter.uplinkLow = satPos.getUplinkFreq(it) }
|
||||||
}
|
}
|
||||||
copiedList.map { it.copy() }
|
copiedList.map { it.copy() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,13 +80,13 @@ class LocalSource(private val storageDao: StorageDao) : ILocalSource {
|
||||||
override suspend fun deleteRadios() = storageDao.deleteRadios()
|
override suspend fun deleteRadios() = storageDao.deleteRadios()
|
||||||
|
|
||||||
private fun DomainRadio.toFramework() = FrameworkRadio(
|
private fun DomainRadio.toFramework() = FrameworkRadio(
|
||||||
this.uuid, this.info, this.isAlive, this.downlink, this.uplink,
|
this.uuid, this.info, this.isAlive, this.downlinkLow, this.downlinkHigh, this.downlinkMode,
|
||||||
this.mode, this.isInverted, this.catnum, this.comment
|
this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum, this.comment
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun FrameworkRadio.toDomain() = DomainRadio(
|
private fun FrameworkRadio.toDomain() = DomainRadio(
|
||||||
this.uuid, this.info, this.isAlive, this.downlink, this.uplink,
|
this.uuid, this.info, this.isAlive, this.downlinkLow, this.downlinkHigh, this.downlinkMode,
|
||||||
this.mode, this.isInverted, this.catnum, this.comment
|
this.uplinkLow, this.uplinkHigh, this.uplinkMode, this.isInverted, this.catnum, this.comment
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun List<DomainRadio>.toFrameworkRadios() = this.map { radio -> radio.toFramework() }
|
private fun List<DomainRadio>.toFrameworkRadios() = this.map { radio -> radio.toFramework() }
|
||||||
|
|
|
@ -17,9 +17,4 @@
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain.model
|
package com.rtbishop.look4sat.domain.model
|
||||||
|
|
||||||
data class SatItem(
|
data class SatItem(val catnum: Int, val name: String, val isSelected: Boolean)
|
||||||
val catnum: Int,
|
|
||||||
val name: String,
|
|
||||||
// val modes: List<String>,
|
|
||||||
val isSelected: Boolean
|
|
||||||
)
|
|
||||||
|
|
|
@ -21,9 +21,12 @@ data class SatRadio(
|
||||||
val uuid: String,
|
val uuid: String,
|
||||||
val info: String,
|
val info: String,
|
||||||
val isAlive: Boolean,
|
val isAlive: Boolean,
|
||||||
var downlink: Long?,
|
var downlinkLow: Long?,
|
||||||
var uplink: Long?,
|
var downlinkHigh: Long?,
|
||||||
val mode: String?,
|
val downlinkMode: String?,
|
||||||
|
var uplinkLow: Long?,
|
||||||
|
var uplinkHigh: Long?,
|
||||||
|
val uplinkMode: String?,
|
||||||
val isInverted: Boolean,
|
val isInverted: Boolean,
|
||||||
val catnum: Int?,
|
val catnum: Int?,
|
||||||
var comment: String? = null
|
var comment: String? = null
|
||||||
|
|
|
@ -383,6 +383,16 @@ abstract class Satellite(val data: OrbitalData) {
|
||||||
return acos(dot(v1, v2) / (v1.w * v2.w))
|
return acos(dot(v1, v2) / (v1.w * v2.w))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function Delta_ET has been added to allow calculations on the
|
||||||
|
* position of the sun. It provides the difference between UT (approximately
|
||||||
|
* the same as UTC) and ET (now referred to as TDT) This function is based
|
||||||
|
* on a least squares fit of data from 1950 to 1991 and will need to be
|
||||||
|
* updated periodically.
|
||||||
|
*
|
||||||
|
* Values determined using data from 1950-1991 in the 1990 Astronomical
|
||||||
|
* Almanac. See DELTA_ET.WQ1 for details.
|
||||||
|
*/
|
||||||
private fun deltaEt(year: Double): Double {
|
private fun deltaEt(year: Double): Double {
|
||||||
return 26.465 + 0.747622 * (year - 1950) + (1.886913 * sin(TWO_PI * (year - 1975) / 33))
|
return 26.465 + 0.747622 * (year - 1950) + (1.886913 * sin(TWO_PI * (year - 1975) / 33))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,12 @@ package com.rtbishop.look4sat.domain.utility
|
||||||
|
|
||||||
import com.rtbishop.look4sat.domain.model.SatRadio
|
import com.rtbishop.look4sat.domain.model.SatRadio
|
||||||
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
import com.rtbishop.look4sat.domain.predict.OrbitalData
|
||||||
|
import java.io.InputStream
|
||||||
|
import kotlin.math.pow
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.InputStream
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
class DataParser(private val dispatcher: CoroutineDispatcher) {
|
class DataParser(private val dispatcher: CoroutineDispatcher) {
|
||||||
|
|
||||||
|
@ -74,75 +74,30 @@ class DataParser(private val dispatcher: CoroutineDispatcher) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseCSV(values: List<String>): OrbitalData? {
|
private fun parseCSV(values: List<String>): OrbitalData? = try {
|
||||||
try {
|
val name = values[0]
|
||||||
val name = values[0]
|
val year = values[2].substring(0, 4)
|
||||||
val year = values[2].substring(0, 4)
|
val month = values[2].substring(5, 7)
|
||||||
val month = values[2].substring(5, 7)
|
val dayOfMonth = values[2].substring(8, 10)
|
||||||
val dayOfMonth = values[2].substring(8, 10)
|
val dayInt = getDayOfYear(year.toInt(), month.toInt(), dayOfMonth.toInt())
|
||||||
val dayInt = getDayOfYear(year.toInt(), month.toInt(), dayOfMonth.toInt())
|
val day = if (dayInt < 10) "00$dayInt" else if (dayInt < 100) "0$dayInt" else "$dayInt"
|
||||||
val day = if (dayInt < 10) "00$dayInt" else if (dayInt < 100) "0$dayInt" else "$dayInt"
|
val hour = values[2].substring(11, 13).toInt() * 3600000 // ms in one hour
|
||||||
val hour = values[2].substring(11, 13).toInt() * 3600000 // ms in one hour
|
val min = values[2].substring(14, 16).toInt() * 60000 // ms in one minute
|
||||||
val min = values[2].substring(14, 16).toInt() * 60000 // ms in one minute
|
val sec = values[2].substring(17, 19).toInt() * 1000 // ms in one second
|
||||||
val sec = values[2].substring(17, 19).toInt() * 1000 // ms in one second
|
val ms = values[2].substring(20, 26).toInt() / 1000.0 // microseconds to ms
|
||||||
val ms = values[2].substring(20, 26).toInt() / 1000.0 // microseconds to ms
|
val frac = ((hour + min + sec + ms) / 86400000.0).toString()
|
||||||
val frac = ((hour + min + sec + ms) / 86400000.0).toString()
|
val epoch = "${year.substring(2)}$day${frac.substring(1)}".toDouble()
|
||||||
val epoch = "${year.substring(2)}$day${frac.substring(1)}".toDouble()
|
val meanmo = values[3].toDouble()
|
||||||
val meanmo = values[3].toDouble()
|
val eccn = values[4].toDouble()
|
||||||
val eccn = values[4].toDouble()
|
val incl = values[5].toDouble()
|
||||||
val incl = values[5].toDouble()
|
val raan = values[6].toDouble()
|
||||||
val raan = values[6].toDouble()
|
val argper = values[7].toDouble()
|
||||||
val argper = values[7].toDouble()
|
val meanan = values[8].toDouble()
|
||||||
val meanan = values[8].toDouble()
|
val catnum = values[11].toInt()
|
||||||
val catnum = values[11].toInt()
|
val bstar = values[14].toDouble()
|
||||||
val bstar = values[14].toDouble()
|
OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
||||||
return OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
} catch (exception: Exception) {
|
||||||
} catch (exception: Exception) {
|
null
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseTLE(tle: List<String>): OrbitalData? {
|
|
||||||
if (tle[1].substring(0, 1) != "1" && tle[2].substring(0, 1) != "2") {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
val name: String = tle[0].trim()
|
|
||||||
val epoch: Double = tle[1].substring(18, 32).toDouble()
|
|
||||||
val meanmo: Double = tle[2].substring(52, 63).toDouble()
|
|
||||||
val eccn: Double = tle[2].substring(26, 33).toDouble() / 10000000.0
|
|
||||||
val incl: Double = tle[2].substring(8, 16).toDouble()
|
|
||||||
val raan: Double = tle[2].substring(17, 25).toDouble()
|
|
||||||
val argper: Double = tle[2].substring(34, 42).toDouble()
|
|
||||||
val meanan: Double = tle[2].substring(43, 51).toDouble()
|
|
||||||
val catnum: Int = tle[1].substring(2, 7).trim().toInt()
|
|
||||||
val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() / 10.0.pow(
|
|
||||||
tle[1].substring(60, 61).toDouble()
|
|
||||||
)
|
|
||||||
return OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseJSON(json: JSONObject): SatRadio? {
|
|
||||||
try {
|
|
||||||
val uuid = json.getString("uuid")
|
|
||||||
val info = json.getString("description")
|
|
||||||
val isAlive = json.getBoolean("alive")
|
|
||||||
val downlink = if (json.isNull("downlink_low")) null
|
|
||||||
else json.getLong("downlink_low")
|
|
||||||
val uplink = if (json.isNull("uplink_low")) null
|
|
||||||
else json.getLong("uplink_low")
|
|
||||||
val mode = if (json.isNull("mode")) null
|
|
||||||
else json.getString("mode")
|
|
||||||
val isInverted = json.getBoolean("invert")
|
|
||||||
val catnum = if (json.isNull("norad_cat_id")) null
|
|
||||||
else json.getInt("norad_cat_id")
|
|
||||||
return SatRadio(uuid, info, isAlive, downlink, uplink, mode, isInverted, catnum)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDayOfYear(year: Int, month: Int, dayOfMonth: Int): Int {
|
private fun getDayOfYear(year: Int, month: Int, dayOfMonth: Int): Int {
|
||||||
|
@ -154,4 +109,37 @@ class DataParser(private val dispatcher: CoroutineDispatcher) {
|
||||||
for (i in 0 until month - 1) dayOfYear += daysArray[i]
|
for (i in 0 until month - 1) dayOfYear += daysArray[i]
|
||||||
return dayOfYear
|
return dayOfYear
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseTLE(tle: List<String>): OrbitalData? = try {
|
||||||
|
val name: String = tle[0].trim()
|
||||||
|
val epoch: Double = tle[1].substring(18, 32).toDouble()
|
||||||
|
val meanmo: Double = tle[2].substring(52, 63).toDouble()
|
||||||
|
val eccn: Double = tle[2].substring(26, 33).toDouble() / 10000000.0
|
||||||
|
val incl: Double = tle[2].substring(8, 16).toDouble()
|
||||||
|
val raan: Double = tle[2].substring(17, 25).toDouble()
|
||||||
|
val argper: Double = tle[2].substring(34, 42).toDouble()
|
||||||
|
val meanan: Double = tle[2].substring(43, 51).toDouble()
|
||||||
|
val catnum: Int = tle[1].substring(2, 7).trim().toInt()
|
||||||
|
val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() / 10.0.pow(tle[1].substring(60, 61).toDouble())
|
||||||
|
OrbitalData(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseJSON(json: JSONObject): SatRadio? = try {
|
||||||
|
val uuid = json.getString("uuid")
|
||||||
|
val info = json.getString("description")
|
||||||
|
val alive = json.getBoolean("alive")
|
||||||
|
val dlinkLow = if (json.isNull("downlink_low")) null else json.getLong("downlink_low")
|
||||||
|
val dlinkHigh = if (json.isNull("downlink_high")) null else json.getLong("downlink_high")
|
||||||
|
val dlinkMode = if (json.isNull("mode")) null else json.getString("mode")
|
||||||
|
val ulinkLow = if (json.isNull("uplink_low")) null else json.getLong("uplink_low")
|
||||||
|
val ulinkHigh = if (json.isNull("uplink_high")) null else json.getLong("uplink_high")
|
||||||
|
val ulinkMode = if (json.isNull("uplink_mode")) null else json.getString("uplink_mode")
|
||||||
|
val inverted = json.getBoolean("invert")
|
||||||
|
val catnum = if (json.isNull("norad_cat_id")) null else json.getInt("norad_cat_id")
|
||||||
|
SatRadio(uuid, info, alive, dlinkLow, dlinkHigh, dlinkMode, ulinkLow, ulinkHigh, ulinkMode, inverted, catnum)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ class DataParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) {
|
fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) {
|
||||||
assert(dataParser.parseJSONStream(validJSONStream)[0].downlink == 136658500L)
|
assert(dataParser.parseJSONStream(validJSONStream)[0].downlinkLow == 136658500L)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Ładowanie…
Reference in New Issue