Added GeoConverter.kt and various minor fixes

develop
Arty Bishop 2023-07-30 12:48:47 +01:00
rodzic 5f392304d3
commit 814a23e730
9 zmienionych plików z 108 dodań i 41 usunięć

Wyświetl plik

@ -9,6 +9,7 @@
android:name=".MainApplication" android:name=".MainApplication"
android:allowBackup="false" android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@ -16,7 +17,7 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Look4Sat.Main" android:theme="@style/Theme.Look4Sat.Main"
tools:targetApi="31"> tools:targetApi="33">
<activity <activity
android:name=".MainActivity" 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.BluetoothReporter
import com.rtbishop.look4sat.data.framework.NetworkReporter import com.rtbishop.look4sat.data.framework.NetworkReporter
import com.rtbishop.look4sat.data.framework.SettingsRepo 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.DatabaseRepo
import com.rtbishop.look4sat.data.repository.SatelliteRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo
import com.rtbishop.look4sat.data.repository.SelectionRepo 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.ISatelliteRepo
import com.rtbishop.look4sat.domain.repository.ISelectionRepo import com.rtbishop.look4sat.domain.repository.ISelectionRepo
import com.rtbishop.look4sat.domain.repository.ISettingsRepo 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.source.ISensorSource
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import okhttp3.Cache
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.osmdroid.config.Configuration import org.osmdroid.config.Configuration
class MainContainer(private val context: Context) { class MainContainer(private val context: Context) {
private val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb") private val database =
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build() Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb").addMigrations(MIGRATION_1_2)
.fallbackToDestructiveMigration().build()
private val localStorage = LocalStorage(database.storageDao()) private val localStorage = LocalStorage(database.storageDao())
private val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") } private val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") }
private val remoteSource = provideRemoteSource()
val mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler) val mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler)
val settingsRepo = provideSettingsRepo() val settingsRepo = provideSettingsRepo()
val databaseRepo = provideDatabaseRepo() val databaseRepo = provideDatabaseRepo()
@ -57,11 +61,15 @@ class MainContainer(private val context: Context) {
return SensorSource(sensorManager, sensor) 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 { private fun provideDatabaseRepo(): IDatabaseRepo {
val httpClient = OkHttpClient.Builder().build()
val dataParser = DataParser(Dispatchers.Default) val dataParser = DataParser(Dispatchers.Default)
val dataSource = DataSource(context.contentResolver, httpClient, Dispatchers.IO) return DatabaseRepo(Dispatchers.Default, dataParser, remoteSource, localStorage, settingsRepo)
return DatabaseRepo(Dispatchers.Default, dataParser, dataSource, localStorage, settingsRepo)
} }
private fun provideSatelliteRepo(): ISatelliteRepo { 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.repository.ISettingsRepo
import com.rtbishop.look4sat.domain.source.IDataSource import com.rtbishop.look4sat.domain.source.IDataSource
import com.rtbishop.look4sat.domain.source.ILocalStorage import com.rtbishop.look4sat.domain.source.ILocalStorage
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.withContext 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 { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.json:json:20230618")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.13.5") 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.data.repository 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

Wyświetl plik

@ -17,8 +17,6 @@
*/ */
package com.rtbishop.look4sat.domain.utility 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 import java.util.concurrent.TimeUnit
fun Long.toTimerString(): String { fun Long.toTimerString(): String {
@ -41,10 +39,6 @@ fun Double.round(decimals: Int): Double {
return kotlin.math.round(this * multiplier) / multiplier 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 { //fun String.getHash(type: String = "SHA-256"): String {
// val hexChars = "0123456789ABCDEF" // val hexChars = "0123456789ABCDEF"
// val bytes = MessageDigest.getInstance(type).digest(this.toByteArray()) // val bytes = MessageDigest.getInstance(type).digest(this.toByteArray())
@ -63,12 +57,12 @@ fun Double.toRadians(): Double = this * DEG2RAD
// return pattern.matcher(this).matches() // return pattern.matcher(this).matches()
//} //}
fun String.isValidIPv4(): Boolean { //fun String.isValidIPv4(): Boolean {
val ip4 = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(?!\$)|\$)){4}\$" // val ip4 = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(?!\$)|\$)){4}\$"
return this.matches(ip4.toRegex()) // return this.matches(ip4.toRegex())
} //}
fun String.isValidPort(): Boolean { //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])" // 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 // 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.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.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -49,12 +49,12 @@ class DataParserTest {
1 25544U 98067A 21320.51955234 .00001288 00000+0 31985-4 0 9990 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 2 25544 51.6447 309.4881 0004694 203.6966 299.8876 15.48582035312205
""".trimIndent().byteInputStream() """.trimIndent().byteInputStream()
// private val validJSONStream = """ 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":""}] [{"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() """.trimIndent().byteInputStream()
// private val invalidJSONStream = """ 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":""}] [{"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() """.trimIndent().byteInputStream()
@Test @Test
fun `Given valid CSV stream returns valid data`() = runTest(testDispatcher) { fun `Given valid CSV stream returns valid data`() = runTest(testDispatcher) {
@ -87,15 +87,15 @@ class DataParserTest {
assert(csvResult == tleResult) assert(csvResult == tleResult)
} }
// @Test @Test
// fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) { fun `Given valid JSON stream returns valid data`() = runTest(testDispatcher) {
// val parsedList = dataParser.parseJSONStream(validJSONStream) val parsedList = dataParser.parseJSONStream(validJSONStream)
// assert(parsedList[0].downlink == 136658500L) assert(parsedList[0].downlink == 136658500L)
// } }
//
// @Test @Test
// fun `Given invalid JSON stream returns empty list`() = runTest(testDispatcher) { fun `Given invalid JSON stream returns empty list`() = runTest(testDispatcher) {
// val parsedList = dataParser.parseJSONStream(invalidJSONStream) val parsedList = dataParser.parseJSONStream(invalidJSONStream)
// assert(parsedList.isEmpty()) assert(parsedList.isEmpty())
// } }
} }