Added database migration, removed moshi and Converters.kt

pull/87/head
Arty Bishop 2021-10-16 16:41:42 +01:00
rodzic 9baaf38a49
commit 253321f3c2
39 zmienionych plików z 400 dodań i 237 usunięć

Wyświetl plik

@ -20,6 +20,8 @@ android {
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
arg("room.incremental", "true")
arg("room.expandProjection", "true")
}
}
}
@ -44,6 +46,13 @@ android {
buildFeatures {
viewBinding true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "$jvm_version"
}
}
dependencies {

Wyświetl plik

@ -0,0 +1,212 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "0f08defa24a78647801005e9277faac7",
"entities": [
{
"tableName": "entries",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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`))",
"fields": [
{
"fieldPath": "isSelected",
"columnName": "isSelected",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tle.name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tle.epoch",
"columnName": "epoch",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.meanmo",
"columnName": "meanmo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.eccn",
"columnName": "eccn",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.incl",
"columnName": "incl",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.raan",
"columnName": "raan",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.argper",
"columnName": "argper",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.meanan",
"columnName": "meanan",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.catnum",
"columnName": "catnum",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tle.bstar",
"columnName": "bstar",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.xincl",
"columnName": "xincl",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.xnodeo",
"columnName": "xnodeo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.omegao",
"columnName": "omegao",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.xmo",
"columnName": "xmo",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.xno",
"columnName": "xno",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "tle.isDeepspace",
"columnName": "isDeepspace",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"catnum"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "transmitters",
"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, 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
}
],
"primaryKey": {
"columnNames": [
"uuid"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sourceUrl` TEXT NOT NULL, PRIMARY KEY(`sourceUrl`))",
"fields": [
{
"fieldPath": "sourceUrl",
"columnName": "sourceUrl",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"sourceUrl"
],
"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, '0f08defa24a78647801005e9277faac7')"
]
}
}

Wyświetl plik

@ -29,7 +29,7 @@ object DataMapper {
// Presentation to Domain
fun satEntryToDomainEntry(entry: SatEntry): DomainEntry {
return DomainEntry(entry.tle, entry.catNum, entry.name, entry.isSelected)
return DomainEntry(entry.tle, entry.isSelected)
}
fun satEntriesToDomainEntries(entries: List<SatEntry>): List<DomainEntry> {
@ -37,7 +37,7 @@ object DataMapper {
}
fun satItemToDomainItem(item: SatItem): DomainItem {
return DomainItem(item.catNum, item.name, item.isSelected, item.modes)
return DomainItem(item.catnum, item.name, item.isSelected, item.modes)
}
fun satItemsToDomainItems(items: List<SatItem>): List<DomainItem> {
@ -47,7 +47,7 @@ object DataMapper {
fun satTransToDomainTrans(transmitter: Transmitter): DomainTrans {
return DomainTrans(
transmitter.uuid, transmitter.info, transmitter.isAlive, transmitter.downlink,
transmitter.uplink, transmitter.mode, transmitter.isInverted, transmitter.catNum
transmitter.uplink, transmitter.mode, transmitter.isInverted, transmitter.catnum
)
}
@ -58,7 +58,7 @@ object DataMapper {
// Domain to Presentation
fun domainEntryToSatEntry(entry: DomainEntry): SatEntry {
return SatEntry(entry.tle, entry.catNum, entry.name, entry.isSelected)
return SatEntry(entry.tle, entry.isSelected)
}
fun domainEntriesToSatEntries(entries: List<DomainEntry>): List<SatEntry> {
@ -66,7 +66,7 @@ object DataMapper {
}
fun domainItemToSatItem(item: DomainItem): SatItem {
return SatItem(item.catNum, item.name, item.isSelected, item.modes)
return SatItem(item.catnum, item.name, item.isSelected, item.modes)
}
fun domainItemsToSatItems(items: List<DomainItem>): List<SatItem> {
@ -76,7 +76,7 @@ object DataMapper {
fun domainTransToSatTrans(transmitter: DomainTrans): Transmitter {
return Transmitter(
transmitter.uuid, transmitter.info, transmitter.isAlive, transmitter.downlink,
transmitter.uplink, transmitter.mode, transmitter.isInverted, transmitter.catNum
transmitter.uplink, transmitter.mode, transmitter.isInverted, transmitter.catnum
)
}

Wyświetl plik

@ -12,7 +12,7 @@ import androidx.core.content.ContextCompat
import com.rtbishop.look4sat.domain.LocationProvider
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.utility.round
import com.rtbishop.look4sat.presentation.round
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow

Wyświetl plik

@ -23,7 +23,7 @@ import android.location.LocationManager
import androidx.core.content.edit
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.utility.round
import com.rtbishop.look4sat.presentation.round
import javax.inject.Inject
import javax.inject.Singleton

Wyświetl plik

@ -1,51 +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.TypeConverter
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.domain.predict.TLE
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
object Converters {
private lateinit var paramsAdapter: JsonAdapter<TLE>
fun initialize(moshi: Moshi) {
paramsAdapter = moshi.adapter(TLE::class.java)
}
@JvmStatic
@TypeConverter
fun paramsToString(tle: TLE): String {
return paramsAdapter.toJson(tle)
}
@JvmStatic
@TypeConverter
fun paramsFromString(string: String): TLE? {
return paramsAdapter.fromJson(string)
}
@JvmStatic
@TypeConverter
fun satelliteFromString(string: String): Satellite? {
return paramsAdapter.fromJson(string)?.createSat()
}
}

Wyświetl plik

@ -20,62 +20,45 @@ package com.rtbishop.look4sat.framework.local
import androidx.room.*
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem
import com.rtbishop.look4sat.framework.model.Transmitter
import com.rtbishop.look4sat.domain.predict.Satellite
import kotlinx.coroutines.flow.Flow
@Dao
interface SatelliteDao {
interface EntriesDao {
@Transaction
@Query("SELECT catNum, name, isSelected FROM entries ORDER BY name ASC")
@Query("SELECT catnum, name, isSelected FROM entries ORDER BY name ASC")
fun getSatItems(): Flow<List<SatItem>>
@Query("SELECT * FROM transmitters WHERE catNum = :catNum")
fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>>
@Query("SELECT tle FROM entries WHERE isSelected = 1")
suspend fun getSelectedSatellites(): List<Satellite>
@Query("SELECT catNum FROM entries WHERE isSelected = 1")
suspend fun getSelectedCatNums(): List<Int>
@Query("SELECT * FROM entries WHERE isSelected = 1")
suspend fun getSelectedSatellites(): List<SatEntry>
@Transaction
suspend fun updateEntries(entries: List<SatEntry>) {
val selectedCatNums = getSelectedCatNums()
val entriesSelection = getEntriesSelection()
insertEntries(entries)
restoreEntriesSelection(selectedCatNums, true)
restoreEntriesSelection(entriesSelection, true)
}
@Query("SELECT catnum FROM entries WHERE isSelected = 1")
suspend fun getEntriesSelection(): List<Int>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertEntries(entries: List<SatEntry>)
@Transaction
suspend fun restoreEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
suspend fun updateEntriesSelection(catnums: List<Int>, isSelected: Boolean) {
catnums.forEach { catnum -> updateEntrySelection(catnum, isSelected) }
}
@Transaction
suspend fun restoreEntriesSelection(catnums: List<Int>, isSelected: Boolean) {
clearEntriesSelection()
catNums.forEach { catNum -> updateEntrySelection(catNum, isSelected) }
catnums.forEach { catnum -> updateEntrySelection(catnum, isSelected) }
}
@Query("UPDATE entries SET isSelected = 0")
suspend fun clearEntriesSelection()
@Query("UPDATE entries SET isSelected = :isSelected WHERE catNum = :catNum")
suspend fun updateEntrySelection(catNum: Int, isSelected: Boolean)
@Transaction
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
catNums.forEach { catNum -> updateEntrySelection(catNum, isSelected) }
}
@Transaction
suspend fun updateTransmitters(transmitters: List<Transmitter>) {
deleteTransmitters()
insertTransmitters(transmitters)
}
@Query("DELETE from transmitters")
suspend fun deleteTransmitters()
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTransmitters(transmitters: List<Transmitter>)
@Query("UPDATE entries SET isSelected = :isSelected WHERE catnum = :catnum")
suspend fun updateEntrySelection(catnum: Int, isSelected: Boolean)
}

Wyświetl plik

@ -23,49 +23,55 @@ import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.framework.DataMapper
import com.rtbishop.look4sat.framework.model.DataSource
import com.rtbishop.look4sat.framework.model.Source
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
class LocalSource(
private val satelliteDao: SatelliteDao,
private val sourcesDao: SourcesDao
private val entriesDao: EntriesDao,
private val sourcesDao: SourcesDao,
private val transmittersDao: TransmittersDao
) : LocalDataSource {
// Entries
override fun getEntriesWithModes(): Flow<List<SatItem>> {
return satelliteDao.getSatItems()
.map { satItems -> DataMapper.satItemsToDomainItems(satItems) }
}
override suspend fun getSources(): List<String> {
return sourcesDao.getSources()
return entriesDao.getSatItems().map { satItems ->
DataMapper.satItemsToDomainItems(satItems)
}
}
override suspend fun getSelectedSatellites(): List<Satellite> {
return satelliteDao.getSelectedSatellites()
return entriesDao.getSelectedSatellites().map { it.tle.createSat() }
}
override suspend fun updateEntries(entries: List<SatEntry>) {
val satEntries = entries.map { entry -> DataMapper.domainEntryToSatEntry(entry) }
satelliteDao.updateEntries(satEntries)
entriesDao.updateEntries(satEntries)
}
override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
satelliteDao.updateEntriesSelection(catNums, isSelected)
override suspend fun updateEntriesSelection(catnums: List<Int>, isSelected: Boolean) {
entriesDao.updateEntriesSelection(catnums, isSelected)
}
// Sources
override suspend fun getSources(): List<String> {
return sourcesDao.getSources()
}
override suspend fun updateSources(sources: List<String>) {
sourcesDao.deleteSources()
sourcesDao.setSources(sources.map { DataSource(it) })
sourcesDao.updateSources(sources.map { Source(it) })
}
override fun getTransmitters(catNum: Int): Flow<List<Transmitter>> {
return satelliteDao.getSatTransmitters(catNum)
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
// Transmitters
override fun getTransmitters(catnum: Int): Flow<List<Transmitter>> {
return transmittersDao.getTransmitters(catnum).map { satTransList ->
DataMapper.satTransListToDomainTransList(satTransList)
}
}
override suspend fun updateTransmitters(transmitters: List<Transmitter>) {
val satTransList = DataMapper.domainTransListToSatTransList(transmitters)
satelliteDao.updateTransmitters(satTransList)
val transList = DataMapper.domainTransListToSatTransList(transmitters)
transmittersDao.updateTransmitters(transList)
}
}

Wyświetl plik

@ -19,24 +19,24 @@ package com.rtbishop.look4sat.framework.local
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.rtbishop.look4sat.framework.model.DataSource
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.Transmitter
@Database(
entities = [SatEntry::class, Transmitter::class, DataSource::class],
version = 3,
entities = [SatEntry::class, Transmitter::class, Source::class],
version = 4,
exportSchema = true
)
@TypeConverters(Converters::class)
abstract class SatelliteDb : RoomDatabase() {
abstract fun satelliteDao(): SatelliteDao
abstract fun entriesDao(): EntriesDao
abstract fun sourcesDao(): SourcesDao
abstract fun transmittersDao(): TransmittersDao
}
val MIGRATION_1_2 = object : Migration(1, 2) {
@ -53,3 +53,16 @@ val MIGRATION_2_3 = object : Migration(2, 3) {
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")
}
}

Wyświetl plik

@ -1,11 +1,8 @@
package com.rtbishop.look4sat.framework.local
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.rtbishop.look4sat.framework.model.DataSource
import kotlinx.coroutines.flow.Flow
import androidx.room.*
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.framework.model.Transmitter
@Dao
interface SourcesDao {
@ -13,9 +10,15 @@ interface SourcesDao {
@Query("SELECT sourceUrl FROM sources")
suspend fun getSources(): List<String>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun setSources(sources: List<DataSource>)
@Transaction
suspend fun updateSources(sources: List<Source>) {
deleteSources()
insertSources(sources)
}
@Query("DELETE from sources")
suspend fun deleteSources()
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSources(sources: List<Source>)
}

Wyświetl plik

@ -0,0 +1,15 @@
package com.rtbishop.look4sat.framework.local
import androidx.room.*
import com.rtbishop.look4sat.framework.model.Transmitter
import kotlinx.coroutines.flow.Flow
@Dao
interface TransmittersDao {
@Query("SELECT * FROM transmitters WHERE catnum = :catnum")
fun getTransmitters(catnum: Int): Flow<List<Transmitter>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun updateTransmitters(transmitters: List<Transmitter>)
}

Wyświetl plik

@ -17,14 +17,13 @@
*/
package com.rtbishop.look4sat.framework.model
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.rtbishop.look4sat.domain.predict.TLE
@Entity(tableName = "entries")
@Entity(tableName = "entries", primaryKeys = ["catnum"])
data class SatEntry(
@Embedded
val tle: TLE,
@PrimaryKey val catNum: Int = tle.catnum,
val name: String = tle.name,
var isSelected: Boolean = false
)

Wyświetl plik

@ -20,13 +20,13 @@ package com.rtbishop.look4sat.framework.model
import androidx.room.Relation
data class SatItem(
val catNum: Int,
val catnum: Int,
val name: String,
var isSelected: Boolean,
@Relation(
parentColumn = "catNum",
parentColumn = "catnum",
entity = Transmitter::class,
entityColumn = "catNum",
entityColumn = "catnum",
projection = ["mode"]
)
val modes: List<String>

Wyświetl plik

@ -21,4 +21,4 @@ import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "sources")
data class DataSource(@PrimaryKey var sourceUrl: String = String())
data class Source(@PrimaryKey var sourceUrl: String = String())

Wyświetl plik

@ -30,5 +30,5 @@ data class Transmitter(
@field:Json(name = "uplink_low") var uplink: Long?,
@field:Json(name = "mode") val mode: String?,
@field:Json(name = "invert") val isInverted: Boolean,
@field:Json(name = "norad_cat_id") val catNum: Int?
@field:Json(name = "norad_cat_id") val catnum: Int?
)

Wyświetl plik

@ -30,6 +30,6 @@ interface SatelliteApi {
@GET
suspend fun fetchFileStream(@Url url: String): Response<ResponseBody>
@GET("transmitters/")
@GET("https://db.satnogs.org/api/transmitters/")
suspend fun fetchTransmitters(): List<Transmitter>
}

Wyświetl plik

@ -24,10 +24,8 @@ import android.hardware.SensorManager
import android.location.LocationManager
import androidx.preference.PreferenceManager
import androidx.room.Room
import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.framework.local.*
import com.rtbishop.look4sat.framework.remote.SatelliteApi
import com.squareup.moshi.Moshi
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -60,48 +58,4 @@ object AppModule {
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(context)
}
@Provides
@Singleton
fun provideMoshi(): Moshi {
return Moshi.Builder().build()
}
@Provides
@Singleton
fun providePreferenceSource(
locationManager: LocationManager,
preferences: SharedPreferences
): PreferencesSource {
return PreferencesSource(locationManager, preferences)
}
@Provides
@Singleton
fun provideSatelliteApi(): SatelliteApi {
return Retrofit.Builder()
.baseUrl("https://db.satnogs.org/api/")
.addConverterFactory(MoshiConverterFactory.create())
.build().create(SatelliteApi::class.java)
}
@Provides
@Singleton
fun provideSatelliteDao(db: SatelliteDb): SatelliteDao {
return db.satelliteDao()
}
@Provides
@Singleton
fun provideSourcesDao(db: SatelliteDb): SourcesDao {
return db.sourcesDao()
}
@Provides
@Singleton
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatelliteDb {
Converters.initialize(moshi)
return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
}
}

Wyświetl plik

@ -17,6 +17,8 @@
*/
package com.rtbishop.look4sat.injection
import android.content.Context
import androidx.room.Room
import com.rtbishop.look4sat.data.LocalDataSource
import com.rtbishop.look4sat.data.RemoteDataSource
import com.rtbishop.look4sat.data.DataRepository
@ -29,8 +31,11 @@ import com.rtbishop.look4sat.framework.local.*
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton
@Module
@ -38,16 +43,19 @@ import javax.inject.Singleton
object CoreModule {
@Provides
fun provideLocalDataSource(
satelliteDao: SatelliteDao,
sourcesDao: SourcesDao
): LocalDataSource {
return LocalSource(satelliteDao, sourcesDao)
@Singleton
fun provideLocalDataSource(@ApplicationContext context: Context): LocalDataSource {
val database = Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4).build()
return LocalSource(database.entriesDao(), database.sourcesDao(), database.transmittersDao())
}
@Provides
@Singleton
fun provideRemoteDataSource(satelliteApi: SatelliteApi): RemoteDataSource {
fun provideRemoteDataSource(): RemoteDataSource {
val satelliteApi = Retrofit.Builder().baseUrl("https://localhost")
.addConverterFactory(MoshiConverterFactory.create()).build()
.create(SatelliteApi::class.java)
return RemoteSource(satelliteApi)
}

Wyświetl plik

@ -27,7 +27,7 @@ import javax.inject.Qualifier
@Module
@InstallIn(SingletonComponent::class)
object CoroutinesModule {
object KotlinModule {
@Provides
@DefaultDispatcher

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.utility
package com.rtbishop.look4sat.presentation
import android.net.Uri
import android.os.Bundle

Wyświetl plik

@ -30,7 +30,7 @@ class EntriesAdapter(private val clickListener: EntriesClickListener) :
private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() {
override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
return oldItem.catNum == newItem.catNum
return oldItem.catnum == newItem.catnum
}
override fun areContentsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
@ -60,7 +60,7 @@ class EntriesAdapter(private val clickListener: EntriesClickListener) :
binding.entryName.text = item.name
binding.entryCheckbox.isChecked = item.isSelected
itemView.setOnClickListener {
listener.updateSelection(listOf(item.catNum), item.isSelected.not())
listener.updateSelection(listOf(item.catnum), item.isSelected.not())
}
}

Wyświetl plik

@ -31,9 +31,9 @@ import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.domain.model.SatItem
import com.rtbishop.look4sat.domain.DataState
import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.getNavResult
import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.showSnack
import com.rtbishop.look4sat.presentation.getNavResult
import com.rtbishop.look4sat.presentation.navigateSafe
import com.rtbishop.look4sat.presentation.showSnack
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint

Wyświetl plik

@ -79,7 +79,7 @@ class EntriesViewModel @Inject constructor(
fun selectCurrentItems() {
val currentValue = _satData.value
if (currentValue is DataState.Success) {
updateSelection(currentValue.data.map { it.catNum }, shouldSelectAll)
updateSelection(currentValue.data.map { it.catnum }, shouldSelectAll)
shouldSelectAll = shouldSelectAll.not()
}
}
@ -114,7 +114,7 @@ class EntriesViewModel @Inject constructor(
private fun filterByQuery(items: List<SatItem>, query: String): List<SatItem> {
if (query.isBlank()) return items
return try {
items.filter { it.catNum == query.toInt() }
items.filter { it.catnum == query.toInt() }
} catch (e: Exception) {
items.filter { item ->
val itemName = item.name.lowercase(Locale.getDefault())

Wyświetl plik

@ -32,8 +32,8 @@ import com.rtbishop.look4sat.databinding.FragmentPassesBinding
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.DataState
import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.toTimerString
import com.rtbishop.look4sat.presentation.navigateSafe
import com.rtbishop.look4sat.presentation.toTimerString
import dagger.hilt.android.AndroidEntryPoint
import java.util.*

Wyświetl plik

@ -32,8 +32,8 @@ import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.toTimerString
import com.rtbishop.look4sat.presentation.navigateSafe
import com.rtbishop.look4sat.presentation.toTimerString
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

Wyświetl plik

@ -26,7 +26,7 @@ import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.domain.model.Transmitter
import com.rtbishop.look4sat.framework.OrientationSource
import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.utility.round
import com.rtbishop.look4sat.presentation.round
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
@ -100,7 +100,7 @@ class RadarViewModel @Inject constructor(
private fun processTransmitters(satPass: SatPass) {
viewModelScope.launch {
satelliteRepo.getSatTransmitters(satPass.catNum).collect { transList ->
satelliteRepo.getTransmitters(satPass.catNum).collect { transList ->
while (isActive) {
val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date())
val copiedList = transList.map { it.copy() }

Wyświetl plik

@ -22,22 +22,22 @@ 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.DataSource
import com.rtbishop.look4sat.framework.model.Source
class SourcesAdapter(private val sources: MutableList<DataSource> = mutableListOf()) :
class SourcesAdapter(private val sources: MutableList<Source> = mutableListOf()) :
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
fun getSources(): List<DataSource> {
fun getSources(): List<Source> {
return sources.filter { it.sourceUrl.contains("https://") }
}
fun setSources(list: List<DataSource>) {
fun setSources(list: List<Source>) {
sources.clear()
sources.addAll(list)
}
fun addSource() {
sources.add(DataSource())
sources.add(Source())
notifyItemInserted(itemCount - 1)
}
@ -58,7 +58,7 @@ class SourcesAdapter(private val sources: MutableList<DataSource> = mutableListO
inner class TleSourceHolder(private val binding: ItemSourceBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(source: DataSource) {
fun bind(source: Source) {
binding.sourceUrl.setText(source.sourceUrl)
binding.sourceUrl.doOnTextChanged { text, _, _, _ -> source.sourceUrl = text.toString() }
binding.sourceInput.setEndIconOnClickListener {

Wyświetl plik

@ -27,8 +27,8 @@ import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
import com.rtbishop.look4sat.framework.model.DataSource
import com.rtbishop.look4sat.utility.setNavResult
import com.rtbishop.look4sat.framework.model.Source
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@ -43,7 +43,7 @@ class SourcesDialog : AppCompatDialogFragment() {
override fun onViewCreated(view: View, state: Bundle?) {
super.onViewCreated(view, state)
viewModel.sources.observe(viewLifecycleOwner, { sources ->
val adapter = SourcesAdapter().apply { setSources(sources.map { DataSource(it) }) }
val adapter = SourcesAdapter().apply { setSources(sources.map { Source(it) }) }
DialogSourcesBinding.bind(view).apply {
dialog?.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,

Wyświetl plik

@ -17,6 +17,7 @@ buildscript {
junit_version = '4.13.2'
mockito_version = '4.0.0'
leak_canary_version = '2.7'
jvm_version = '11'
}
repositories {
google()

Wyświetl plik

@ -2,6 +2,15 @@ plugins {
id 'kotlin'
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
kotlinOptions {
jvmTarget = "$jvm_version"
}
}
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"

Wyświetl plik

@ -41,8 +41,8 @@ class DataRepository(
return localSource.getEntriesWithModes()
}
override fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>> {
return localSource.getTransmitters(catNum)
override fun getTransmitters(catnum: Int): Flow<List<Transmitter>> {
return localSource.getTransmitters(catnum)
}
override fun getDefaultSources(): List<String> {
@ -97,8 +97,8 @@ class DataRepository(
}
}
override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
localSource.updateEntriesSelection(catNums, isSelected)
override suspend fun updateEntriesSelection(catnums: List<Int>, isSelected: Boolean) {
localSource.updateEntriesSelection(catnums, isSelected)
}
private fun importSatEntries(stream: InputStream): List<SatEntry> {

Wyświetl plik

@ -25,19 +25,22 @@ import kotlinx.coroutines.flow.Flow
interface LocalDataSource {
// Entries
fun getEntriesWithModes(): Flow<List<SatItem>>
fun getTransmitters(catNum: Int): Flow<List<Transmitter>>
suspend fun getSources(): List<String>
suspend fun getSelectedSatellites(): List<Satellite>
suspend fun updateEntries(entries: List<SatEntry>)
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
suspend fun updateEntriesSelection(catnums: List<Int>, isSelected: Boolean)
// Sources
suspend fun getSources(): List<String>
suspend fun updateSources(sources: List<String>)
// Transmitters
fun getTransmitters(catnum: Int): Flow<List<Transmitter>>
suspend fun updateTransmitters(transmitters: List<Transmitter>)
}

Wyświetl plik

@ -27,7 +27,7 @@ interface SatelliteRepo {
fun getSatItems(): Flow<List<SatItem>>
fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>>
fun getTransmitters(catnum: Int): Flow<List<Transmitter>>
fun getDefaultSources(): List<String>
@ -39,5 +39,5 @@ interface SatelliteRepo {
suspend fun updateEntriesFromWeb(sources: List<String>)
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
suspend fun updateEntriesSelection(catnums: List<Int>, isSelected: Boolean)
}

Wyświetl plik

@ -21,7 +21,5 @@ import com.rtbishop.look4sat.domain.predict.TLE
data class SatEntry(
val tle: TLE,
val catNum: Int = tle.catnum,
val name: String = tle.name,
var isSelected: Boolean = false
)

Wyświetl plik

@ -18,7 +18,7 @@
package com.rtbishop.look4sat.domain.model
data class SatItem(
val catNum: Int,
val catnum: Int,
val name: String,
var isSelected: Boolean,
val modes: List<String>

Wyświetl plik

@ -25,5 +25,5 @@ data class Transmitter(
var uplink: Long?,
val mode: String?,
val isInverted: Boolean,
val catNum: Int?
val catnum: Int?
)

Wyświetl plik

@ -30,14 +30,14 @@ data class TLE(
val argper: Double,
val meanan: Double,
val catnum: Int,
val bstar: Double
) {
val xincl: Double = Math.toRadians(incl)
val xnodeo: Double = Math.toRadians(raan)
val omegao: Double = Math.toRadians(argper)
val xmo: Double = Math.toRadians(meanan)
val xno: Double = meanmo * Math.PI * 2.0 / 1440
val bstar: Double,
val xincl: Double = Math.toRadians(incl),
val xnodeo: Double = Math.toRadians(raan),
val omegao: Double = Math.toRadians(argper),
val xmo: Double = Math.toRadians(meanan),
val xno: Double = meanmo * Math.PI * 2.0 / 1440,
val isDeepspace: Boolean = meanmo < 6.4
) {
fun createSat(): Satellite {
return when {

Wyświetl plik

@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m
org.gradle.jvmargs=-Xmx2048m -XX:+UseParallelGC
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
@ -20,3 +20,4 @@ android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
kapt.use.worker.api=false
org.gradle.unsafe.configuration-cache=true

Wyświetl plik

@ -1,3 +1,3 @@
include ':core'
include ':app'
include ':core'
rootProject.name='Look4Sat'