Added GeoConverter.kt and various minor fixes

pull/122/head
Arty Bishop 2023-07-30 12:48:47 +01:00
rodzic 3efff32dbb
commit 6a2a4f9f9e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 5C71CFDC37AD73CC
9 zmienionych plików z 108 dodań i 41 usunięć

Wyświetl plik

@ -9,6 +9,7 @@
android:name=".MainApplication"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@ -16,7 +17,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Look4Sat.Main"
tools:targetApi="31">
tools:targetApi="33">
<activity
android:name=".MainActivity"

Wyświetl plik

@ -11,7 +11,6 @@ import com.rtbishop.look4sat.data.database.MainDatabase
import com.rtbishop.look4sat.data.framework.BluetoothReporter
import com.rtbishop.look4sat.data.framework.NetworkReporter
import com.rtbishop.look4sat.data.framework.SettingsRepo
import com.rtbishop.look4sat.data.repository.DataParser
import com.rtbishop.look4sat.data.repository.DatabaseRepo
import com.rtbishop.look4sat.data.repository.SatelliteRepo
import com.rtbishop.look4sat.data.repository.SelectionRepo
@ -22,20 +21,25 @@ 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.ISettingsRepo
import com.rtbishop.look4sat.domain.source.IDataSource
import com.rtbishop.look4sat.domain.source.ISensorSource
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import okhttp3.Cache
import okhttp3.OkHttpClient
import org.osmdroid.config.Configuration
class MainContainer(private val context: Context) {
private val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb")
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
private val database =
Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb").addMigrations(MIGRATION_1_2)
.fallbackToDestructiveMigration().build()
private val localStorage = LocalStorage(database.storageDao())
private val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") }
private val remoteSource = provideRemoteSource()
val mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler)
val settingsRepo = provideSettingsRepo()
val databaseRepo = provideDatabaseRepo()
@ -57,11 +61,15 @@ class MainContainer(private val context: Context) {
return SensorSource(sensorManager, sensor)
}
private fun provideRemoteSource(): IDataSource {
val cache = Cache(context.cacheDir, 1000 * 1000 * 10L)
val httpClient = OkHttpClient.Builder().cache(cache).build()
return DataSource(context.contentResolver, httpClient, Dispatchers.IO)
}
private fun provideDatabaseRepo(): IDatabaseRepo {
val httpClient = OkHttpClient.Builder().build()
val dataParser = DataParser(Dispatchers.Default)
val dataSource = DataSource(context.contentResolver, httpClient, Dispatchers.IO)
return DatabaseRepo(Dispatchers.Default, dataParser, dataSource, localStorage, settingsRepo)
return DatabaseRepo(Dispatchers.Default, dataParser, remoteSource, localStorage, settingsRepo)
}
private fun provideSatelliteRepo(): ISatelliteRepo {

Wyświetl plik

@ -24,6 +24,7 @@ import com.rtbishop.look4sat.domain.repository.IDatabaseRepo
import com.rtbishop.look4sat.domain.repository.ISettingsRepo
import com.rtbishop.look4sat.domain.source.IDataSource
import com.rtbishop.look4sat.domain.source.ILocalStorage
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext

Wyświetl plik

@ -0,0 +1,12 @@
package com.rtbishop.look4sat.data
import org.junit.Assert
import org.junit.Test
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
Assert.assertEquals(4, 2 + 2)
}
}

Wyświetl plik

@ -8,6 +8,7 @@ kotlin {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.json:json:20230618")
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.13.5")

Wyświetl plik

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.data.repository
package com.rtbishop.look4sat.domain.utility
import com.rtbishop.look4sat.domain.model.SatRadio
import com.rtbishop.look4sat.domain.predict.OrbitalData

Wyświetl plik

@ -17,8 +17,6 @@
*/
package com.rtbishop.look4sat.domain.utility
import com.rtbishop.look4sat.domain.predict.DEG2RAD
import com.rtbishop.look4sat.domain.predict.RAD2DEG
import java.util.concurrent.TimeUnit
fun Long.toTimerString(): String {
@ -41,10 +39,6 @@ fun Double.round(decimals: Int): Double {
return kotlin.math.round(this * multiplier) / multiplier
}
fun Double.toDegrees(): Double = this * RAD2DEG
fun Double.toRadians(): Double = this * DEG2RAD
//fun String.getHash(type: String = "SHA-256"): String {
// val hexChars = "0123456789ABCDEF"
// val bytes = MessageDigest.getInstance(type).digest(this.toByteArray())
@ -63,12 +57,12 @@ fun Double.toRadians(): Double = this * DEG2RAD
// return pattern.matcher(this).matches()
//}
fun String.isValidIPv4(): Boolean {
val ip4 = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(?!\$)|\$)){4}\$"
return this.matches(ip4.toRegex())
}
//fun String.isValidIPv4(): Boolean {
// val ip4 = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(?!\$)|\$)){4}\$"
// return this.matches(ip4.toRegex())
//}
fun String.isValidPort(): Boolean {
val port = "([1-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])"
return this.matches(port.toRegex()) && this.toInt() in 1024..65535
}
//fun String.isValidPort(): Boolean {
// val port = "([1-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])"
// return this.matches(port.toRegex()) && this.toInt() in 1024..65535
//}

Wyświetl plik

@ -0,0 +1,50 @@
package com.rtbishop.look4sat.domain.utility
import com.rtbishop.look4sat.domain.predict.DEG2RAD
import com.rtbishop.look4sat.domain.predict.PI
import com.rtbishop.look4sat.domain.predict.RAD2DEG
import kotlin.math.ln
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin
private const val MIN_LATITUDE = -85.05112877980658
private const val MAX_LATITUDE = 85.05112877980658
private const val MIN_LONGITUDE = -180.0
private const val MAX_LONGITUDE = 180.0
fun Double.toDegrees(): Double = this * RAD2DEG
fun Double.toRadians(): Double = this * DEG2RAD
fun Double.latToY01(): Double {
val sinus = sin(clipLat(this) * PI / MAX_LONGITUDE)
return 0.5 - ln((1 + sinus) / (1 - sinus)) / (4 * PI)
}
fun Double.lonToX01(): Double {
return (clipLon(this) - MIN_LONGITUDE) / (MAX_LONGITUDE - MIN_LONGITUDE)
}
//fun Double.y01ToLat(): Double {
// return 90 - 360 * atan(exp((this - 0.5) * 2 * PI)) / PI
//}
//fun Double.x01ToLon(): Double {
// return MIN_LONGITUDE + (MAX_LONGITUDE - MIN_LONGITUDE) * this
//}
private fun clipLat(latitude: Double): Double {
return clip(latitude, MIN_LATITUDE, MAX_LATITUDE)
}
private fun clipLon(longitude: Double): Double {
var result = longitude
while (result < MIN_LONGITUDE) result += 360.0
while (result > MAX_LONGITUDE) result -= 360.0
return clip(result, MIN_LONGITUDE, MAX_LONGITUDE)
}
private fun clip(currentValue: Double, minValue: Double, maxValue: Double): Double {
return min(max(currentValue, minValue), maxValue)
}

Wyświetl plik

@ -15,9 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.data
package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.data.repository.DataParser
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest
@ -49,12 +49,12 @@ class DataParserTest {
1 25544U 98067A 21320.51955234 .00001288 00000+0 31985-4 0 9990
2 25544 51.6447 309.4881 0004694 203.6966 299.8876 15.48582035312205
""".trimIndent().byteInputStream()
// private val validJSONStream = """
// [{"uuid":"UzPz4gcsNBPKPKAFPmer7g","description":"Upper side band (drifting)","alive":true,"type":"Transmitter","uplink_low":null,"uplink_high":null,"uplink_drift":null,"downlink_low":136658500,"downlink_high":null,"downlink_drift":null,"mode":"USB","mode_id":9,"uplink_mode":null,"invert":false,"baud":null,"sat_id":"SCHX-0895-2361-9925-0309","norad_cat_id":965,"status":"active","updated":"2019-04-18T05:39:53.343316Z","citation":"CITATION NEEDED - https://xkcd.com/285/","service":"Unknown","coordination":"","coordination_url":""}]
// """.trimIndent().byteInputStream()
// private val invalidJSONStream = """
// [{"description":"Upper side band (drifting)","alive":true,"type":"Transmitter","uplink_low":null,"uplink_high":null,"uplink_drift":null,"downlink_low":136658500,"downlink_high":null,"downlink_drift":null,"mode":"USB","mode_id":9,"uplink_mode":null,"invert":false,"baud":null,"sat_id":"SCHX-0895-2361-9925-0309","norad_cat_id":965,"status":"active","updated":"2019-04-18T05:39:53.343316Z","citation":"CITATION NEEDED - https://xkcd.com/285/","service":"Unknown","coordination":"","coordination_url":""}]
// """.trimIndent().byteInputStream()
private val validJSONStream = """
[{"uuid":"UzPz4gcsNBPKPKAFPmer7g","description":"Upper side band (drifting)","alive":true,"type":"Transmitter","uplink_low":null,"uplink_high":null,"uplink_drift":null,"downlink_low":136658500,"downlink_high":null,"downlink_drift":null,"mode":"USB","mode_id":9,"uplink_mode":null,"invert":false,"baud":null,"sat_id":"SCHX-0895-2361-9925-0309","norad_cat_id":965,"status":"active","updated":"2019-04-18T05:39:53.343316Z","citation":"CITATION NEEDED - https://xkcd.com/285/","service":"Unknown","coordination":"","coordination_url":""}]
""".trimIndent().byteInputStream()
private val invalidJSONStream = """
[{"description":"Upper side band (drifting)","alive":true,"type":"Transmitter","uplink_low":null,"uplink_high":null,"uplink_drift":null,"downlink_low":136658500,"downlink_high":null,"downlink_drift":null,"mode":"USB","mode_id":9,"uplink_mode":null,"invert":false,"baud":null,"sat_id":"SCHX-0895-2361-9925-0309","norad_cat_id":965,"status":"active","updated":"2019-04-18T05:39:53.343316Z","citation":"CITATION NEEDED - https://xkcd.com/285/","service":"Unknown","coordination":"","coordination_url":""}]
""".trimIndent().byteInputStream()
@Test
fun `Given valid CSV stream returns valid data`() = runTest(testDispatcher) {
@ -87,15 +87,15 @@ class DataParserTest {
assert(csvResult == tleResult)
}
// @Test
// fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) {
// val parsedList = dataParser.parseJSONStream(validJSONStream)
// assert(parsedList[0].downlink == 136658500L)
// }
//
// @Test
// fun `Given invalid JSON stream returns empty list`() = runTest(testDispatcher) {
// val parsedList = dataParser.parseJSONStream(invalidJSONStream)
// assert(parsedList.isEmpty())
// }
@Test
fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) {
val parsedList = dataParser.parseJSONStream(validJSONStream)
assert(parsedList[0].downlink == 136658500L)
}
@Test
fun `Given invalid JSON stream returns empty list`() = runTest(testDispatcher) {
val parsedList = dataParser.parseJSONStream(invalidJSONStream)
assert(parsedList.isEmpty())
}
}