Destructively migrated to the new database

This commit is contained in:
Arty Bishop committed 2022-02-19 12:10:30 +00:00
1 parent 92eec290b1
commit 64b5010a44
53 files changed
+381 -901

No files matched your search

+1 -1
View File
@@ -23,4 +23,4 @@
</activity>
</application>
</manifest>
</manifest>
@@ -19,29 +19,29 @@ package com.rtbishop.look4sat.framework
import com.rtbishop.look4sat.domain.model.SatEntry as DomainEntry
import com.rtbishop.look4sat.domain.model.SatItem as DomainItem
import com.rtbishop.look4sat.domain.model.Transmitter as DomainTransmitter
import com.rtbishop.look4sat.domain.model.SatRadio as DomainRadio
import com.rtbishop.look4sat.framework.model.SatEntry as FrameworkEntry
import com.rtbishop.look4sat.framework.model.SatItem as FrameworkItem
import com.rtbishop.look4sat.framework.model.Transmitter as FrameworkTransmitter
import com.rtbishop.look4sat.framework.model.SatRadio as FrameworkRadio
fun DomainEntry.toFramework() = FrameworkEntry(this.tle, this.isSelected)
fun DomainEntry.toFramework() = FrameworkEntry(this.data, this.comment)
fun DomainTransmitter.toFramework() = FrameworkTransmitter(
this.uuid, this.info, this.isAlive, this.downlink,
this.uplink, this.mode, this.isInverted, this.catnum
fun DomainRadio.toFramework() = FrameworkRadio(
this.uuid, this.info, this.isAlive, this.downlink, this.uplink,
this.mode, this.isInverted, this.catnum, this.comment
)
fun FrameworkItem.toDomain() = DomainItem(this.catnum, this.name, this.isSelected, this.modes)
fun FrameworkItem.toDomain() = DomainItem(this.catnum, this.name, this.modes, false)
fun FrameworkTransmitter.toDomain() = DomainTransmitter(
this.uuid, this.info, this.isAlive, this.downlink,
this.uplink, this.mode, this.isInverted, this.catnum
fun FrameworkRadio.toDomain() = DomainRadio(
this.uuid, this.info, this.isAlive, this.downlink, this.uplink,
this.mode, this.isInverted, this.catnum, this.comment
)
fun List<DomainEntry>.toFrameworkEntries() = this.map { it.toFramework() }
fun List<DomainTransmitter>.toFramework() = this.map { it.toFramework() }
fun List<DomainRadio>.toFrameworkRadios() = this.map { it.toFramework() }
fun List<FrameworkItem>.toDomainItems() = this.map { it.toDomain() }
fun List<FrameworkTransmitter>.toDomain() = this.map { it.toDomain() }
fun List<FrameworkRadio>.toDomainRadios() = this.map { it.toDomain() }
@@ -61,12 +61,12 @@ class SettingsHandler @Inject constructor(private val prefs: SharedPreferences)
}
}
override fun saveSatelliteSelection(catnums: List<Int>) {
override fun saveEntriesSelection(catnums: List<Int>) {
val stringList = catnums.map { catnum -> catnum.toString() }
prefs.edit { putStringSet(keySelection, stringList.toSet()) }
}
override fun loadSatelliteSelection(): List<Int> {
override fun loadEntriesSelection(): List<Int> {
val catnums = prefs.getStringSet(keySelection, emptySet())?.map { catnum -> catnum.toInt() }
return catnums?.sorted() ?: emptyList()
}
@@ -20,52 +20,77 @@ package com.rtbishop.look4sat.framework.local
import android.content.ContentResolver
import android.net.Uri
import com.rtbishop.look4sat.data.ILocalSource
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.domain.model.SatEntry
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.domain.model.SatRadio
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.framework.toDomain
import com.rtbishop.look4sat.framework.toDomainItems
import com.rtbishop.look4sat.framework.toFramework
import com.rtbishop.look4sat.framework.toDomainRadios
import com.rtbishop.look4sat.framework.toFrameworkEntries
import com.rtbishop.look4sat.framework.toFrameworkRadios
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import java.io.InputStream
class LocalSource(
private val entriesDao: SatEntriesDao,
private val radiosDao: SatRadiosDao,
private val settings: ISettingsHandler,
private val resolver: ContentResolver,
private val ioDispatcher: CoroutineDispatcher,
private val entriesDao: EntriesDao,
private val transmittersDao: TransmittersDao,
private val ioDispatcher: CoroutineDispatcher
) : ILocalSource {
override suspend fun getAllSatellites(): List<SatItem> {
return entriesDao.getAllSatellites().toDomainItems()
override suspend fun getEntriesWithModes(): List<SatItem> {
val selectedCatnums = getEntriesSelection()
val entriesWithModes = entriesDao.getEntriesWithModes().toDomainItems()
entriesWithModes.forEach { entry -> entry.isSelected = entry.catnum in selectedCatnums }
return entriesWithModes
}
override suspend fun getSelectedSatellites(catnums: List<Int>): List<Satellite> {
return entriesDao.getSelectedSatellites(catnums).map { entry -> entry.tle.createSat() }
override suspend fun getSelectedEntries(): List<Satellite> {
val selectedSatellites = mutableListOf<Satellite>()
getEntriesSelection().chunked(999).forEach { catnums ->
val entries = entriesDao.getSelectedEntries(catnums)
selectedSatellites.addAll(entries.map { entry -> entry.data.createSat() })
}
return selectedSatellites
}
override suspend fun getTransmitters(catnum: Int): List<Transmitter> {
return transmittersDao.getTransmitters(catnum).toDomain()
override suspend fun getRadios(catnum: Int): List<SatRadio> {
return radiosDao.getRadios(catnum).toDomainRadios()
}
@Suppress("BlockingMethodInNonBlockingContext")
override suspend fun getFileStream(uri: String): InputStream? {
return withContext(ioDispatcher) { resolver.openInputStream(Uri.parse(uri)) }
}
override suspend fun updateEntries(entries: List<SatEntry>) {
override suspend fun insertEntries(entries: List<SatEntry>) {
entriesDao.insertEntries(entries.toFrameworkEntries())
}
override suspend fun updateTransmitters(transmitters: List<Transmitter>) {
transmittersDao.updateTransmitters(transmitters.toFramework())
override suspend fun insertRadios(radios: List<SatRadio>) {
radiosDao.insertRadios(radios.toFrameworkRadios())
}
override suspend fun clearAllData() {
entriesDao.deleteEntries()
transmittersDao.deleteTransmitters()
radiosDao.deleteRadios()
}
override suspend fun getDataSources(): List<String> {
return withContext(ioDispatcher) { settings.loadDataSources() }
}
override suspend fun setDataSources(sources: List<String>) {
withContext(ioDispatcher) { settings.saveDataSources(sources) }
}
override suspend fun getEntriesSelection(): List<Int> {
return withContext(ioDispatcher) { settings.loadEntriesSelection() }
}
override suspend fun setEntriesSelection(catnums: List<Int>) {
withContext(ioDispatcher) { settings.saveEntriesSelection(catnums) }
}
}
@@ -0,0 +1,31 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.framework.local
import androidx.room.Database
import androidx.room.RoomDatabase
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatRadio
@Database(entities = [SatEntry::class, SatRadio::class], version = 1, exportSchema = true)
abstract class Look4SatDb : RoomDatabase() {
abstract fun entriesDao(): SatEntriesDao
abstract fun radiosDao(): SatRadiosDao
}
@@ -22,23 +22,15 @@ import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem
@Dao
interface EntriesDao {
interface SatEntriesDao {
@Transaction
@Query("SELECT catnum, name, isSelected FROM entries ORDER BY name ASC")
suspend fun getAllSatellites(): List<SatItem>
@Query("SELECT catnum, name FROM entries ORDER BY name ASC")
suspend fun getEntriesWithModes(): List<SatItem>
@Transaction
suspend fun getSelectedSatellites(catnums: List<Int>): List<SatEntry> {
val selectedSatellites = mutableListOf<SatEntry>()
catnums.chunked(999).forEach { chunkedList ->
selectedSatellites.addAll(getSelectedSatellitesChunked(chunkedList))
}
return selectedSatellites
}
@Query("SELECT * FROM entries WHERE catnum IN (:catnums)")
suspend fun getSelectedSatellitesChunked(catnums: List<Int>): List<SatEntry>
suspend fun getSelectedEntries(catnums: List<Int>): List<SatEntry>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertEntries(entries: List<SatEntry>)
@@ -17,24 +17,21 @@
*/
package com.rtbishop.look4sat.framework.local
import androidx.room.*
import com.rtbishop.look4sat.framework.model.Transmitter
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.rtbishop.look4sat.framework.model.SatRadio
@Dao
interface TransmittersDao {
interface SatRadiosDao {
@Query("SELECT * FROM transmitters WHERE catnum = :catnum AND isAlive = 1")
suspend fun getTransmitters(catnum: Int): List<Transmitter>
@Query("SELECT * FROM radios WHERE catnum = :catnum AND isAlive = 1")
suspend fun getRadios(catnum: Int): List<SatRadio>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTransmitters(transmitters: List<Transmitter>)
suspend fun insertRadios(radios: List<SatRadio>)
@Transaction
suspend fun updateTransmitters(transmitters: List<Transmitter>) {
deleteTransmitters()
insertTransmitters(transmitters)
}
@Query("DELETE FROM transmitters")
suspend fun deleteTransmitters()
@Query("DELETE FROM radios")
suspend fun deleteRadios()
}
@@ -1,67 +0,0 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.framework.local
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.Transmitter
@Database(entities = [SatEntry::class, Transmitter::class], version = 5, exportSchema = true)
abstract class SatelliteDb : RoomDatabase() {
abstract fun entriesDao(): EntriesDao
abstract fun transmittersDao(): TransmittersDao
}
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE trans_backup (uuid TEXT NOT NULL, info TEXT NOT NULL, isAlive INTEGER NOT NULL, downlink INTEGER, uplink INTEGER, mode TEXT, isInverted INTEGER NOT NULL, catNum INTEGER, PRIMARY KEY(uuid))")
database.execSQL("INSERT INTO trans_backup (uuid, info, isAlive, downlink, uplink, mode, isInverted, catNum) SELECT uuid, info, isAlive, downlink, uplink, mode, isInverted, catNum FROM transmitters")
database.execSQL("DROP TABLE transmitters")
database.execSQL("ALTER TABLE trans_backup RENAME TO transmitters")
}
}
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE sources (sourceUrl TEXT NOT NULL, PRIMARY KEY(sourceUrl))")
}
}
val MIGRATION_3_4 = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE entries_backup (isSelected INTEGER NOT NULL, 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, isDeepspace INTEGER NOT NULL, PRIMARY KEY(catnum))")
database.execSQL("INSERT INTO entries_backup (isSelected, name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar, xincl, xnodeo, omegao, xmo, xno, isDeepspace) SELECT isSelected, 'name', 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, catNum, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0 FROM entries")
database.execSQL("DROP TABLE entries")
database.execSQL("ALTER TABLE entries_backup RENAME TO entries")
database.execSQL("CREATE TABLE trans_backup (uuid TEXT NOT NULL, info TEXT NOT NULL, isAlive INTEGER NOT NULL, downlink INTEGER, uplink INTEGER, mode TEXT, isInverted INTEGER NOT NULL, catnum INTEGER, PRIMARY KEY(uuid))")
database.execSQL("INSERT INTO trans_backup (uuid, info, isAlive, downlink, uplink, mode, isInverted, catnum) SELECT uuid, info, isAlive, downlink, uplink, mode, isInverted, catNum FROM transmitters")
database.execSQL("DROP TABLE transmitters")
database.execSQL("ALTER TABLE trans_backup RENAME TO transmitters")
}
}
val MIGRATION_4_5 = object : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE sources")
}
}
@@ -17,8 +17,4 @@
*/
package com.rtbishop.look4sat.framework.model
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "sources")
data class Source(@PrimaryKey var sourceUrl: String = String())
data class DataSource(var url: String = String())
@@ -19,11 +19,7 @@ package com.rtbishop.look4sat.framework.model
import androidx.room.Embedded
import androidx.room.Entity
import com.rtbishop.look4sat.domain.predict.TLE
import com.rtbishop.look4sat.domain.predict.OrbitalData
@Entity(tableName = "entries", primaryKeys = ["catnum"])
data class SatEntry(
@Embedded
val tle: TLE,
var isSelected: Boolean = false
)
data class SatEntry(@Embedded val data: OrbitalData, var comment: String? = null)
@@ -22,10 +22,9 @@ import androidx.room.Relation
data class SatItem(
val catnum: Int,
val name: String,
var isSelected: Boolean = false,
@Relation(
parentColumn = "catnum",
entity = Transmitter::class,
entity = SatRadio::class,
entityColumn = "catnum",
projection = ["mode"]
)
@@ -20,8 +20,8 @@ package com.rtbishop.look4sat.framework.model
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "transmitters")
data class Transmitter(
@Entity(tableName = "radios")
data class SatRadio(
@PrimaryKey val uuid: String,
val info: String,
val isAlive: Boolean,
@@ -29,5 +29,6 @@ data class Transmitter(
var uplink: Long?,
val mode: String?,
val isInverted: Boolean,
val catnum: Int?
val catnum: Int?,
var comment: String? = null
)
@@ -8,8 +8,7 @@ import java.net.URL
class RemoteSource(private val ioDispatcher: CoroutineDispatcher) : IRemoteSource {
@Suppress("BlockingMethodInNonBlockingContext")
override suspend fun fetchFileStream(url: String): InputStream? {
override suspend fun getFileStream(url: String): InputStream? {
return withContext(ioDispatcher) { URL(url).openStream() }
}
}
@@ -29,7 +29,8 @@ import com.rtbishop.look4sat.domain.ILocationHandler
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.framework.LocationHandler
import com.rtbishop.look4sat.framework.SettingsHandler
import com.rtbishop.look4sat.framework.local.*
import com.rtbishop.look4sat.framework.local.LocalSource
import com.rtbishop.look4sat.framework.local.Look4SatDb
import com.rtbishop.look4sat.framework.remote.RemoteSource
import dagger.Module
import dagger.Provides
@@ -53,15 +54,14 @@ object CoreModule {
@IoDispatcher ioDispatcher: CoroutineDispatcher,
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
): IDataRepository {
val db = Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5)
val db = Room.databaseBuilder(context, Look4SatDb::class.java, "Look4SatDb")
.fallbackToDestructiveMigration().build()
val dataParser = DataParser(defaultDispatcher)
val resolver = context.contentResolver
val localSource = LocalSource(resolver, ioDispatcher, db.entriesDao(), db.transmittersDao())
val remoteSource = RemoteSource(ioDispatcher)
val local = LocalSource(db.entriesDao(), db.radiosDao(), settings, resolver, ioDispatcher)
val remote = RemoteSource(ioDispatcher)
val repositoryScope = CoroutineScope(SupervisorJob())
return DataRepository(dataParser, settings, localSource, remoteSource, repositoryScope)
return DataRepository(dataParser, local, remote, repositoryScope)
}
@Provides
@@ -21,4 +21,4 @@ import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class Look4SatApplication : Application()
class Look4SatApplication : Application()
@@ -22,7 +22,7 @@ class MainViewModel @Inject constructor(
timeRef: Long = System.currentTimeMillis()
) {
viewModelScope.launch {
val satellites = dataRepository.getSelectedSatellites()
val satellites = dataRepository.getSelectedEntries()
val stationPos = preferences.loadStationPosition()
predictor.forceCalculation(satellites, stationPos, timeRef, hoursAhead, minElevation)
}
@@ -34,7 +34,7 @@ class EntriesViewModel @Inject constructor(
private val transModes = MutableLiveData(preferences.loadModesSelection())
private val currentQuery = MutableLiveData(String())
private val itemsFromRepo = liveData { emit(repository.getAllSatellites()) } as MutableLiveData
private val itemsFromRepo = liveData { emit(repository.getEntriesWithModes()) } as MutableLiveData
private val itemsWithModes = transModes.switchMap { modes ->
itemsFromRepo.map { items -> filterByModes(items, modes) }
}
@@ -68,7 +68,7 @@ class EntriesViewModel @Inject constructor(
fun saveSelection() {
itemsFromRepo.value?.let { itemsAll ->
val filteredItems = itemsAll.filter { item -> item.isSelected }
repository.updatesSelection(filteredItems.map { item -> item.catnum })
repository.setEntriesSelection(filteredItems.map { item -> item.catnum })
}
}
@@ -130,7 +130,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
textLabelBackgroundColor = Color.TRANSPARENT
textLabelForegroundColor =
ContextCompat.getColor(requireContext(), R.color.themeAccent)
setTextIcon(it.key.params.name)
setTextIcon(it.key.data.name)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
try {
position = GeoPoint(it.value.latitude, it.value.longitude)
@@ -76,13 +76,13 @@ class MapViewModel @Inject constructor(
fun selectDefaultSatellite(catnum: Int) {
viewModelScope.launch {
dataRepository.getSelectedSatellites().also { satellites ->
dataRepository.getSelectedEntries().also { satellites ->
if (satellites.isNotEmpty()) {
allSatList = satellites
if (catnum == -1) {
selectSatellite(satellites.first())
} else {
satellites.find { it.params.catnum == catnum }?.let { selectSatellite(it) }
satellites.find { it.data.catnum == catnum }?.let { selectSatellite(it) }
}
}
}
@@ -164,7 +164,7 @@ class MapViewModel @Inject constructor(
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = QthConverter.positionToQth(osmPos.latitude, osmPos.longitude) ?: "-- --"
val satData = MapData(
satellite, satellite.params.catnum, satellite.params.name, satPos.range,
satellite, satellite.data.catnum, satellite.data.name, satPos.range,
satPos.altitude, satPos.getOrbitalVelocity(), qthLoc, osmPos
)
_satData.postValue(satData)
@@ -65,7 +65,7 @@ class PassesViewModel @Inject constructor(
viewModelScope.launch {
_passes.postValue(DataState.Loading)
passesProcessing?.cancelAndJoin()
val satellites = repository.getSelectedSatellites()
val satellites = repository.getSelectedEntries()
val stationPos = settings.loadStationPosition()
predictor.forceCalculation(satellites, stationPos, timeRef, hoursAhead, minElevation)
}
@@ -53,7 +53,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
private fun setupViews() {
val context = requireContext()
val adapter = TransmittersAdapter()
val adapter = RadiosAdapter()
val layoutManager = LinearLayoutManager(context)
val itemDecoration = DividerItemDecoration(context, layoutManager.orientation)
binding.run {
@@ -68,7 +68,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
}
}
private fun setupObservers(transmittersAdapter: TransmittersAdapter) {
private fun setupObservers(radiosAdapter: RadiosAdapter) {
viewModel.getPass(args.catNum, args.aosTime).observe(viewLifecycleOwner) { pass ->
radarView = RadarView(requireContext()).apply {
setShowAim(preferences.getUseCompass())
@@ -82,7 +82,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
}
viewModel.transmitters.observe(viewLifecycleOwner) { list ->
if (list.isNotEmpty()) {
transmittersAdapter.submitList(list)
radiosAdapter.submitList(list)
binding.radarRecyclerMsg.text = getString(R.string.trans_data)
} else {
binding.radarRecyclerMsg.text = getString(R.string.trans_no_data)
@@ -22,7 +22,7 @@ import androidx.lifecycle.*
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.domain.model.SatRadio
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.Predictor
import com.rtbishop.look4sat.domain.predict.SatPass
@@ -47,10 +47,10 @@ class RadarViewModel @Inject constructor(
private val stationPos = preferences.loadStationPosition()
private val _passData = MutableLiveData<RadarData>()
private val _transmitters = MutableLiveData<List<Transmitter>>()
private val _transmitters = MutableLiveData<List<SatRadio>>()
private val _orientation = MutableLiveData<Triple<Float, Float, Float>>()
val radarData: LiveData<RadarData> = _passData
val transmitters: LiveData<List<Transmitter>> = _transmitters
val transmitters: LiveData<List<SatRadio>> = _transmitters
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
fun getPass(catNum: Int, aosTime: Long) = liveData {
@@ -107,7 +107,7 @@ class RadarViewModel @Inject constructor(
private fun processTransmitters(pass: SatPass) {
viewModelScope.launch {
val transmitters = dataRepository.getTransmitters(pass.catNum)
val transmitters = dataRepository.getRadios(pass.catNum)
while (isActive) {
val time = System.currentTimeMillis()
val list = predictor.processRadios(pass.satellite, stationPos, transmitters, time)
@@ -24,24 +24,24 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.ItemTransBinding
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.domain.model.SatRadio
import java.util.*
class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder>() {
class RadiosAdapter : RecyclerView.Adapter<RadiosAdapter.TransHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<Transmitter>() {
override fun areItemsTheSame(oldItem: Transmitter, newItem: Transmitter): Boolean {
private val diffCallback = object : DiffUtil.ItemCallback<SatRadio>() {
override fun areItemsTheSame(oldItem: SatRadio, newItem: SatRadio): Boolean {
return oldItem.uuid == newItem.uuid
}
override fun areContentsTheSame(oldItem: Transmitter, newItem: Transmitter): Boolean {
override fun areContentsTheSame(oldItem: SatRadio, newItem: SatRadio): Boolean {
return oldItem.downlink == newItem.downlink
}
}
private val differ = AsyncListDiffer(this, diffCallback)
fun submitList(transmitters: List<Transmitter>) {
differ.submitList(transmitters)
fun submitList(radios: List<SatRadio>) {
differ.submitList(radios)
}
override fun getItemCount() = differ.currentList.size
@@ -65,10 +65,10 @@ class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder
private val formatLinkNull = itemView.context.getString(R.string.trans_no_link)
private val isInverted = itemView.context.getString(R.string.trans_inverted)
fun bind(transmitter: Transmitter) {
binding.transDesc.text = transmitter.info
fun bind(radio: SatRadio) {
binding.transDesc.text = radio.info
transmitter.downlink.let { downlink ->
radio.downlink.let { downlink ->
if (downlink != null) {
val downlinkFreq = downlink / divider
binding.transDownlink.text =
@@ -78,7 +78,7 @@ class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder
}
}
transmitter.uplink.let { uplink ->
radio.uplink.let { uplink ->
if (uplink != null) {
val uplinkFreq = uplink / divider
binding.transUplink.text = String.format(Locale.ENGLISH, formatLink, uplinkFreq)
@@ -87,13 +87,13 @@ class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder
}
}
if (transmitter.mode != null) {
binding.transMode.text = String.format(mode, transmitter.mode)
if (radio.mode != null) {
binding.transMode.text = String.format(mode, radio.mode)
} else {
binding.transMode.text = String.format(mode, strNo)
}
if (transmitter.isInverted) {
if (radio.isInverted) {
binding.transInverted.text = String.format(isInverted, strYes)
} else {
binding.transInverted.text = String.format(isInverted, strNo)
@@ -15,29 +15,29 @@
* 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.presentation.sourcesScreen
package com.rtbishop.look4sat.presentation.settingsScreen
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.databinding.ItemSourceBinding
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.framework.model.DataSource
class SourcesAdapter(private val sources: MutableList<Source> = mutableListOf()) :
class SourcesAdapter(private val sources: MutableList<DataSource> = mutableListOf()) :
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
fun getSources(): List<Source> {
return sources.filter { it.sourceUrl.contains("https://") }
fun getSources(): List<DataSource> {
return sources.filter { source -> source.url.contains("https://") }
}
fun setSources(list: List<Source>) {
fun setSources(list: List<DataSource>) {
sources.clear()
sources.addAll(list)
}
fun addSource() {
sources.add(Source())
sources.add(DataSource())
notifyItemInserted(itemCount - 1)
}
@@ -58,9 +58,9 @@ class SourcesAdapter(private val sources: MutableList<Source> = mutableListOf())
inner class TleSourceHolder(private val binding: ItemSourceBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(source: Source) {
binding.sourceUrl.setText(source.sourceUrl)
binding.sourceUrl.doOnTextChanged { txt, _, _, _ -> source.sourceUrl = txt.toString() }
fun bind(source: DataSource) {
binding.sourceUrl.setText(source.url)
binding.sourceUrl.doOnTextChanged { txt, _, _, _ -> source.url = txt.toString() }
binding.sourceBtn.setOnClickListener {
sources.remove(source)
notifyItemRemoved(adapterPosition)
@@ -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.presentation.sourcesScreen
package com.rtbishop.look4sat.presentation.settingsScreen
import android.os.Bundle
import android.view.LayoutInflater
@@ -23,11 +23,11 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.ISettingsHandler
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.framework.model.DataSource
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -36,35 +36,37 @@ import javax.inject.Inject
class SourcesDialog : AppCompatDialogFragment() {
@Inject
lateinit var settings: ISettingsHandler
lateinit var repository: IDataRepository
private lateinit var binding: DialogSourcesBinding
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_sources, group, false)
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View {
binding = DialogSourcesBinding.inflate(inflater, group, false)
return binding.root
}
override fun onViewCreated(view: View, state: Bundle?) {
super.onViewCreated(view, state)
val sources = settings.loadDataSources()
val adapter = SourcesAdapter().apply { setSources(sources.map { Source(it) }) }
val layoutManager = LinearLayoutManager(requireContext())
DialogSourcesBinding.bind(view).apply {
dialog?.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
sourcesRecycler.apply {
setHasFixedSize(true)
this.adapter = adapter
this.layoutManager = layoutManager
dialog?.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
lifecycleScope.launchWhenResumed {
val adapter = SourcesAdapter()
val layoutManager = LinearLayoutManager(requireContext())
adapter.setSources(repository.getDataSources().map { url -> DataSource(url) })
binding.run {
sourcesRecycler.apply {
setHasFixedSize(true)
this.adapter = adapter
this.layoutManager = layoutManager
}
sourcesBtnAdd.setOnClickListener { adapter.addSource() }
sourcesBtnNeg.setOnClickListener { dismiss() }
sourcesBtnPos.setOnClickListener {
setNavResult("sources", adapter.getSources().map { source -> source.url })
dismiss()
}
}
sourcesBtnAdd.setOnClickListener {
adapter.addSource()
}
sourcesBtnPos.setOnClickListener {
setNavResult("sources", adapter.getSources().map { it.sourceUrl })
dismiss()
}
sourcesBtnNeg.setOnClickListener { dismiss() }
}
}
}
@@ -52,7 +52,7 @@
</fragment>
<dialog
android:id="@+id/nav_sources"
android:name="com.rtbishop.look4sat.presentation.sourcesScreen.SourcesDialog"
android:name="com.rtbishop.look4sat.presentation.settingsScreen.SourcesDialog"
tools:layout="@layout/dialog_sources" />
<action
android:id="@+id/action_global_entriesFragment"