Various tweaks and minor refactoring, fixed issue #84

This commit is contained in:
Arty Bishop committed 2022-03-11 12:45:26 +00:00
1 parent ec553bf429
commit abb1bd4718
22 files changed
+321 -87

No files matched your search

@@ -0,0 +1,204 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "f43ab966fb7b0508057c359530582ff5",
"entities": [
{
"tableName": "entries",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`comment` TEXT, `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, PRIMARY KEY(`catnum`))",
"fields": [
{
"fieldPath": "comment",
"columnName": "comment",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "data.name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "data.epoch",
"columnName": "epoch",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.meanmo",
"columnName": "meanmo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.eccn",
"columnName": "eccn",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.incl",
"columnName": "incl",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.raan",
"columnName": "raan",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.argper",
"columnName": "argper",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.meanan",
"columnName": "meanan",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.catnum",
"columnName": "catnum",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "data.bstar",
"columnName": "bstar",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.xincl",
"columnName": "xincl",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.xnodeo",
"columnName": "xnodeo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.omegao",
"columnName": "omegao",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.xmo",
"columnName": "xmo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.xno",
"columnName": "xno",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.orbitalPeriod",
"columnName": "orbitalPeriod",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "data.isDeepSpace",
"columnName": "isDeepSpace",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"catnum"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "radios",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `info` TEXT NOT NULL, `isAlive` INTEGER NOT NULL, `downlink` INTEGER, `uplink` INTEGER, `mode` TEXT, `isInverted` INTEGER NOT NULL, `catnum` INTEGER, `comment` TEXT, PRIMARY KEY(`uuid`))",
"fields": [
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "info",
"columnName": "info",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isAlive",
"columnName": "isAlive",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "downlink",
"columnName": "downlink",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "uplink",
"columnName": "uplink",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "mode",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isInverted",
"columnName": "isInverted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "catnum",
"columnName": "catnum",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "comment",
"columnName": "comment",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"uuid"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f43ab966fb7b0508057c359530582ff5')"
]
}
}
@@ -19,15 +19,26 @@ package com.rtbishop.look4sat.framework.data
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.rtbishop.look4sat.framework.data.dao.EntriesDao
import com.rtbishop.look4sat.framework.data.dao.RadiosDao
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatRadio
@Database(entities = [SatEntry::class, SatRadio::class], version = 1, exportSchema = true)
@Database(entities = [SatEntry::class, SatRadio::class], version = 2, exportSchema = true)
abstract class LocalDatabase : RoomDatabase() {
abstract fun entriesDao(): EntriesDao
abstract fun radiosDao(): RadiosDao
}
val MIGRATION_1_2 = object : Migration(1, 2) {
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("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("ALTER TABLE entries_backup RENAME TO entries")
}
}
@@ -37,7 +37,7 @@ class LocalEntrySource(private val entriesDao: EntriesDao) : ILocalEntrySource {
val selectedSatellites = mutableListOf<Satellite>()
ids.chunked(999).forEach { idsPart ->
val entries = entriesDao.getEntriesWithIds(idsPart)
selectedSatellites.addAll(entries.map { entry -> entry.data.createSat() })
selectedSatellites.addAll(entries.map { entry -> entry.data.getSatellite() })
}
return selectedSatellites
}
@@ -48,7 +48,7 @@ object BaseModule {
@Singleton
fun provideDataRepository(@ApplicationContext context: Context): IDataRepository {
val db = Room.databaseBuilder(context, LocalDatabase::class.java, "Look4SatDb")
.fallbackToDestructiveMigration().build()
.addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
val parser = DataParser(Dispatchers.Default)
val fileSource = FileDataSource(context.contentResolver, Dispatchers.IO)
val entries = LocalEntrySource(db.entriesDao())
@@ -22,6 +22,8 @@ import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.Bundle
import android.os.SystemClock
import android.view.View
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@@ -68,3 +70,15 @@ fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T)
fun <T> Fragment.setNavResult(key: String, value: T) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
}
fun View.clickWithDebounce(debounceTime: Long = 875L, action: () -> Unit) {
this.setOnClickListener(object : View.OnClickListener {
private var lastClickTime: Long = 0
override fun onClick(v: View) {
if (SystemClock.elapsedRealtime() - lastClickTime < debounceTime) return
else action()
lastClickTime = SystemClock.elapsedRealtime()
}
})
}
@@ -31,6 +31,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.presentation.getNavResult
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
@@ -58,21 +59,21 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
}
})
}
entriesBtnBack.setOnClickListener { findNavController().navigateUp() }
entriesBtnBack.clickWithDebounce { findNavController().navigateUp() }
entriesSearch.doOnTextChanged { text, _, _, _ -> viewModel.setQuery(text.toString()) }
entriesBtnModes.setOnClickListener {
entriesBtnModes.clickWithDebounce {
val direction = EntriesFragmentDirections.entriesToModes()
findNavController().navigate(direction)
}
entriesBtnSelect.setOnClickListener { viewModel.selectCurrentItems(true) }
entriesBtnClear.setOnClickListener { viewModel.selectCurrentItems(false) }
entriesFab.setOnClickListener {
setNavResult("selection", viewModel.saveSelection())
findNavController().popBackStack()
}
entriesBtnSelect.clickWithDebounce { viewModel.selectCurrentItems(true) }
entriesBtnClear.clickWithDebounce { viewModel.selectCurrentItems(false) }
}
viewModel.satData.observe(viewLifecycleOwner) { satData ->
handleSatData(satData, entriesAdapter)
binding.entriesFab.clickWithDebounce {
setNavResult("selection", viewModel.saveSelection())
findNavController().popBackStack()
}
}
getNavResult<List<String>>(R.id.nav_entries, "modes") { modes ->
viewModel.saveSelectedModes(modes)
@@ -18,10 +18,8 @@
package com.rtbishop.look4sat.presentation.mapScreen
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Satellite
data class MapData(
val pass: Satellite,
val catNum: Int,
val name: String,
val aosTime: String,
@@ -32,6 +30,7 @@ data class MapData(
val velocity: Double,
val qthLoc: String,
val osmPos: GeoPos,
val period: Double,
val phase: Double,
val eclipsed: Boolean
)
@@ -33,6 +33,7 @@ import com.rtbishop.look4sat.databinding.FragmentMapBinding
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.presentation.clickWithDebounce
import dagger.hilt.android.AndroidEntryPoint
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@@ -98,7 +99,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
overlays.addAll(Array(4) { FolderOverlay() })
}
mapBtnBack.setOnClickListener { findNavController().navigateUp() }
mapBtnBack.clickWithDebounce { findNavController().navigateUp() }
mapBtnPrev.setOnClickListener { viewModel.scrollSelection(true) }
mapBtnNext.setOnClickListener { viewModel.scrollSelection(false) }
}
@@ -199,24 +200,22 @@ class MapFragment : Fragment(R.layout.fragment_map) {
private fun handleMapData(mapData: MapData) {
binding.apply {
mapTimer.text = mapData.aosTime
mapDataPeriod.text = String.format(getString(R.string.map_period, mapData.period))
mapDataPhase.text = String.format(getString(R.string.map_phase), mapData.phase)
mapAzimuth.text = String.format(getString(R.string.map_azimuth), mapData.azimuth)
mapElevation.text = String.format(getString(R.string.map_elevation), mapData.elevation)
mapDataId.text = String.format(getString(R.string.map_sat_id), mapData.catNum)
mapDataQth.text = String.format(getString(R.string.map_qth), mapData.qthLoc)
mapDataAlt.text = String.format(getString(R.string.map_altitude), mapData.altitude)
mapDataDst.text = String.format(getString(R.string.map_distance), mapData.range)
mapDataVel.text = String.format(getString(R.string.map_velocity), mapData.velocity)
mapDataLat.text =
String.format(getString(R.string.map_latitude), mapData.osmPos.lat)
mapDataLon.text =
String.format(getString(R.string.map_longitude), mapData.osmPos.lon)
mapDataPhase.text = String.format(getString(R.string.map_phase), mapData.phase)
mapDataQth.text = String.format(getString(R.string.map_qth), mapData.qthLoc)
mapDataVel.text = String.format(getString(R.string.map_velocity), mapData.velocity)
if (mapData.eclipsed) {
val eclipsed = getString(R.string.map_eclipsed)
mapDataVisibility.text = String.format(getString(R.string.map_visibility), eclipsed)
mapDataVisibility.text = getString(R.string.map_eclipsed)
} else {
val visible = getString(R.string.map_visible)
mapDataVisibility.text = String.format(getString(R.string.map_visibility), visible)
mapDataVisibility.text = getString(R.string.map_visible)
}
}
binding.mapView.invalidate()
@@ -117,7 +117,7 @@ class MapViewModel @Inject constructor(
private suspend fun getSatTrack(satellite: Satellite, pos: GeoPos, date: Date) {
val satTracks = mutableListOf<List<GeoPos>>()
val currentTrack = mutableListOf<GeoPos>()
val endDate = Date(date.time + (satellite.orbitalPeriod * 2.4 * 60000L).toLong())
val endDate = Date(date.time + (satellite.data.orbitalPeriod * 2.4 * 60000L).toLong())
var oldLongitude = 0.0
satelliteManager.getTrack(satellite, pos, date.time, endDate.time).forEach { satPos ->
val osmLat = clipLat(satPos.latitude.toDegrees())
@@ -180,11 +180,12 @@ class MapViewModel @Inject constructor(
val osmLon = clipLon(satPos.longitude.toDegrees())
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = QthConverter.positionToQth(osmPos.lat, osmPos.lon) ?: "-- --"
val velocity = satPos.getOrbitalVelocity()
val phase = satPos.phase.toDegrees()
val visibility = satPos.eclipsed
val satData = MapData(
sat, sat.data.catnum, sat.data.name, aosTime, azimuth, elevation, satPos.distance,
satPos.altitude, satPos.getOrbitalVelocity(), qthLoc, osmPos, phase, visibility
sat.data.catnum, sat.data.name, aosTime, azimuth, elevation, satPos.distance,
satPos.altitude, velocity, qthLoc, osmPos, sat.data.orbitalPeriod, phase, visibility
)
_mapData.postValue(satData)
}
@@ -31,6 +31,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentPassesBinding
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.presentation.getNavResult
import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.AndroidEntryPoint
@@ -60,16 +61,16 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
}
})
}
passesBtnRefresh.setOnClickListener { viewModel.calculatePasses() }
passesBtnMap.setOnClickListener {
passesBtnRefresh.clickWithDebounce { viewModel.calculatePasses() }
passesBtnMap.clickWithDebounce {
val dir = PassesFragmentDirections.globalToMap()
findNavController().navigate(dir)
}
passesBtnFilter.setOnClickListener {
passesBtnFilter.clickWithDebounce {
val dir = PassesFragmentDirections.passesToFilter()
findNavController().navigate(dir)
}
passesBtnSettings.setOnClickListener {
passesBtnSettings.clickWithDebounce {
val dir = PassesFragmentDirections.globalToSettings()
findNavController().navigate(dir)
}
@@ -118,12 +119,12 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
private fun handleEntriesTotal(number: Int) {
binding?.run {
if (number > 0) {
passesFab.setOnClickListener {
passesFab.clickWithDebounce {
val direction = PassesFragmentDirections.globalToEntries()
findNavController().navigate(direction)
}
} else {
passesFab.setOnClickListener {
passesFab.clickWithDebounce {
val errorMessage = getString(R.string.passes_empty_db)
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
}
@@ -139,13 +140,17 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
tickMainTimer(state.data)
if (state.data.isNotEmpty()) { // show new passes list
passesEmpty.visibility = View.INVISIBLE
passesProgress.visibility = View.INVISIBLE
} else { // show no passes message
passesEmpty.visibility = View.VISIBLE
passesProgress.visibility = View.INVISIBLE
}
}
is DataState.Loading -> {
// refreshAnimator?.start()
passesBtnRefresh.isEnabled = false
// passesBtnRefresh.isEnabled = false
passesEmpty.visibility = View.INVISIBLE
passesProgress.visibility = View.VISIBLE
passesTimer.text = 0L.toTimerString()
}
else -> {}
@@ -30,6 +30,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.utility.toDegrees
import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.AndroidEntryPoint
@@ -100,13 +101,13 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
viewModel.orientation.observe(viewLifecycleOwner) { value ->
radarView?.setOrientation(value.first, value.second, value.third)
}
radarBtnBack.setOnClickListener { findNavController().navigateUp() }
radarBtnMap.setOnClickListener {
radarBtnBack.clickWithDebounce { findNavController().navigateUp() }
radarBtnMap.clickWithDebounce {
val direction = RadarFragmentDirections.globalToMap(pass.catNum)
findNavController().navigate(direction)
}
radarBtnNotify.isEnabled = false
radarBtnSettings.setOnClickListener {
radarBtnSettings.clickWithDebounce {
val direction = RadarFragmentDirections.globalToSettings()
findNavController().navigate(direction)
}
@@ -36,6 +36,7 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.presentation.getNavResult
import com.rtbishop.look4sat.utility.isValidIPv4
import com.rtbishop.look4sat.utility.isValidPort
@@ -64,19 +65,19 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentSettingsBinding.bind(view).apply {
settingsBtnBack.setOnClickListener { findNavController().navigateUp() }
settingsBtnBack.clickWithDebounce { findNavController().navigateUp() }
settingsScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, y, _, newY ->
if (y > newY) settingsFab.hide() else settingsFab.show()
})
settingsAbout.aboutVersion.text =
String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME)
settingsBtnGithub.setOnClickListener {
settingsBtnGithub.clickWithDebounce {
gotoUrl("https://github.com/rt-bishop/Look4Sat/")
}
settingsFab.setOnClickListener {
settingsFab.clickWithDebounce {
gotoUrl("https://ko-fi.com/rt_bishop")
}
settingsBtnFdroid.setOnClickListener {
settingsBtnFdroid.clickWithDebounce {
gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
}
}
@@ -96,14 +97,14 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
private fun setupLocationCard() {
binding.run {
setPositionText(viewModel.getStationPosition())
settingsLocation.locationBtnGps.setOnClickListener {
settingsLocation.locationBtnGps.clickWithDebounce {
locationRequest.launch(arrayOf(locationFine, locationCoarse))
}
settingsLocation.locationBtnManual.setOnClickListener {
settingsLocation.locationBtnManual.clickWithDebounce {
val action = SettingsFragmentDirections.globalToPosition()
findNavController().navigate(action)
}
settingsLocation.locationBtnQth.setOnClickListener {
settingsLocation.locationBtnQth.clickWithDebounce {
val action = SettingsFragmentDirections.globalToLocator()
findNavController().navigate(action)
}
@@ -118,12 +119,12 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
private fun setupDataCard() {
binding.run {
settingsData.dataBtnFile.setOnClickListener { contentRequest.launch("*/*") }
settingsData.dataBtnWeb.setOnClickListener {
settingsData.dataBtnWeb.clickWithDebounce {
val action = SettingsFragmentDirections.settingsToSources()
findNavController().navigate(action)
}
settingsData.dataBtnClear.setOnClickListener { viewModel.clearData() }
settingsData.dataBtnFile.clickWithDebounce { contentRequest.launch("*/*") }
settingsData.dataBtnClear.clickWithDebounce { viewModel.clearData() }
viewModel.entriesTotal.observe(viewLifecycleOwner) { number ->
val entriesFormat = getString(R.string.data_entries)
settingsData.dataEntries.text = String.format(entriesFormat, number)
+7 -7
View File
@@ -89,8 +89,8 @@
android:layout_marginTop="4dp"
android:text="@string/map_azimuth"
app:layout_constraintBottom_toTopOf="@+id/map_data_alt"
app:layout_constraintStart_toStartOf="@+id/map_data_visibility"
app:layout_constraintTop_toBottomOf="@+id/map_data_visibility" />
app:layout_constraintStart_toStartOf="@+id/map_data_period"
app:layout_constraintTop_toBottomOf="@+id/map_data_period" />
<TextView
android:id="@+id/map_data_lat"
@@ -142,13 +142,13 @@
app:layout_constraintEnd_toEndOf="@+id/map_data_phase" />
<TextView
android:id="@+id/map_data_visibility"
android:id="@+id/map_data_period"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="6dp"
android:text="@string/map_visibility"
android:text="@string/map_period"
app:layout_constraintBottom_toTopOf="@+id/map_azimuth"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -160,7 +160,7 @@
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="@string/map_phase"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_visibility"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_period"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
@@ -214,7 +214,7 @@
app:layout_constraintTop_toTopOf="@+id/map_coordinator" />
<TextView
android:id="@+id/map_data_id"
android:id="@+id/map_data_visibility"
style="@style/WorldMapText"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -223,7 +223,7 @@
android:ellipsize="end"
android:gravity="center_horizontal"
android:maxLines="1"
android:text="@string/map_sat_id"
android:text="@string/map_visible"
app:layout_constraintBaseline_toBaselineOf="@+id/map_btn_prev"
app:layout_constraintEnd_toStartOf="@+id/map_btn_next"
app:layout_constraintStart_toEndOf="@+id/map_btn_prev" />
+8 -4
View File
@@ -46,6 +46,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/passes_progress"
style="@style/RecyclerProgress" />
<LinearLayout
android:id="@+id/passes_empty"
android:layout_width="match_parent"
@@ -59,10 +63,10 @@
<ImageView
android:id="@+id/passes_empty_img"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp"
android:layout_marginBottom="32dp"
android:contentDescription="@string/passes_error"
android:src="@drawable/ic_list"
app:tint="@color/textDisabled" />
@@ -74,7 +78,7 @@
android:layout_gravity="center_horizontal"
android:gravity="center"
android:text="@string/passes_error"
android:textSize="@dimen/text_size_large" />
android:textSize="@dimen/text_size_mediumLarge" />
</LinearLayout>
+1
View File
@@ -109,6 +109,7 @@
<string name="map_visible">Видимый</string>
<string name="map_eclipsed">В тени</string>
<string name="map_visibility">Видимость: %s</string>
<string name="map_period">Период: %.0fмин</string>
<string name="map_phase">Фаза: %.1f°</string>
<string name="map_altitude">Высота: %.0fкм</string>
<string name="map_distance">Дистанция: %.0fкм</string>
+1
View File
@@ -110,6 +110,7 @@
<string name="map_visible">Visible</string>
<string name="map_eclipsed">Eclipsed</string>
<string name="map_visibility">Visibility: %s</string>
<string name="map_period">Period: %.0f min</string>
<string name="map_phase">Phase: %.1f°</string>
<string name="map_altitude">Altitude: %.0f km</string>
<string name="map_distance">Distance: %.0f km</string>
+2 -2
View File
@@ -102,8 +102,8 @@
</style>
<style name="RecyclerProgress">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">72dp</item>
<item name="android:layout_height">72dp</item>
<item name="android:layout_gravity">center</item>
</style>
@@ -56,9 +56,9 @@ class DataRepository(
override fun updateFromFile(uri: String) {
repositoryScope.launch(exceptionHandler) {
_updateState.value = DataState.Loading
fileSource.getDataStream(uri)?.let { fileStream ->
fileSource.getDataStream(uri)?.let { stream ->
delay(updateStateDelay)
entrySource.insertEntries(importSatellites(fileStream))
entrySource.insertEntries(importSatellites(stream))
}
_updateState.value = DataState.Success(0L)
}
@@ -67,23 +67,20 @@ class DataRepository(
override fun updateFromWeb(urls: List<String>) {
_updateState.value = DataState.Loading
repositoryScope.launch(exceptionHandler) {
val jobsMap = mutableMapOf<String, Deferred<InputStream?>>()
val streamsMap = mutableMapOf<String, InputStream?>()
val streams = mutableListOf<InputStream>()
val entries = mutableListOf<SatEntry>()
urls.forEach { jobsMap[it] = async { remoteSource.getDataStream(it) } }
jobsMap.forEach { job -> streamsMap[job.key] = job.value.await() }
streamsMap.forEach { stream ->
stream.value?.let { inputStream ->
val jobs = urls.associateWith { url -> async { remoteSource.getDataStream(url) } }
jobs.mapValues { job -> job.value.await() }.forEach { result ->
result.value?.let { stream ->
when {
stream.key.contains("=csv", true) -> {
val tles = dataParser.parseCSVStream(inputStream)
entries.addAll(tles.map { tle -> SatEntry(tle) })
result.key.contains("=csv", true) -> {
val orbitalData = dataParser.parseCSVStream(stream)
entries.addAll(orbitalData.map { data -> SatEntry(data) })
}
stream.key.contains(".zip", true) -> {
streams.add(ZipInputStream(inputStream).apply { nextEntry })
result.key.contains(".zip", true) -> {
streams.add(ZipInputStream(stream).apply { nextEntry })
}
else -> streams.add(inputStream)
else -> streams.add(stream)
}
}
}
@@ -113,6 +110,6 @@ class DataRepository(
}
private suspend fun importSatellites(stream: InputStream): List<SatEntry> {
return dataParser.parseTLEStream(stream).map { tle -> SatEntry(tle) }
return dataParser.parseTLEStream(stream).map { data -> SatEntry(data) }
}
}
@@ -33,13 +33,9 @@ data class OrbitalData(
val omegao: Double = argper * DEG2RAD,
val xmo: Double = meanan * DEG2RAD,
val xno: Double = meanmo * TWO_PI / MIN_PER_DAY,
val isDeepspace: Boolean = meanmo < 6.4
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
) {
fun createSat(): Satellite {
return when {
this.isDeepspace -> DeepSpaceSat(this)
else -> NearEarthSat(this)
}
}
fun getSatellite(): Satellite = if (isDeepSpace) DeepSpaceSat(this) else NearEarthSat(this)
}
@@ -31,5 +31,5 @@ data class SatPass(
) {
val catNum: Int = satellite.data.catnum
val name: String = satellite.data.name
val isDeepSpace: Boolean = satellite.data.isDeepspace
val isDeepSpace: Boolean = satellite.data.isDeepSpace
}
@@ -47,7 +47,6 @@ abstract class Satellite(val data: OrbitalData) {
private var gsPosTheta = 0.0
private var julUTC = 0.0
private var perigee = 0.0
val orbitalPeriod = 24 * 60 / data.meanmo
var qoms24 = 0.0
var s4 = 0.0
@@ -108,7 +107,7 @@ abstract class Satellite(val data: OrbitalData) {
}
private fun calculateSDP4orSGP4(tsince: Double) {
if (data.isDeepspace) (this as DeepSpaceSat).calculateSDP4(tsince)
if (data.isDeepSpace) (this as DeepSpaceSat).calculateSDP4(tsince)
else (this as NearEarthSat).calculateSGP4(tsince)
}
@@ -118,13 +118,13 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
private fun Satellite.getPasses(pos: GeoPos, time: Long, hours: Int): List<SatPass> {
val passes = mutableListOf<SatPass>()
val endDate = time + hours * 60L * 60L * 1000L
val quarterOrbitMin = (this.orbitalPeriod / 4.0).toInt()
val quarterOrbitMin = (this.data.orbitalPeriod / 4.0).toInt()
var startDate = time
var shouldRewind = true
var lastAosDate: Long
var count = 0
if (this.willBeSeen(pos)) {
if (this.data.isDeepspace) {
if (this.data.isDeepSpace) {
passes.add(getGeoPass(this, pos, time))
} else {
do {
@@ -160,7 +160,7 @@ class SatelliteManager(private val defaultDispatcher: CoroutineDispatcher) : ISa
}
private fun getLeoPass(sat: Satellite, pos: GeoPos, time: Long, rewind: Boolean): SatPass {
val quarterOrbitMin = (sat.orbitalPeriod / 4.0).toInt()
val quarterOrbitMin = (sat.data.orbitalPeriod / 4.0).toInt()
var calendarTimeMillis = time
var elevation: Double
var maxElevation = 0.0