Added initial code for the custom tle import from file

This commit is contained in:
Arty Bishop committed 2020-05-10 19:07:07 +01:00
1 parent 7c60fa9b2b
commit 3b5c3a8bb3
11 files changed
+118 -24

No files matched your search

@@ -1,5 +1,7 @@
package com.rtbishop.look4sat.dagger.modules
import android.content.ContentResolver
import android.content.Context
import com.rtbishop.look4sat.network.RemoteSource
import com.rtbishop.look4sat.persistence.LocalSource
import com.rtbishop.look4sat.repo.DefaultRepository
@@ -13,7 +15,17 @@ class RepoModule {
@Singleton
@Provides
fun provideDefaultRepository(localSource: LocalSource, remoteSource: RemoteSource): Repository {
return DefaultRepository(localSource, remoteSource)
fun provideContentResolver(context: Context): ContentResolver {
return context.applicationContext.contentResolver
}
@Singleton
@Provides
fun provideDefaultRepository(
resolver: ContentResolver,
localSource: LocalSource,
remoteSource: RemoteSource
): Repository {
return DefaultRepository(resolver, localSource, remoteSource)
}
}
@@ -34,14 +34,12 @@ class RemoteDataSource @Inject constructor(
private val client: OkHttpClient
) : RemoteSource {
override suspend fun fetchTleStream(urlList: List<String>): InputStream {
override suspend fun fetchTleStream(tleUrl: String): InputStream {
val streamTable = Hashtable<String, InputStream>()
withContext(Dispatchers.IO) {
urlList.forEach {
val request = Request.Builder().url(it).build()
val stream = client.newCall(request).execute().body()?.byteStream()
streamTable[it] = stream
}
val request = Request.Builder().url(tleUrl).build()
val stream = client.newCall(request).execute().body()?.byteStream()
streamTable[tleUrl] = stream
}
return SequenceInputStream(streamTable.elements())
}
@@ -5,7 +5,7 @@ import java.io.InputStream
interface RemoteSource {
suspend fun fetchTleStream(urlList: List<String>): InputStream
suspend fun fetchTleStream(tleUrl: String): InputStream
suspend fun fetchTransmitters(): List<Transmitter>
}
@@ -19,6 +19,8 @@
package com.rtbishop.look4sat.repo
import android.content.ContentResolver
import android.net.Uri
import com.github.amsacode.predict4java.TLE
import com.rtbishop.look4sat.data.SatEntry
import com.rtbishop.look4sat.data.Transmitter
@@ -29,12 +31,23 @@ import kotlinx.coroutines.withContext
import javax.inject.Inject
class DefaultRepository @Inject constructor(
private val resolver: ContentResolver,
private val localSource: LocalSource,
private val remoteSource: RemoteSource
) : Repository {
override suspend fun updateEntriesFrom(urlList: List<String>) {
val stream = remoteSource.fetchTleStream(urlList)
override suspend fun updateEntriesFromFile(uri: Uri) {
resolver.openInputStream(uri)?.use {
withContext(Dispatchers.IO) {
val tleList = TLE.importSat(it)
val entries = tleList.map { SatEntry(it) }
localSource.insertEntries(entries)
}
}
}
override suspend fun updateEntriesFromUrl(tleUrl: String) {
val stream = remoteSource.fetchTleStream(tleUrl)
withContext(Dispatchers.IO) {
val tleList = TLE.importSat(stream)
val entries = tleList.map { SatEntry(it) }
@@ -1,11 +1,14 @@
package com.rtbishop.look4sat.repo
import android.net.Uri
import com.rtbishop.look4sat.data.SatEntry
import com.rtbishop.look4sat.data.Transmitter
interface Repository {
suspend fun updateEntriesFrom(urlList: List<String>)
suspend fun updateEntriesFromFile(uri: Uri)
suspend fun updateEntriesFromUrl(tleUrl: String)
suspend fun getAllEntries(): List<SatEntry>
@@ -21,6 +21,7 @@ package com.rtbishop.look4sat.ui
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
@@ -52,6 +53,7 @@ import javax.inject.Inject
class MainActivity : AppCompatActivity() {
private val pickFileReqCode = 111
private val permLocationCode = 101
private val permLocation = Manifest.permission.ACCESS_FINE_LOCATION
private val permGranted = PackageManager.PERMISSION_GRANTED
@@ -150,8 +152,17 @@ class MainActivity : AppCompatActivity() {
requestLocationUpdate()
it.lockButton()
}
drawerBinding.drawerBtnTle.setOnClickListener {
viewModel.updateEntries()
drawerBinding.drawerBtnTleFile.setOnClickListener {
val openFileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/*"
}
startActivityForResult(openFileIntent, pickFileReqCode)
mainBinding.drawerLayout.closeDrawers()
it.lockButton()
}
drawerBinding.drawerBtnTleUrl.setOnClickListener {
viewModel.updateEntriesFromWeb()
it.lockButton()
}
drawerBinding.drawerBtnTrans.setOnClickListener {
@@ -204,4 +215,14 @@ class MainActivity : AppCompatActivity() {
val navController = findNavController(R.id.nav_host)
return navController.navigateUp(appBarConfig) || super.onSupportNavigateUp()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == pickFileReqCode && resultCode == Activity.RESULT_OK) {
data?.data?.also { uri ->
viewModel.updateEntriesFromFile(uri)
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
}
@@ -20,6 +20,7 @@
package com.rtbishop.look4sat.ui
import android.location.LocationManager
import android.net.Uri
import androidx.lifecycle.*
import com.github.amsacode.predict4java.GroundStationPosition
import com.rtbishop.look4sat.data.Result
@@ -46,7 +47,6 @@ class SharedViewModel @Inject constructor(
private val _gsp = MutableLiveData<Result<GroundStationPosition>>().apply {
value = Result.Success(prefsManager.getPosition())
}
private val urlList = listOf("https://celestrak.com/NORAD/elements/active.txt")
private var calculationJob: Job? = null
var isFirstLaunch = true
@@ -85,11 +85,25 @@ class SharedViewModel @Inject constructor(
}
}
fun updateEntries() {
fun updateEntriesFromFile(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
try {
val selected = repository.getSelectedEntries().map { it.catNum }
repository.updateEntriesFrom(urlList)
repository.updateEntriesFromFile(uri)
repository.updateEntriesSelection(selected)
_updateStatus.postValue(Result.Success(0))
} catch (e: Exception) {
_updateStatus.postValue(Result.Error(e))
}
}
}
fun updateEntriesFromWeb() {
viewModelScope.launch(Dispatchers.IO) {
try {
val url = prefsManager.getTleUrl()
val selected = repository.getSelectedEntries().map { it.catNum }
repository.updateEntriesFromUrl(url)
repository.updateEntriesSelection(selected)
_updateStatus.postValue(Result.Success(0))
} catch (e: Exception) {
@@ -36,10 +36,12 @@ class PrefsManager @Inject constructor(
private val keyAltitude = "altitude"
private val keyRefreshRate = "rate"
private val keyCompass = "compass"
private val keyTleUrl = "tleUrl"
private val defaultHoursAhead = 8
private val defaultMinEl = 16.0
private val defaultRefreshRate = "3000"
private val defaultGSP = "0.0"
private val defaultTleUrl = "https://celestrak.com/NORAD/elements/active.txt"
fun getHoursAhead(): Int {
return preferences.getInt(keyHoursAhead, defaultHoursAhead)
@@ -64,6 +66,10 @@ class PrefsManager @Inject constructor(
return GroundStationPosition(lat, lon, alt)
}
fun getTleUrl(): String {
return preferences.getString(keyTleUrl, defaultTleUrl)!!
}
fun setHoursAhead(hours: Int) {
preferences.edit {
putInt(keyHoursAhead, hours)
@@ -94,6 +100,12 @@ class PrefsManager @Inject constructor(
}
}
fun setTleUrl(tleUrl: String) {
preferences.edit {
putString(keyTleUrl, tleUrl)
}
}
private fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
putLong(key, double.toRawBits())
}
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/themeIcon"
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z" />
</vector>
+15 -5
View File
@@ -94,16 +94,26 @@
android:id="@+id/drawer_btn_loc"
style="@style/DrawerHeader.Button"
android:layout_width="0dp"
android:layout_marginTop="4dp"
android:drawableEnd="@drawable/ic_update_loc"
android:text="@string/update_loc"
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_tle"
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_tle_file"
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toBottomOf="@+id/drawer_lon_value" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/drawer_btn_tle"
android:id="@+id/drawer_btn_tle_file"
style="@style/DrawerHeader.Button"
android:layout_width="0dp"
android:drawableEnd="@drawable/ic_file_open"
android:text="@string/update_tle_file"
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_tle_url"
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_loc" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/drawer_btn_tle_url"
style="@style/DrawerHeader.Button"
android:layout_width="0dp"
android:drawableEnd="@drawable/ic_update_tle"
@@ -111,7 +121,7 @@
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_trans"
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_loc" />
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_tle_file" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/drawer_btn_trans"
@@ -122,7 +132,7 @@
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_github"
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_tle" />
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_tle_url" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/drawer_btn_github"
+4 -2
View File
@@ -28,8 +28,10 @@
<string name="update_loc">Update location</string>
<string name="update_loc_success">Location was updated</string>
<string name="update_loc_failure">Check your Location settings</string>
<string name="update_tle">Update TLE file</string>
<string name="update_tle_success">TLE file was updated</string>
<string name="update_tle_file" translatable="false">Update TLE from file</string>
<string name="update_tle_file_success" translatable="false">TLE was updated</string>
<string name="update_tle">Update TLE from URL</string>
<string name="update_tle_success">TLE was updated</string>
<string name="update_trans">Update transceivers</string>
<string name="update_trans_success">Transceivers database was updated</string>
<string name="update_failure">Check your internet connection</string>