Moved and renamed several classes

This commit is contained in:
Arty Bishop committed 2021-10-27 21:47:02 +01:00
1 parent 6fa63fdcff
commit 55a827330f
59 files changed
+383 -322

No files matched your search

+4
View File
@@ -24,8 +24,12 @@ android {
} }
} }
// def props = new Properties()
// file("../securityKeys.properties").withInputStream { props.load(it) }
buildTypes { buildTypes {
release { release {
// buildConfigField "String", "ApiKey", props.getProperty("apiKey")
// minifyEnabled true // minifyEnabled true
// shrinkResources true // shrinkResources true
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' // proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -15,18 +15,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.utility package com.rtbishop.look4sat.framework
import com.rtbishop.look4sat.framework.model.SatEntry import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem import com.rtbishop.look4sat.framework.model.SatItem
import com.rtbishop.look4sat.framework.model.Transmitter import com.rtbishop.look4sat.framework.model.Transmitter
import com.rtbishop.look4sat.data.SatEntry as DomainEntry import com.rtbishop.look4sat.model.SatEntry as DomainEntry
import com.rtbishop.look4sat.data.SatItem as DomainItem import com.rtbishop.look4sat.model.SatItem as DomainItem
import com.rtbishop.look4sat.domain.Transmitter as DomainTrans import com.rtbishop.look4sat.model.Transmitter as DomainTrans
object DataMapper { object DataMapper {
// Framework to Domain // Presentation to Domain
fun satEntryToDomainEntry(entry: SatEntry): DomainEntry { fun satEntryToDomainEntry(entry: SatEntry): DomainEntry {
return DomainEntry(entry.tle, entry.catNum, entry.name, entry.isSelected) return DomainEntry(entry.tle, entry.catNum, entry.name, entry.isSelected)
@@ -55,7 +55,7 @@ object DataMapper {
return transmitters.map { transmitter -> satTransToDomainTrans(transmitter) } return transmitters.map { transmitter -> satTransToDomainTrans(transmitter) }
} }
// Domain to Framework // Domain to Presentation
fun domainEntryToSatEntry(entry: DomainEntry): SatEntry { fun domainEntryToSatEntry(entry: DomainEntry): SatEntry {
return SatEntry(entry.tle, entry.catNum, entry.name, entry.isSelected) return SatEntry(entry.tle, entry.catNum, entry.name, entry.isSelected)
@@ -21,8 +21,8 @@ import android.content.SharedPreferences
import android.hardware.GeomagneticField import android.hardware.GeomagneticField
import android.location.LocationManager import android.location.LocationManager
import androidx.core.content.edit import androidx.core.content.edit
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.common.Constants
import com.rtbishop.look4sat.domain.GeoPos import com.rtbishop.look4sat.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.QthConverter import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.utility.round import com.rtbishop.look4sat.utility.round
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
@@ -33,12 +33,12 @@ class PreferencesSource @Inject constructor(
moshi: Moshi, moshi: Moshi,
private val locationManager: LocationManager, private val locationManager: LocationManager,
private val preferences: SharedPreferences private val preferences: SharedPreferences
) : Preferences { ) {
private val sourcesType = Types.newParameterizedType(List::class.java, String::class.java) private val sourcesType = Types.newParameterizedType(List::class.java, String::class.java)
private val sourcesAdapter = moshi.adapter<List<String>>(sourcesType) private val sourcesAdapter = moshi.adapter<List<String>>(sourcesType)
override fun loadTleSources(): List<String> { fun loadTleSources(): List<String> {
return try { return try {
val sourcesString = preferences.getString(keySources, String()) val sourcesString = preferences.getString(keySources, String())
if (sourcesString.isNullOrEmpty()) { if (sourcesString.isNullOrEmpty()) {
@@ -51,17 +51,15 @@ class PreferencesSource @Inject constructor(
} }
} }
override fun saveTleSources(sources: List<String>) { fun saveTleSources(sources: List<String>) {
val sourcesJson = sourcesAdapter.toJson(sources) val sourcesJson = sourcesAdapter.toJson(sources)
preferences.edit { putString(keySources, sourcesJson) } preferences.edit { putString(keySources, sourcesJson) }
} }
override fun loadDefaultSources(): List<String> { fun loadDefaultSources(): List<String> {
return listOf( return listOf(
"https://celestrak.com/NORAD/elements/active.txt", Constants.URL_CELESTRAK, Constants.URL_AMSAT,
"https://amsat.org/tle/current/nasabare.txt", Constants.URL_PRISM_CLASSFD, Constants.URL_PRISM_INTEL
"https://www.prismnet.com/~mmccants/tles/classfd.zip",
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
) )
} }
@@ -85,11 +83,11 @@ class PreferencesSource @Inject constructor(
const val keyPositionQTH = "setPositionQTH" const val keyPositionQTH = "setPositionQTH"
} }
override fun positionToQTH(lat: Double, lon: Double): String? { fun positionToQTH(lat: Double, lon: Double): String? {
return QthConverter.positionToQTH(lat, lon) return QthConverter.positionToQTH(lat, lon)
} }
override fun loadStationPosition(): GeoPos { fun loadStationPosition(): GeoPos {
val defaultSP = "0.0" val defaultSP = "0.0"
val latitude = preferences.getString(keyLatitude, null) ?: defaultSP val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
val longitude = preferences.getString(keyLongitude, null) ?: defaultSP val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
@@ -97,7 +95,7 @@ class PreferencesSource @Inject constructor(
return GeoPos(latitude.toDouble(), longitude.toDouble(), altitude.toDouble()) return GeoPos(latitude.toDouble(), longitude.toDouble(), altitude.toDouble())
} }
override fun saveStationPosition(pos: GeoPos) { fun saveStationPosition(pos: GeoPos) {
preferences.edit { preferences.edit {
putString(keyLatitude, pos.latitude.toString()) putString(keyLatitude, pos.latitude.toString())
putString(keyLongitude, pos.longitude.toString()) putString(keyLongitude, pos.longitude.toString())
@@ -105,7 +103,7 @@ class PreferencesSource @Inject constructor(
} }
} }
override fun updatePositionFromGPS(): Boolean { fun updatePositionFromGPS(): Boolean {
return try { return try {
val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER) val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
if (location == null) false if (location == null) false
@@ -122,14 +120,14 @@ class PreferencesSource @Inject constructor(
} }
} }
override fun updatePositionFromQTH(qthString: String): Boolean { fun updatePositionFromQTH(qthString: String): Boolean {
val position = QthConverter.qthToPosition(qthString) ?: return false val position = QthConverter.qthToPosition(qthString) ?: return false
val stationPosition = GeoPos(position.latitude, position.longitude, 0.0) val stationPosition = GeoPos(position.latitude, position.longitude, 0.0)
saveStationPosition(stationPosition) saveStationPosition(stationPosition)
return true return true
} }
override fun getMagDeclination(): Float { fun getMagDeclination(): Float {
val stationPosition = loadStationPosition() val stationPosition = loadStationPosition()
val lat = stationPosition.latitude.toFloat() val lat = stationPosition.latitude.toFloat()
val lon = stationPosition.longitude.toFloat() val lon = stationPosition.longitude.toFloat()
@@ -137,56 +135,60 @@ class PreferencesSource @Inject constructor(
return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination
} }
override fun getHoursAhead(): Int { fun getHoursAhead(): Int {
return preferences.getInt(keyHoursAhead, 8) return preferences.getInt(keyHoursAhead, 8)
} }
override fun getMinElevation(): Double { fun getMinElevation(): Double {
return preferences.getInt(keyMinElevation, 16).toDouble() return preferences.getInt(keyMinElevation, 16).toDouble()
} }
override fun shouldUseTextLabels(): Boolean { fun shouldUseTextLabels(): Boolean {
return preferences.getBoolean(keyTextLabels, false) return preferences.getBoolean(keyTextLabels, false)
} }
override fun shouldUseUTC(): Boolean { fun shouldUseUTC(): Boolean {
return preferences.getBoolean(keyTimeUTC, false) return preferences.getBoolean(keyTimeUTC, false)
} }
override fun shouldUseCompass(): Boolean { fun shouldUseCompass(): Boolean {
return preferences.getBoolean(keyCompass, true) return preferences.getBoolean(keyCompass, true)
} }
override fun shouldShowSweep(): Boolean { fun shouldShowSweep(): Boolean {
return preferences.getBoolean(keyRadarSweep, true) return preferences.getBoolean(keyRadarSweep, true)
} }
override fun isSetupDone(): Boolean { fun isSetupDone(): Boolean {
return preferences.getBoolean(keyInitialSetup, false) return preferences.getBoolean(keyInitialSetup, false)
} }
override fun setSetupDone() { fun setSetupDone() {
preferences.edit { putBoolean(keyInitialSetup, true) } preferences.edit { putBoolean(keyInitialSetup, true) }
} }
override fun saveModesSelection(modes: List<String>) { fun saveModesSelection(modes: List<String>) {
val modesSet = modes.toSet() val modesSet = modes.toSet()
preferences.edit { preferences.edit {
putStringSet(keyModes, modesSet) putStringSet(keyModes, modesSet)
} }
} }
override fun loadModesSelection(): List<String> { fun loadModesSelection(): List<String> {
preferences.getStringSet(keyModes, setOf())?.let { modesSet -> preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
return modesSet.toList().sorted() return modesSet.toList().sorted()
} }
return emptyList() return emptyList()
} }
override fun getRotatorServer(): Pair<String, Int>? { fun isRotatorEnabled(): Boolean {
return if (preferences.getBoolean(keyRotator, false)) { return preferences.getBoolean(keyRotator, false)
}
fun getRotatorServer(): Pair<String, Int>? {
return if (isRotatorEnabled()) {
val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1" val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
val port = preferences.getString(keyRotatorPort, null) ?: "4096" val port = preferences.getString(keyRotatorPort, null) ?: "4533"
Pair(address, port.toInt()) Pair(address, port.toInt())
} else null } else null
} }
@@ -15,15 +15,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.db package com.rtbishop.look4sat.framework.local
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.predict4kotlin.Satellite
import com.rtbishop.look4sat.domain.TLE import com.rtbishop.look4sat.predict4kotlin.TLE
import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
object RoomConverters { object Converters {
private lateinit var paramsAdapter: JsonAdapter<TLE> private lateinit var paramsAdapter: JsonAdapter<TLE>
@@ -15,18 +15,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.db package com.rtbishop.look4sat.framework.local
import com.rtbishop.look4sat.data.LocalSource import com.rtbishop.look4sat.data.LocalDataSource
import com.rtbishop.look4sat.data.SatEntry import com.rtbishop.look4sat.model.SatEntry
import com.rtbishop.look4sat.data.SatItem import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.predict4kotlin.Satellite
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.utility.DataMapper import com.rtbishop.look4sat.framework.DataMapper
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
class LocalDataSource(private val satelliteDao: SatelliteDao) : LocalSource { class LocalSource(private val satelliteDao: SatelliteDao) : LocalDataSource {
override fun getEntriesWithModes(): Flow<List<SatItem>> { override fun getEntriesWithModes(): Flow<List<SatItem>> {
return satelliteDao.getSatItems() return satelliteDao.getSatItems()
@@ -15,13 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.db package com.rtbishop.look4sat.framework.local
import androidx.room.* import androidx.room.*
import com.rtbishop.look4sat.framework.model.SatEntry import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.SatItem import com.rtbishop.look4sat.framework.model.SatItem
import com.rtbishop.look4sat.framework.model.Transmitter import com.rtbishop.look4sat.framework.model.Transmitter
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.predict4kotlin.Satellite
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.db package com.rtbishop.look4sat.framework.local
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
@@ -26,7 +26,7 @@ import com.rtbishop.look4sat.framework.model.SatEntry
import com.rtbishop.look4sat.framework.model.Transmitter import com.rtbishop.look4sat.framework.model.Transmitter
@Database(entities = [SatEntry::class, Transmitter::class], version = 2, exportSchema = true) @Database(entities = [SatEntry::class, Transmitter::class], version = 2, exportSchema = true)
@TypeConverters(RoomConverters::class) @TypeConverters(Converters::class)
abstract class SatelliteDb : RoomDatabase() { abstract class SatelliteDb : RoomDatabase() {
abstract fun satelliteDao(): SatelliteDao abstract fun satelliteDao(): SatelliteDao
@@ -1,33 +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.model
import com.squareup.moshi.Json
data class OMM(
@field:Json(name = "OBJECT_NAME") val name: String,
@field:Json(name = "EPOCH") val epochString: String,
@field:Json(name = "MEAN_MOTION") val meanmo: Double,
@field:Json(name = "ECCENTRICITY") val eccn: Double,
@field:Json(name = "INCLINATION") val incl: Double,
@field:Json(name = "RA_OF_ASC_NODE") val raan: Double,
@field:Json(name = "ARG_OF_PERICENTER") val argper: Double,
@field:Json(name = "MEAN_ANOMALY") val meanan: Double,
@field:Json(name = "NORAD_CAT_ID") val catnum: Int,
@field:Json(name = "BSTAR") val bstar: Double,
)
@@ -19,7 +19,7 @@ package com.rtbishop.look4sat.framework.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.rtbishop.look4sat.domain.TLE import com.rtbishop.look4sat.predict4kotlin.TLE
@Entity(tableName = "entries") @Entity(tableName = "entries")
data class SatEntry( data class SatEntry(
@@ -15,14 +15,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.api package com.rtbishop.look4sat.framework.remote
import com.rtbishop.look4sat.data.RemoteSource import com.rtbishop.look4sat.data.RemoteDataSource
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.utility.DataMapper import com.rtbishop.look4sat.framework.DataMapper
import java.io.InputStream import java.io.InputStream
class RemoteDataSource(private val satelliteApi: SatelliteApi) : RemoteSource { class RemoteSource(private val satelliteApi: SatelliteApi) : RemoteDataSource {
override suspend fun fetchFileStream(url: String): InputStream? { override suspend fun fetchFileStream(url: String): InputStream? {
return satelliteApi.fetchFileStream(url).body()?.byteStream() return satelliteApi.fetchFileStream(url).body()?.byteStream()
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.api package com.rtbishop.look4sat.framework.remote
import com.rtbishop.look4sat.framework.model.Transmitter import com.rtbishop.look4sat.framework.model.Transmitter
import okhttp3.ResponseBody import okhttp3.ResponseBody
@@ -21,16 +21,17 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.location.LocationManager import android.location.LocationManager
import androidx.room.Room import androidx.room.Room
import com.rtbishop.look4sat.data.LocalSource import com.rtbishop.look4sat.data.LocalDataSource
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.data.RemoteDataSource
import com.rtbishop.look4sat.data.RemoteSource import com.rtbishop.look4sat.data.DataRepository
import com.rtbishop.look4sat.data.SatelliteRepo import com.rtbishop.look4sat.framework.remote.SatelliteApi
import com.rtbishop.look4sat.domain.PassReporter import com.rtbishop.look4sat.common.Constants
import com.rtbishop.look4sat.domain.Predictor import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.framework.PreferencesSource import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.framework.api.RemoteDataSource import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.framework.api.SatelliteApi import com.rtbishop.look4sat.predict4kotlin.Predictor
import com.rtbishop.look4sat.framework.db.* import com.rtbishop.look4sat.framework.remote.RemoteSource
import com.rtbishop.look4sat.framework.local.*
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@@ -44,7 +45,7 @@ import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object DataModule { object Look4SatModule {
@Provides @Provides
@Singleton @Singleton
@@ -58,7 +59,7 @@ object DataModule {
moshi: Moshi, moshi: Moshi,
locationManager: LocationManager, locationManager: LocationManager,
preferences: SharedPreferences preferences: SharedPreferences
): Preferences { ): PreferencesSource {
return PreferencesSource(moshi, locationManager, preferences) return PreferencesSource(moshi, locationManager, preferences)
} }
@@ -71,17 +72,16 @@ object DataModule {
@Provides @Provides
@Singleton @Singleton
fun provideSatelliteRepo( fun provideSatelliteRepo(
preferences: Preferences, localSource: LocalDataSource,
localSource: LocalSource, remoteSource: RemoteDataSource,
remoteSource: RemoteSource,
@IoDispatcher dispatcher: CoroutineDispatcher @IoDispatcher dispatcher: CoroutineDispatcher
): SatelliteRepo { ): Repository {
return SatelliteRepo(preferences, localSource, remoteSource, dispatcher) return DataRepository(localSource, remoteSource, dispatcher)
} }
@Provides @Provides
fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalSource { fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalDataSource {
return LocalDataSource(satelliteDao) return LocalSource(satelliteDao)
} }
@Provides @Provides
@@ -93,29 +93,29 @@ object DataModule {
@Provides @Provides
@Singleton @Singleton
fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatelliteDb { fun provideSatelliteDb(@ApplicationContext context: Context, moshi: Moshi): SatelliteDb {
RoomConverters.initialize(moshi) Converters.initialize(moshi)
return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb") return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb")
.addMigrations(MIGRATION_1_2).build() .addMigrations(MIGRATION_1_2).build()
} }
@Provides @Provides
@Singleton @Singleton
fun provideRemoteDataSource(satelliteApi: SatelliteApi): RemoteSource { fun provideRemoteDataSource(satelliteApi: SatelliteApi): RemoteDataSource {
return RemoteDataSource(satelliteApi) return RemoteSource(satelliteApi)
} }
@Provides @Provides
@Singleton @Singleton
fun provideSatelliteService(): SatelliteApi { fun provideSatelliteService(): SatelliteApi {
return Retrofit.Builder() return Retrofit.Builder()
.baseUrl("https://db.satnogs.org/api/") .baseUrl(Constants.URL_BASE)
.addConverterFactory(MoshiConverterFactory.create()) .addConverterFactory(MoshiConverterFactory.create())
.build().create(SatelliteApi::class.java) .build().create(SatelliteApi::class.java)
} }
@Provides @Provides
@Singleton @Singleton
fun provideDataReporter(@IoDispatcher dispatcher: CoroutineDispatcher): PassReporter { fun provideDataReporter(@IoDispatcher dispatcher: CoroutineDispatcher): DataReporter {
return PassReporter(dispatcher) return DataReporter(dispatcher)
} }
} }
@@ -15,13 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.utility package com.rtbishop.look4sat.presentation
import android.graphics.Canvas import android.graphics.Canvas
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
class RecyclerDivider(private val resId: Int) : RecyclerView.ItemDecoration() { class ItemDivider(private val resId: Int) : RecyclerView.ItemDecoration() {
override fun onDrawOver(canvas: Canvas, parent: RecyclerView) { override fun onDrawOver(canvas: Canvas, parent: RecyclerView) {
ContextCompat.getDrawable(parent.context, resId)?.let { drawable -> ContextCompat.getDrawable(parent.context, resId)?.let { drawable ->
@@ -22,10 +22,11 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.data.SatItem import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.databinding.ItemEntryBinding import com.rtbishop.look4sat.databinding.ItemEntryBinding
class EntriesAdapter : RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() { class EntriesAdapter(private val clickListener: EntriesClickListener) :
RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() { private val diffCallback = object : DiffUtil.ItemCallback<SatItem>() {
override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean { override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean {
@@ -37,15 +38,6 @@ class EntriesAdapter : RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() {
} }
} }
private val differ = AsyncListDiffer(this, diffCallback) private val differ = AsyncListDiffer(this, diffCallback)
private lateinit var clickListener: EntriesClickListener
interface EntriesClickListener {
fun updateSelection(catNums: List<Int>, isSelected: Boolean)
}
fun setEntriesClickListener(listener: EntriesClickListener) {
clickListener = listener
}
fun submitList(items: List<SatItem>) { fun submitList(items: List<SatItem>) {
differ.submitList(items) differ.submitList(items)
@@ -79,4 +71,8 @@ class EntriesAdapter : RecyclerView.Adapter<EntriesAdapter.SatItemHolder>() {
} }
} }
} }
interface EntriesClickListener {
fun updateSelection(catNums: List<Int>, isSelected: Boolean)
}
} }
@@ -27,10 +27,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.SatItem import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.framework.model.DataState import com.rtbishop.look4sat.common.DataState
import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.getNavResult import com.rtbishop.look4sat.utility.getNavResult
import com.rtbishop.look4sat.utility.navigateSafe import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.showSnack import com.rtbishop.look4sat.utility.showSnack
@@ -51,16 +51,18 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
} }
private fun setupComponents(view: View) { private fun setupComponents(view: View) {
val entriesAdapter = EntriesAdapter().apply { val entriesAdapter = EntriesAdapter(object: EntriesAdapter.EntriesClickListener {
setEntriesClickListener(viewModel) override fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
} viewModel.updateSelection(catNums, isSelected)
}
})
val binding = FragmentEntriesBinding.bind(view).apply { val binding = FragmentEntriesBinding.bind(view).apply {
entriesRecycler.apply { entriesRecycler.apply {
setHasFixedSize(true) setHasFixedSize(true)
adapter = entriesAdapter adapter = entriesAdapter
layoutManager = LinearLayoutManager(requireContext()) layoutManager = LinearLayoutManager(requireContext())
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light)) addItemDecoration(ItemDivider(R.drawable.rec_divider_light))
} }
entriesImportWeb.setOnClickListener { entriesImportWeb.setOnClickListener {
findNavController().navigateSafe(R.id.action_entries_to_sources) findNavController().navigateSafe(R.id.action_entries_to_sources)
@@ -98,6 +100,8 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
binding.entriesRecycler.visibility = View.VISIBLE binding.entriesRecycler.visibility = View.VISIBLE
requireView().showSnack(getString(R.string.entries_update_error)) requireView().showSnack(getString(R.string.entries_update_error))
} }
else -> {
}
} }
} }
@@ -21,10 +21,10 @@ import android.content.ContentResolver
import android.net.Uri import android.net.Uri
import android.widget.SearchView import android.widget.SearchView
import androidx.lifecycle.* import androidx.lifecycle.*
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.data.SatelliteRepo import com.rtbishop.look4sat.common.DataState
import com.rtbishop.look4sat.data.SatItem import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.framework.model.DataState import com.rtbishop.look4sat.framework.PreferencesSource
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
@@ -35,16 +35,16 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class EntriesViewModel @Inject constructor( class EntriesViewModel @Inject constructor(
private val preferences: Preferences, private val preferences: PreferencesSource,
private val resolver: ContentResolver, private val resolver: ContentResolver,
private val satelliteRepo: SatelliteRepo, private val satelliteRepo: Repository,
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener { ) : ViewModel(), SearchView.OnQueryTextListener {
private val coroutineHandler = CoroutineExceptionHandler { _, throwable -> private val coroutineHandler = CoroutineExceptionHandler { _, throwable ->
Timber.d(throwable) Timber.d(throwable)
_satData.value = DataState.Error(throwable) _satData.value = DataState.Error(throwable)
} }
private val transModes = MutableLiveData(satelliteRepo.loadSelectedModes()) private val transModes = MutableLiveData(preferences.loadModesSelection())
private val currentQuery = MutableLiveData(String()) private val currentQuery = MutableLiveData(String())
private val itemsWithModes = transModes.switchMap { modes -> private val itemsWithModes = transModes.switchMap { modes ->
liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } } liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } }
@@ -86,12 +86,12 @@ class EntriesViewModel @Inject constructor(
} }
fun loadSelectedModes(): List<String> { fun loadSelectedModes(): List<String> {
return satelliteRepo.loadSelectedModes() return preferences.loadModesSelection()
} }
fun saveSelectedModes(modes: List<String>) { fun saveSelectedModes(modes: List<String>) {
transModes.value = modes transModes.value = modes
satelliteRepo.saveSelectedModes(modes) preferences.saveModesSelection(modes)
} }
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
@@ -103,7 +103,7 @@ class EntriesViewModel @Inject constructor(
return true return true
} }
override fun updateSelection(catNums: List<Int>, isSelected: Boolean) { fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
viewModelScope.launch { satelliteRepo.updateEntriesSelection(catNums, isSelected) } viewModelScope.launch { satelliteRepo.updateEntriesSelection(catNums, isSelected) }
} }
@@ -17,8 +17,8 @@
*/ */
package com.rtbishop.look4sat.presentation.mapScreen package com.rtbishop.look4sat.presentation.mapScreen
import com.rtbishop.look4sat.domain.GeoPos import com.rtbishop.look4sat.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.predict4kotlin.Satellite
data class MapData( data class MapData(
val pass: Satellite, val pass: Satellite,
@@ -29,8 +29,8 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentMapBinding import com.rtbishop.look4sat.databinding.FragmentMapBinding
import com.rtbishop.look4sat.domain.GeoPos import com.rtbishop.look4sat.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.predict4kotlin.Satellite
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.osmdroid.config.Configuration import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@@ -18,10 +18,12 @@
package com.rtbishop.look4sat.presentation.mapScreen package com.rtbishop.look4sat.presentation.mapScreen
import androidx.lifecycle.* import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.Predictor import com.rtbishop.look4sat.predict4kotlin.Predictor
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.data.SatelliteRepo import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.domain.* import com.rtbishop.look4sat.predict4kotlin.GeoPos
import com.rtbishop.look4sat.domain.QthConverter
import com.rtbishop.look4sat.predict4kotlin.Satellite
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.util.* import java.util.*
@@ -31,9 +33,9 @@ import kotlin.math.min
@HiltViewModel @HiltViewModel
class MapViewModel @Inject constructor( class MapViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo, private val satelliteRepo: Repository,
private val predictor: Predictor, private val predictor: Predictor,
private val preferences: Preferences, private val preferences: PreferencesSource,
) : ViewModel() { ) : ViewModel() {
private val stationPos = preferences.loadStationPosition() private val stationPos = preferences.loadStationPosition()
@@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.ItemPassGeoBinding import com.rtbishop.look4sat.databinding.ItemPassGeoBinding
import com.rtbishop.look4sat.databinding.ItemPassLeoBinding import com.rtbishop.look4sat.databinding.ItemPassLeoBinding
import com.rtbishop.look4sat.domain.SatPass import com.rtbishop.look4sat.predict4kotlin.SatPass
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -29,9 +29,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentPassesBinding import com.rtbishop.look4sat.databinding.FragmentPassesBinding
import com.rtbishop.look4sat.domain.SatPass import com.rtbishop.look4sat.predict4kotlin.SatPass
import com.rtbishop.look4sat.framework.model.DataState import com.rtbishop.look4sat.common.DataState
import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.navigateSafe import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.toTimerString import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@@ -60,7 +60,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
isVerticalScrollBarEnabled = false isVerticalScrollBarEnabled = false
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark)) addItemDecoration(ItemDivider(R.drawable.rec_divider_dark))
} }
passesRefresh.setOnClickListener { passesViewModel.forceCalculation() } passesRefresh.setOnClickListener { passesViewModel.forceCalculation() }
} }
@@ -21,11 +21,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.predict4kotlin.Predictor
import com.rtbishop.look4sat.data.SatelliteRepo import com.rtbishop.look4sat.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.Predictor import com.rtbishop.look4sat.common.DataState
import com.rtbishop.look4sat.domain.SatPass import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.framework.model.DataState import com.rtbishop.look4sat.framework.PreferencesSource
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
@@ -34,9 +34,9 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class PassesViewModel @Inject constructor( class PassesViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo, private val satelliteRepo: Repository,
private val predictor: Predictor, private val predictor: Predictor,
private val preferences: Preferences private val preferences: PreferencesSource
) : ViewModel() { ) : ViewModel() {
private val _passes = MutableLiveData<DataState<List<SatPass>>>(DataState.Loading) private val _passes = MutableLiveData<DataState<List<SatPass>>>(DataState.Loading)
@@ -1,5 +1,22 @@
/*
* 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.presentation.radarScreen package com.rtbishop.look4sat.presentation.radarScreen
import com.rtbishop.look4sat.domain.SatPos import com.rtbishop.look4sat.predict4kotlin.SatPos
data class RadarData(val satPos: SatPos, val satTrack: List<SatPos> = emptyList()) data class RadarData(val satPos: SatPos, val satTrack: List<SatPos> = emptyList())
@@ -25,11 +25,11 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.Preferences
import com.rtbishop.look4sat.databinding.FragmentRadarBinding import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.SatPass import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.domain.SatPos import com.rtbishop.look4sat.predict4kotlin.SatPass
import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.predict4kotlin.SatPos
import com.rtbishop.look4sat.presentation.ItemDivider
import com.rtbishop.look4sat.utility.navigateSafe import com.rtbishop.look4sat.utility.navigateSafe
import com.rtbishop.look4sat.utility.toTimerString import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@@ -39,7 +39,7 @@ import javax.inject.Inject
class RadarFragment : Fragment(R.layout.fragment_radar) { class RadarFragment : Fragment(R.layout.fragment_radar) {
@Inject @Inject
lateinit var preferences: Preferences lateinit var preferences: PreferencesSource
private val viewModel: RadarViewModel by viewModels() private val viewModel: RadarViewModel by viewModels()
private var radarView: RadarView? = null private var radarView: RadarView? = null
@@ -53,7 +53,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
isVerticalScrollBarEnabled = false isVerticalScrollBarEnabled = false
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark)) addItemDecoration(ItemDivider(R.drawable.rec_divider_dark))
} }
setupObservers(transAdapter, this) setupObservers(transAdapter, this)
} }
@@ -22,7 +22,7 @@ import android.graphics.*
import android.view.View import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.SatPos import com.rtbishop.look4sat.predict4kotlin.SatPos
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.min import kotlin.math.min
import kotlin.math.sin import kotlin.math.sin
@@ -18,14 +18,14 @@
package com.rtbishop.look4sat.presentation.radarScreen package com.rtbishop.look4sat.presentation.radarScreen
import androidx.lifecycle.* import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.PassReporter import com.rtbishop.look4sat.domain.DataReporter
import com.rtbishop.look4sat.data.Preferences import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.data.SatelliteRepo import com.rtbishop.look4sat.predict4kotlin.Predictor
import com.rtbishop.look4sat.domain.Predictor import com.rtbishop.look4sat.predict4kotlin.SatPass
import com.rtbishop.look4sat.domain.SatPass import com.rtbishop.look4sat.predict4kotlin.SatPos
import com.rtbishop.look4sat.domain.SatPos import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.domain.Transmitter
import com.rtbishop.look4sat.framework.OrientationSource import com.rtbishop.look4sat.framework.OrientationSource
import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.utility.round import com.rtbishop.look4sat.utility.round
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -38,10 +38,10 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RadarViewModel @Inject constructor( class RadarViewModel @Inject constructor(
private val orientationSource: OrientationSource, private val orientationSource: OrientationSource,
private val preferences: Preferences, private val preferences: PreferencesSource,
private val predictor: Predictor, private val predictor: Predictor,
private val satelliteRepo: SatelliteRepo, private val satelliteRepo: Repository,
private val passReporter: PassReporter private val dataReporter: DataReporter
) : ViewModel(), OrientationSource.OrientationListener { ) : ViewModel(), OrientationSource.OrientationListener {
private val stationPos = preferences.loadStationPosition() private val stationPos = preferences.loadStationPosition()
@@ -80,7 +80,7 @@ class RadarViewModel @Inject constructor(
var satTrack: List<SatPos> = emptyList() var satTrack: List<SatPos> = emptyList()
val rotatorPrefs = preferences.getRotatorServer() val rotatorPrefs = preferences.getRotatorServer()
if (rotatorPrefs != null) { if (rotatorPrefs != null) {
passReporter.setupRotatorSocket(rotatorPrefs.first, rotatorPrefs.second) dataReporter.setupRotatorSocket(rotatorPrefs.first, rotatorPrefs.second)
} }
if (!satPass.isDeepSpace) { if (!satPass.isDeepSpace) {
val startDate = Date(satPass.aosTime) val startDate = Date(satPass.aosTime)
@@ -91,7 +91,7 @@ class RadarViewModel @Inject constructor(
val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date()) val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date())
val azimuth = Math.toDegrees(satPos.azimuth).round(1) val azimuth = Math.toDegrees(satPos.azimuth).round(1)
val elevation = Math.toDegrees(satPos.elevation).round(1) val elevation = Math.toDegrees(satPos.elevation).round(1)
passReporter.reportRotation(azimuth, elevation) dataReporter.reportRotation(azimuth, elevation)
_passData.postValue(RadarData(satPos, satTrack)) _passData.postValue(RadarData(satPos, satTrack))
delay(1000) delay(1000)
} }
@@ -24,7 +24,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.ItemTransBinding import com.rtbishop.look4sat.databinding.ItemTransBinding
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.model.Transmitter
import java.util.* import java.util.*
class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder>() { class TransmittersAdapter : RecyclerView.Adapter<TransmittersAdapter.TransHolder>() {
@@ -29,7 +29,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.Preferences
import com.rtbishop.look4sat.framework.PreferencesSource import com.rtbishop.look4sat.framework.PreferencesSource
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
@@ -38,7 +37,7 @@ import javax.inject.Inject
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat() {
@Inject @Inject
lateinit var preferences: Preferences lateinit var preferences: PreferencesSource
private val requestPermissionLauncher = private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
@@ -25,8 +25,8 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.rtbishop.look4sat.R import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.Preferences
import com.rtbishop.look4sat.databinding.DialogSourcesBinding import com.rtbishop.look4sat.databinding.DialogSourcesBinding
import com.rtbishop.look4sat.framework.PreferencesSource
import com.rtbishop.look4sat.utility.setNavResult import com.rtbishop.look4sat.utility.setNavResult
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
@@ -35,7 +35,7 @@ import javax.inject.Inject
class SourcesDialog : AppCompatDialogFragment() { class SourcesDialog : AppCompatDialogFragment() {
@Inject @Inject
lateinit var prefsManager: Preferences lateinit var prefsManager: PreferencesSource
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
return inflater.inflate(R.layout.dialog_sources, group, false) return inflater.inflate(R.layout.dialog_sources, group, false)
@@ -1,18 +0,0 @@
package com.rtbishop.look4sat.utility
import android.app.Activity
class CustomHandler(private val activity: Activity) : Thread.UncaughtExceptionHandler {
private val rootHandler = Thread.getDefaultUncaughtExceptionHandler()
init {
Thread.setDefaultUncaughtExceptionHandler(this)
}
override fun uncaughtException(thread: Thread, throwable: Throwable) {
// Custom exception handling, use intents instead of dialogs
// Process.killProcess(Process.myPid())
// exitProcess(0)
}
}
+1 -1
View File
@@ -50,7 +50,7 @@
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<EditTextPreference <EditTextPreference
android:defaultValue="4096" android:defaultValue="4533"
android:dependency="isRotatorEnabled" android:dependency="isRotatorEnabled"
android:key="rotatorPort" android:key="rotatorPort"
android:title="@string/tracking_rotator_port" android:title="@string/tracking_rotator_port"
+2 -2
View File
@@ -1,7 +1,7 @@
buildscript { buildscript {
ext { ext {
gradle_version = '7.0.2' gradle_version = '7.0.2'
kotlin_version = '1.5.30' kotlin_version = '1.5.31'
coroutines_version = '1.5.2-native-mt' coroutines_version = '1.5.2-native-mt'
material_version = '1.4.0' material_version = '1.4.0'
splash_screen_version = '1.0.0-alpha01' splash_screen_version = '1.0.0-alpha01'
@@ -10,7 +10,7 @@ buildscript {
navigation_version = '2.3.5' navigation_version = '2.3.5'
preference_version = '1.1.1' preference_version = '1.1.1'
room_version = '2.3.0' room_version = '2.3.0'
hilt_version = '2.39' hilt_version = '2.39.1'
retrofit_version = '2.9.0' retrofit_version = '2.9.0'
osmdroid_version = '6.1.11' osmdroid_version = '6.1.11'
timber_version = '5.0.1' timber_version = '5.0.1'
@@ -0,0 +1,28 @@
/*
* 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.common
object Constants {
const val URL_BASE = "https://db.satnogs.org/api/"
const val URL_CELESTRAK = "https://celestrak.com/NORAD/elements/active.txt"
const val URL_AMSAT = "https://amsat.org/tle/current/nasabare.txt"
const val URL_PRISM_CLASSFD = "https://www.prismnet.com/~mmccants/tles/classfd.zip"
const val URL_PRISM_INTEL = "https://www.prismnet.com/~mmccants/tles/inttles.zip"
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.framework.model package com.rtbishop.look4sat.common
sealed class DataState<out T> { sealed class DataState<out T> {
data class Success<out T>(val data: T) : DataState<T>() data class Success<out T>(val data: T) : DataState<T>()
@@ -17,9 +17,12 @@
*/ */
package com.rtbishop.look4sat.data package com.rtbishop.look4sat.data
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.domain.Repository
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.model.SatEntry
import com.rtbishop.look4sat.domain.TLE import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.predict4kotlin.Satellite
import com.rtbishop.look4sat.predict4kotlin.TLE
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -28,38 +31,29 @@ import kotlinx.coroutines.withContext
import java.io.InputStream import java.io.InputStream
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
class SatelliteRepo( class DataRepository(
private val preferences: Preferences, private val localSource: LocalDataSource,
private val localSource: LocalSource, private val remoteSource: RemoteDataSource,
private val remoteSource: RemoteSource,
private val repoDispatcher: CoroutineDispatcher private val repoDispatcher: CoroutineDispatcher
) { ) : Repository {
fun saveSelectedModes(modes: List<String>) { override fun getSatItems(): Flow<List<SatItem>> {
preferences.saveModesSelection(modes)
}
fun loadSelectedModes(): List<String> {
return preferences.loadModesSelection()
}
fun getSatItems(): Flow<List<SatItem>> {
return localSource.getEntriesWithModes() return localSource.getEntriesWithModes()
} }
fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>> { override fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>> {
return localSource.getTransmitters(catNum) return localSource.getTransmitters(catNum)
} }
suspend fun getSelectedSatellites(): List<Satellite> { override suspend fun getSelectedSatellites(): List<Satellite> {
return localSource.getSelectedSatellites() return localSource.getSelectedSatellites()
} }
suspend fun updateEntriesFromFile(stream: InputStream) = withContext(repoDispatcher) { override suspend fun updateEntriesFromFile(stream: InputStream) = withContext(repoDispatcher) {
localSource.updateEntries(importSatEntries(stream)) localSource.updateEntries(importSatEntries(stream))
} }
suspend fun updateEntriesFromWeb(sources: List<String>) { override suspend fun updateEntriesFromWeb(sources: List<String>) {
coroutineScope { coroutineScope {
launch(repoDispatcher) { launch(repoDispatcher) {
val streams = mutableListOf<InputStream>() val streams = mutableListOf<InputStream>()
@@ -84,7 +78,7 @@ class SatelliteRepo(
} }
} }
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) { override suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
localSource.updateEntriesSelection(catNums, isSelected) localSource.updateEntriesSelection(catNums, isSelected)
} }
@@ -17,11 +17,13 @@
*/ */
package com.rtbishop.look4sat.data package com.rtbishop.look4sat.data
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.model.SatEntry
import com.rtbishop.look4sat.domain.Satellite import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.predict4kotlin.Satellite
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface LocalSource { interface LocalDataSource {
fun getEntriesWithModes(): Flow<List<SatItem>> fun getEntriesWithModes(): Flow<List<SatItem>>
@@ -1,63 +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.data
import com.rtbishop.look4sat.domain.GeoPos
interface Preferences {
fun positionToQTH(lat: Double, lon: Double): String?
fun loadStationPosition(): GeoPos
fun saveStationPosition(pos: GeoPos)
fun updatePositionFromGPS(): Boolean
fun updatePositionFromQTH(qthString: String): Boolean
fun getMagDeclination(): Float
fun getHoursAhead(): Int
fun getMinElevation(): Double
fun shouldUseTextLabels(): Boolean
fun shouldUseUTC(): Boolean
fun shouldUseCompass(): Boolean
fun shouldShowSweep(): Boolean
fun isSetupDone(): Boolean
fun setSetupDone()
fun saveModesSelection(modes: List<String>)
fun loadModesSelection(): List<String>
fun getRotatorServer(): Pair<String, Int>?
fun loadTleSources(): List<String>
fun saveTleSources(sources: List<String>)
fun loadDefaultSources(): List<String>
}
@@ -17,10 +17,10 @@
*/ */
package com.rtbishop.look4sat.data package com.rtbishop.look4sat.data
import com.rtbishop.look4sat.domain.Transmitter import com.rtbishop.look4sat.model.Transmitter
import java.io.InputStream import java.io.InputStream
interface RemoteSource { interface RemoteDataSource {
suspend fun fetchFileStream(url: String): InputStream? suspend fun fetchFileStream(url: String): InputStream?
@@ -1,3 +1,20 @@
/*
* 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.domain package com.rtbishop.look4sat.domain
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
@@ -5,7 +22,7 @@ import kotlinx.coroutines.withContext
import java.io.BufferedWriter import java.io.BufferedWriter
import java.net.Socket import java.net.Socket
class PassReporter(private val reporterDispatcher: CoroutineDispatcher) { class DataReporter(private val reporterDispatcher: CoroutineDispatcher) {
private var radioSocket: Socket? = null private var radioSocket: Socket? = null
private var radioWriter: BufferedWriter? = null private var radioWriter: BufferedWriter? = null
@@ -17,6 +17,7 @@
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.predict4kotlin.GeoPos
import kotlin.math.round import kotlin.math.round
object QthConverter { object QthConverter {
@@ -0,0 +1,39 @@
/*
* 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.domain
import com.rtbishop.look4sat.model.SatItem
import com.rtbishop.look4sat.model.Transmitter
import com.rtbishop.look4sat.predict4kotlin.Satellite
import kotlinx.coroutines.flow.Flow
import java.io.InputStream
interface Repository {
fun getSatItems(): Flow<List<SatItem>>
fun getSatTransmitters(catNum: Int): Flow<List<Transmitter>>
suspend fun getSelectedSatellites(): List<Satellite>
suspend fun updateEntriesFromFile(stream: InputStream)
suspend fun updateEntriesFromWeb(sources: List<String>)
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
}
@@ -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.model
data class OMM(
val name: String,
val epochString: String,
val meanmo: Double,
val eccn: Double,
val incl: Double,
val raan: Double,
val argper: Double,
val meanan: Double,
val catnum: Int,
val bstar: Double,
)
@@ -15,9 +15,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.data package com.rtbishop.look4sat.model
import com.rtbishop.look4sat.domain.TLE import com.rtbishop.look4sat.predict4kotlin.TLE
data class SatEntry( data class SatEntry(
val tle: TLE, val tle: TLE,
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.data package com.rtbishop.look4sat.model
data class SatItem( data class SatItem(
val catNum: Int, val catNum: Int,
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.model
data class Transmitter( data class Transmitter(
val uuid: String, val uuid: String,
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import kotlin.math.* import kotlin.math.*
@@ -15,6 +15,6 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
data class GeoPos(val latitude: Double, val longitude: Double, val altitude: Double = 0.0) data class GeoPos(val latitude: Double, val longitude: Double, val altitude: Double = 0.0)
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import kotlin.math.* import kotlin.math.*
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import com.rtbishop.look4sat.domain.* import com.rtbishop.look4sat.domain.*
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
data class SatPass( data class SatPass(
val aosTime: Long, val aosTime: Long,
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import kotlin.math.* import kotlin.math.*
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat.domain package com.rtbishop.look4sat.predict4kotlin
import java.io.InputStream import java.io.InputStream
import kotlin.math.pow import kotlin.math.pow
@@ -0,0 +1,24 @@
/*
* 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.usecases
import com.rtbishop.look4sat.domain.Repository
class GetSelectedSatellites(private val dataRepository: Repository) {
suspend operator fun invoke() = dataRepository.getSelectedSatellites()
}
@@ -15,9 +15,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.rtbishop.look4sat package com.rtbishop.look4sat.domain
import com.rtbishop.look4sat.domain.QthConverter
import org.junit.Test import org.junit.Test
class QthConverterTest { class QthConverterTest {
@@ -1,6 +1,22 @@
package com.rtbishop.look4sat /*
* 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.predict4kotlin
import com.rtbishop.look4sat.domain.TLE
import org.junit.Test import org.junit.Test
class TleParserTest { class TleParserTest {