mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Moved from a file-based TLE storage to a Room-based one. Fixed entries selection issue.
This commit is contained in:
1 parent
0188248bc1
commit
cf86892ad5
47 files changed
+806
-684
No files matched your search
@@ -72,6 +72,7 @@ dependencies {
|
|||||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle"
|
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle"
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle"
|
||||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle"
|
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle"
|
||||||
|
|
||||||
// room
|
// room
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
package com.rtbishop.look4sat
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.rtbishop.look4sat.di.AppComponent
|
import com.rtbishop.look4sat.dagger.AppComponent
|
||||||
import com.rtbishop.look4sat.di.DaggerAppComponent
|
import com.rtbishop.look4sat.dagger.DaggerAppComponent
|
||||||
|
|
||||||
class Look4SatApp : Application() {
|
class Look4SatApp : Application() {
|
||||||
|
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.github.amsacode.predict4java.GroundStationPosition
|
|
||||||
import com.github.amsacode.predict4java.SatNotFoundException
|
|
||||||
import com.github.amsacode.predict4java.TLE
|
|
||||||
import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
|
||||||
import com.rtbishop.look4sat.repo.Repository
|
|
||||||
import com.rtbishop.look4sat.repo.SatPass
|
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
|
||||||
import com.rtbishop.look4sat.utility.DataManager
|
|
||||||
import com.rtbishop.look4sat.utility.PrefsManager
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|
||||||
|
|
||||||
private val app = application
|
|
||||||
private val urlList = listOf("https://celestrak.com/NORAD/elements/active.txt")
|
|
||||||
private val _satPassList = MutableLiveData<MutableList<SatPass>>()
|
|
||||||
private val _debugMessage = MutableLiveData<String>()
|
|
||||||
private val _gsp = MutableLiveData<GroundStationPosition>()
|
|
||||||
private val _isListRefreshing = MutableLiveData<Boolean>()
|
|
||||||
private var calculationJob: Job? = null
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var repository: Repository
|
|
||||||
@Inject
|
|
||||||
lateinit var dataManager: DataManager
|
|
||||||
@Inject
|
|
||||||
lateinit var prefsManager: PrefsManager
|
|
||||||
|
|
||||||
init {
|
|
||||||
(app as Look4SatApp).appComponent.inject(this)
|
|
||||||
setGroundStationPosition()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isFirstLaunch = true
|
|
||||||
var tleMainList = dataManager.loadTleList()
|
|
||||||
var tleSelection = dataManager.loadSelectionList()
|
|
||||||
|
|
||||||
fun getGSP(): LiveData<GroundStationPosition> = _gsp
|
|
||||||
fun getDebugMessage(): LiveData<String> = _debugMessage
|
|
||||||
fun getSatPassList(): LiveData<MutableList<SatPass>> = _satPassList
|
|
||||||
fun getRefreshing(): LiveData<Boolean> = _isListRefreshing
|
|
||||||
fun getRefreshRate() = prefsManager.getRefreshRate()
|
|
||||||
fun getHoursAhead() = prefsManager.getHoursAhead()
|
|
||||||
fun getMinElevation() = prefsManager.getMinElevation()
|
|
||||||
fun setGroundStationPosition() = _gsp.postValue(prefsManager.getGroundStationPosition())
|
|
||||||
|
|
||||||
fun updateLocation() {
|
|
||||||
dataManager.getLastKnownLocation()?.let {
|
|
||||||
prefsManager.setGroundStationPosition(it)
|
|
||||||
_gsp.postValue(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
|
||||||
prefsManager.setHoursAhead(hoursAhead)
|
|
||||||
prefsManager.setMinElevation(minEl)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateAndSaveTleFile() {
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
val inputStream = repository.getStreamForUrl(urlList)
|
|
||||||
val tleList = TLE.importSat(inputStream).apply { sortBy { it.name } }
|
|
||||||
dataManager.saveTleList(tleList)
|
|
||||||
tleMainList = tleList
|
|
||||||
updateAndSaveSelectionList(mutableListOf())
|
|
||||||
_debugMessage.postValue(app.getString(R.string.update_tle_success))
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
_debugMessage.postValue(app.getString(R.string.update_failure))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateTransmittersDatabase() {
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
repository.updateTransmittersDatabase()
|
|
||||||
_debugMessage.postValue(app.getString(R.string.update_trans_success))
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
_debugMessage.postValue(app.getString(R.string.update_failure))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateAndSaveSelectionList(list: MutableList<Int>) {
|
|
||||||
tleSelection = list
|
|
||||||
dataManager.saveSelectionList(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPasses() {
|
|
||||||
_isListRefreshing.value = true
|
|
||||||
calculationJob?.cancel()
|
|
||||||
var passList = mutableListOf<SatPass>()
|
|
||||||
calculationJob = viewModelScope.launch {
|
|
||||||
if (tleMainList.isNotEmpty() && tleSelection.isNotEmpty()) {
|
|
||||||
withContext(Dispatchers.Default) {
|
|
||||||
val dateNow = Date()
|
|
||||||
tleSelection.forEach { indexOfSelection ->
|
|
||||||
val tle = tleMainList[indexOfSelection]
|
|
||||||
try {
|
|
||||||
val gsp = getGSP().value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
|
||||||
val predictor = PassPredictor(tle, gsp)
|
|
||||||
val passes = predictor.getPasses(dateNow, getHoursAhead(), true)
|
|
||||||
passes.forEach {
|
|
||||||
passList.add(SatPass(tle, predictor, it))
|
|
||||||
}
|
|
||||||
} catch (exception: IllegalArgumentException) {
|
|
||||||
_debugMessage.postValue(app.getString(R.string.err_parse_tle))
|
|
||||||
} catch (exception: SatNotFoundException) {
|
|
||||||
_debugMessage.postValue(app.getString(R.string.err_sat_wont_pass))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
passList = filterAndSortList(passList, getHoursAhead())
|
|
||||||
}
|
|
||||||
_satPassList.postValue(passList)
|
|
||||||
} else {
|
|
||||||
_satPassList.postValue(mutableListOf())
|
|
||||||
_debugMessage.postValue(app.getString(R.string.err_no_sat_selected))
|
|
||||||
}
|
|
||||||
_isListRefreshing.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun filterAndSortList(
|
|
||||||
list: MutableList<SatPass>,
|
|
||||||
hoursAhead: Int
|
|
||||||
): MutableList<SatPass> {
|
|
||||||
val dateNow = Date()
|
|
||||||
val dateFuture = Calendar.getInstance().let {
|
|
||||||
it.time = dateNow
|
|
||||||
it.add(Calendar.HOUR, hoursAhead)
|
|
||||||
it.time
|
|
||||||
}
|
|
||||||
list.removeAll { it.pass.startTime.after(dateFuture) }
|
|
||||||
list.removeAll { it.pass.endTime.before(dateNow) }
|
|
||||||
list.removeAll { it.pass.maxEl < getMinElevation() }
|
|
||||||
list.sortBy { it.pass.startTime }
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
|
||||||
return repository.getTransmittersForSat(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+14
-4
@@ -17,16 +17,23 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.di
|
package com.rtbishop.look4sat.dagger
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
import com.rtbishop.look4sat.dagger.modules.*
|
||||||
|
import com.rtbishop.look4sat.ui.MainActivity
|
||||||
|
import com.rtbishop.look4sat.ui.fragments.MapViewFragment
|
||||||
|
import com.rtbishop.look4sat.ui.fragments.PassListFragment
|
||||||
|
import com.rtbishop.look4sat.ui.fragments.PolarViewFragment
|
||||||
import dagger.BindsInstance
|
import dagger.BindsInstance
|
||||||
import dagger.Component
|
import dagger.Component
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = [AndroidModule::class, NetworkModule::class, StorageModule::class, UtilityModule::class])
|
@Component(
|
||||||
|
modules = [NetworkModule::class, PersistenceModule::class,
|
||||||
|
RepoModule::class, UtilityModule::class, ViewModelModule::class]
|
||||||
|
)
|
||||||
interface AppComponent {
|
interface AppComponent {
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
@@ -34,5 +41,8 @@ interface AppComponent {
|
|||||||
fun create(@BindsInstance context: Context): AppComponent
|
fun create(@BindsInstance context: Context): AppComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
fun inject(viewModel: MainViewModel)
|
fun inject(mainActivity: MainActivity)
|
||||||
|
fun inject(mapViewFragment: MapViewFragment)
|
||||||
|
fun inject(passListFragment: PassListFragment)
|
||||||
|
fun inject(polarViewFragment: PolarViewFragment)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.rtbishop.look4sat.dagger
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ViewModelFactory @Inject constructor(
|
||||||
|
private val creators: Map<Class<out ViewModel>,
|
||||||
|
@JvmSuppressWildcards Provider<ViewModel>>
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||||
|
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
|
||||||
|
modelClass.isAssignableFrom(it.key)
|
||||||
|
}?.value ?: throw IllegalArgumentException("Unsupported ViewModel class: $modelClass")
|
||||||
|
try {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return creator.get() as T
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.rtbishop.look4sat.dagger
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import dagger.MapKey
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Target(
|
||||||
|
AnnotationTarget.FUNCTION,
|
||||||
|
AnnotationTarget.PROPERTY_GETTER,
|
||||||
|
AnnotationTarget.PROPERTY_SETTER
|
||||||
|
)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@MapKey
|
||||||
|
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
||||||
+15
-7
@@ -17,8 +17,10 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.di
|
package com.rtbishop.look4sat.dagger.modules
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.network.RemoteDataSource
|
||||||
|
import com.rtbishop.look4sat.network.RemoteSource
|
||||||
import com.rtbishop.look4sat.network.TransmittersApi
|
import com.rtbishop.look4sat.network.TransmittersApi
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
@@ -30,6 +32,18 @@ import javax.inject.Singleton
|
|||||||
@Module
|
@Module
|
||||||
class NetworkModule {
|
class NetworkModule {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideOkHttpClient(): OkHttpClient {
|
||||||
|
return OkHttpClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideRemoteDataSource(api: TransmittersApi, client: OkHttpClient): RemoteSource {
|
||||||
|
return RemoteDataSource(api, client)
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideTransmittersApi(): TransmittersApi {
|
fun provideTransmittersApi(): TransmittersApi {
|
||||||
@@ -39,10 +53,4 @@ class NetworkModule {
|
|||||||
.build()
|
.build()
|
||||||
.create(TransmittersApi::class.java)
|
.create(TransmittersApi::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideOkHttpClient(): OkHttpClient {
|
|
||||||
return OkHttpClient()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+26
-8
@@ -17,29 +17,47 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.di
|
package com.rtbishop.look4sat.dagger.modules
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import com.rtbishop.look4sat.storage.TransmittersDao
|
import com.rtbishop.look4sat.persistence.LocalDataSource
|
||||||
import com.rtbishop.look4sat.storage.TransmittersDb
|
import com.rtbishop.look4sat.persistence.LocalSource
|
||||||
|
import com.rtbishop.look4sat.persistence.SatelliteDb
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class StorageModule {
|
class PersistenceModule {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideTransmittersDb(context: Context): TransmittersDb {
|
fun provideEntriesDao(db: SatelliteDb): EntriesDao {
|
||||||
return Room.databaseBuilder(context, TransmittersDb::class.java, "transmitters")
|
return db.entriesDao()
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideTransmittersDao(db: TransmittersDb): TransmittersDao {
|
fun provideTransmittersDao(db: SatelliteDb): TransmittersDao {
|
||||||
return db.transmittersDao()
|
return db.transmittersDao()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideLocalDataSource(
|
||||||
|
entriesDao: EntriesDao,
|
||||||
|
transmittersDao: TransmittersDao
|
||||||
|
): LocalSource {
|
||||||
|
return LocalDataSource(entriesDao, transmittersDao)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideSatelliteDb(context: Context): SatelliteDb {
|
||||||
|
return Room.databaseBuilder(context, SatelliteDb::class.java, "satellites")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.rtbishop.look4sat.dagger.modules
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.network.RemoteSource
|
||||||
|
import com.rtbishop.look4sat.persistence.LocalSource
|
||||||
|
import com.rtbishop.look4sat.repo.DefaultRepository
|
||||||
|
import com.rtbishop.look4sat.repo.Repository
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class RepoModule {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideDefaultRepository(localSource: LocalSource, remoteSource: RemoteSource): Repository {
|
||||||
|
return DefaultRepository(localSource, remoteSource)
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-2
@@ -17,18 +17,19 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.di
|
package com.rtbishop.look4sat.dagger.modules
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.rtbishop.look4sat.utility.PrefsManager
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class AndroidModule {
|
class UtilityModule {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
@@ -41,4 +42,13 @@ class AndroidModule {
|
|||||||
fun provideLocationManager(context: Context): LocationManager {
|
fun provideLocationManager(context: Context): LocationManager {
|
||||||
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun providePrefsManager(
|
||||||
|
sharedPreferences: SharedPreferences,
|
||||||
|
locationManager: LocationManager
|
||||||
|
): PrefsManager {
|
||||||
|
return PrefsManager(sharedPreferences, locationManager)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.rtbishop.look4sat.dagger.modules
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelKey
|
||||||
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.multibindings.IntoMap
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class ViewModelModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(SharedViewModel::class)
|
||||||
|
abstract fun bindSharedViewModel(viewModel: SharedViewModel): ViewModel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.amsacode.predict4java.TLE
|
||||||
|
|
||||||
|
@Entity(tableName = "entries")
|
||||||
|
data class SatEntry(val tle: TLE, var isSelected: Boolean = false) {
|
||||||
|
@PrimaryKey
|
||||||
|
var catNum: Int = tle.catnum
|
||||||
|
var name: String = tle.name
|
||||||
|
}
|
||||||
+2
-2
@@ -17,11 +17,11 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.repo
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import com.github.amsacode.predict4java.SatPassTime
|
import com.github.amsacode.predict4java.SatPassTime
|
||||||
import com.github.amsacode.predict4java.TLE
|
import com.github.amsacode.predict4java.TLE
|
||||||
import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
|
|
||||||
data class SatPass(
|
data class SatPass(
|
||||||
val tle: TLE,
|
val tle: TLE,
|
||||||
+2
-2
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.repo
|
package com.rtbishop.look4sat.data
|
||||||
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
@@ -34,5 +34,5 @@ data class Transmitter(
|
|||||||
@SerializedName("downlink_high") val downlinkHigh: Long?,
|
@SerializedName("downlink_high") val downlinkHigh: Long?,
|
||||||
@SerializedName("mode") val mode: String?,
|
@SerializedName("mode") val mode: String?,
|
||||||
@SerializedName("invert") val isInverted: Boolean,
|
@SerializedName("invert") val isInverted: Boolean,
|
||||||
@SerializedName("norad_cat_id") val noradCatId: Int
|
@SerializedName("norad_cat_id") val catNum: Int
|
||||||
)
|
)
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat.di
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.location.LocationManager
|
|
||||||
import com.rtbishop.look4sat.utility.DataManager
|
|
||||||
import com.rtbishop.look4sat.utility.PrefsManager
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class UtilityModule {
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun providePrefsManager(preferences: SharedPreferences): PrefsManager {
|
|
||||||
return PrefsManager(preferences)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideDataManager(locationManager: LocationManager, context: Context): DataManager {
|
|
||||||
return DataManager(locationManager, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,11 +19,13 @@
|
|||||||
|
|
||||||
package com.rtbishop.look4sat.network
|
package com.rtbishop.look4sat.network
|
||||||
|
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
import android.util.Log
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.SequenceInputStream
|
import java.io.SequenceInputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -32,20 +34,25 @@ import javax.inject.Inject
|
|||||||
class RemoteDataSource @Inject constructor(
|
class RemoteDataSource @Inject constructor(
|
||||||
private val api: TransmittersApi,
|
private val api: TransmittersApi,
|
||||||
private val client: OkHttpClient
|
private val client: OkHttpClient
|
||||||
) {
|
) : RemoteSource {
|
||||||
suspend fun getStreamForUrl(urlList: List<String>): InputStream {
|
|
||||||
|
override suspend fun fetchTleStream(urlList: List<String>): InputStream {
|
||||||
val streamTable = Hashtable<String, InputStream>()
|
val streamTable = Hashtable<String, InputStream>()
|
||||||
withContext(Dispatchers.IO) {
|
try {
|
||||||
urlList.forEach {
|
withContext(Dispatchers.IO) {
|
||||||
val request = Request.Builder().url(it).build()
|
urlList.forEach {
|
||||||
val stream = client.newCall(request).execute().body()?.byteStream()!!
|
val request = Request.Builder().url(it).build()
|
||||||
streamTable[it] = stream
|
val stream = client.newCall(request).execute().body()?.byteStream()
|
||||||
|
streamTable[it] = stream
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w("remoteDataSource", e.toString())
|
||||||
}
|
}
|
||||||
return SequenceInputStream(streamTable.elements())
|
return SequenceInputStream(streamTable.elements())
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchTransmittersList(): List<Transmitter> {
|
override suspend fun fetchTransmitters(): List<Transmitter> {
|
||||||
return api.fetchTransmittersList()
|
return api.fetchTransmitters()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.rtbishop.look4sat.network
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
interface RemoteSource {
|
||||||
|
|
||||||
|
suspend fun fetchTleStream(urlList: List<String>): InputStream
|
||||||
|
|
||||||
|
suspend fun fetchTransmitters(): List<Transmitter>
|
||||||
|
}
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
package com.rtbishop.look4sat.network
|
package com.rtbishop.look4sat.network
|
||||||
|
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
|
||||||
interface TransmittersApi {
|
interface TransmittersApi {
|
||||||
|
|
||||||
@GET("transmitters/")
|
@GET("transmitters/")
|
||||||
suspend fun fetchTransmittersList(): List<Transmitter>
|
suspend fun fetchTransmitters(): List<Transmitter>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.persistence
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LocalDataSource @Inject constructor(
|
||||||
|
private val entriesDao: EntriesDao,
|
||||||
|
private val transmittersDao: TransmittersDao
|
||||||
|
) : LocalSource {
|
||||||
|
|
||||||
|
override suspend fun insertEntries(entries: List<SatEntry>) {
|
||||||
|
entriesDao.insertEntries(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAllEntries(): List<SatEntry> {
|
||||||
|
return entriesDao.getAllEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSelectedEntries(): List<SatEntry> {
|
||||||
|
return entriesDao.getSelectedEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateEntriesSelection(entries: List<SatEntry>) {
|
||||||
|
entriesDao.updateEntriesSelection(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
override suspend fun insertTransmitters(transmitters: List<Transmitter>) {
|
||||||
|
transmittersDao.insertTransmitters(transmitters)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter> {
|
||||||
|
return transmittersDao.getTransmittersByCatNum(catNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.rtbishop.look4sat.persistence
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
|
||||||
|
interface LocalSource {
|
||||||
|
|
||||||
|
suspend fun insertEntries(entries: List<SatEntry>)
|
||||||
|
|
||||||
|
suspend fun getAllEntries(): List<SatEntry>
|
||||||
|
|
||||||
|
suspend fun getSelectedEntries(): List<SatEntry>
|
||||||
|
|
||||||
|
suspend fun updateEntriesSelection(entries: List<SatEntry>)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
suspend fun insertTransmitters(transmitters: List<Transmitter>)
|
||||||
|
|
||||||
|
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||||
|
}
|
||||||
+12
-4
@@ -17,14 +17,22 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.storage
|
package com.rtbishop.look4sat.persistence
|
||||||
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
import androidx.room.TypeConverters
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||||
|
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||||
|
import com.rtbishop.look4sat.utility.Converters
|
||||||
|
|
||||||
@Database(entities = [Transmitter::class], version = 1, exportSchema = false)
|
@Database(entities = [Transmitter::class, SatEntry::class], version = 1, exportSchema = false)
|
||||||
abstract class TransmittersDb : RoomDatabase() {
|
@TypeConverters(Converters::class)
|
||||||
|
abstract class SatelliteDb : RoomDatabase() {
|
||||||
|
|
||||||
|
abstract fun entriesDao(): EntriesDao
|
||||||
|
|
||||||
abstract fun transmittersDao(): TransmittersDao
|
abstract fun transmittersDao(): TransmittersDao
|
||||||
}
|
}
|
||||||
+13
-10
@@ -17,20 +17,23 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.storage
|
package com.rtbishop.look4sat.persistence.dao
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.*
|
||||||
import androidx.room.Insert
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface TransmittersDao {
|
interface EntriesDao {
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertTransmitters(transmitters: List<Transmitter>)
|
suspend fun insertEntries(entries: List<SatEntry>)
|
||||||
|
|
||||||
@Query("SELECT * FROM transmitters WHERE isAlive = 1 and noradCatId = :id")
|
@Query("SELECT * FROM entries ORDER BY name ASC")
|
||||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter>
|
suspend fun getAllEntries(): List<SatEntry>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM entries WHERE isSelected = 1 ORDER BY name ASC")
|
||||||
|
suspend fun getSelectedEntries(): List<SatEntry>
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun updateEntriesSelection(entries: List<SatEntry>)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.rtbishop.look4sat.persistence.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface TransmittersDao {
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertTransmitters(transmitters: List<Transmitter>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM transmitters WHERE isAlive = 1 and catNum = :catNum")
|
||||||
|
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.repo
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.github.amsacode.predict4java.TLE
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
|
import com.rtbishop.look4sat.network.RemoteSource
|
||||||
|
import com.rtbishop.look4sat.persistence.LocalSource
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DefaultRepository @Inject constructor(
|
||||||
|
private val localSource: LocalSource,
|
||||||
|
private val remoteSource: RemoteSource
|
||||||
|
) : Repository {
|
||||||
|
|
||||||
|
private val tag = "defaultRepository"
|
||||||
|
|
||||||
|
override suspend fun updateEntriesFrom(urlList: List<String>) {
|
||||||
|
val stream = remoteSource.fetchTleStream(urlList)
|
||||||
|
try {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val tleList = TLE.importSat(stream)
|
||||||
|
val entries = tleList.map { SatEntry(it) }
|
||||||
|
localSource.insertEntries(entries)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(tag, e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAllEntries(): List<SatEntry> {
|
||||||
|
return localSource.getAllEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSelectedEntries(): List<SatEntry> {
|
||||||
|
return localSource.getSelectedEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateEntriesSelection(entries: List<SatEntry>) {
|
||||||
|
localSource.updateEntriesSelection(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
override suspend fun updateTransmitters() {
|
||||||
|
try {
|
||||||
|
val list = remoteSource.fetchTransmitters()
|
||||||
|
localSource.insertTransmitters(list)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w(tag, e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter> {
|
||||||
|
return localSource.getTransmittersByCatNum(catNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +1,21 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat.repo
|
package com.rtbishop.look4sat.repo
|
||||||
|
|
||||||
import com.rtbishop.look4sat.network.RemoteDataSource
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
import com.rtbishop.look4sat.storage.LocalDataSource
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
import java.io.InputStream
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class Repository @Inject constructor(
|
interface Repository {
|
||||||
private val localSource: LocalDataSource,
|
|
||||||
private val remoteSource: RemoteDataSource
|
|
||||||
) {
|
|
||||||
suspend fun getStreamForUrl(urlList: List<String>): InputStream {
|
|
||||||
return remoteSource.getStreamForUrl(urlList)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun updateTransmittersDatabase() {
|
suspend fun updateEntriesFrom(urlList: List<String>)
|
||||||
localSource.insertTransmitters(remoteSource.fetchTransmittersList())
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
suspend fun getAllEntries(): List<SatEntry>
|
||||||
return localSource.getTransmittersForSat(id)
|
|
||||||
}
|
suspend fun getSelectedEntries(): List<SatEntry>
|
||||||
|
|
||||||
|
suspend fun updateEntriesSelection(entries: List<SatEntry>)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
suspend fun updateTransmitters()
|
||||||
|
|
||||||
|
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||||
}
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat.repo
|
|
||||||
|
|
||||||
data class SatEntry(val id: Int, val name: String, var isSelected: Boolean = false)
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat.storage
|
|
||||||
|
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class LocalDataSource @Inject constructor(private val transmittersDao: TransmittersDao) {
|
|
||||||
|
|
||||||
suspend fun insertTransmitters(transmitters: List<Transmitter>) {
|
|
||||||
transmittersDao.insertTransmitters(transmitters)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
|
||||||
return transmittersDao.getTransmittersForSat(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,12 +40,14 @@ import androidx.navigation.ui.AppBarConfiguration
|
|||||||
import androidx.navigation.ui.navigateUp
|
import androidx.navigation.ui.navigateUp
|
||||||
import androidx.navigation.ui.setupActionBarWithNavController
|
import androidx.navigation.ui.setupActionBarWithNavController
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
import com.rtbishop.look4sat.Look4SatApp
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||||
import com.rtbishop.look4sat.databinding.DrawerHeaderBinding
|
import com.rtbishop.look4sat.databinding.DrawerHeaderBinding
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -54,19 +56,25 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private val permGranted = PackageManager.PERMISSION_GRANTED
|
private val permGranted = PackageManager.PERMISSION_GRANTED
|
||||||
private val githubUrl = "https://github.com/rt-bishop/LookingSat"
|
private val githubUrl = "https://github.com/rt-bishop/LookingSat"
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewModelFactory: ViewModelFactory
|
||||||
|
private lateinit var viewModel: SharedViewModel
|
||||||
private lateinit var mainBinding: ActivityMainBinding
|
private lateinit var mainBinding: ActivityMainBinding
|
||||||
private lateinit var drawerBinding: DrawerHeaderBinding
|
private lateinit var drawerBinding: DrawerHeaderBinding
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
private lateinit var appBarConfig: AppBarConfiguration
|
private lateinit var appBarConfig: AppBarConfiguration
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setTheme(R.style.AppTheme)
|
setTheme(R.style.AppTheme)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
mainBinding = ActivityMainBinding.inflate(layoutInflater)
|
mainBinding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
drawerBinding = DrawerHeaderBinding.inflate(layoutInflater, mainBinding.navView, true)
|
drawerBinding = DrawerHeaderBinding.inflate(layoutInflater, mainBinding.navView, true)
|
||||||
setContentView(mainBinding.root)
|
setContentView(mainBinding.root)
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
|
||||||
|
(application as Look4SatApp).appComponent.inject(this)
|
||||||
|
viewModel = ViewModelProvider(this, viewModelFactory).get(SharedViewModel::class.java)
|
||||||
|
|
||||||
setupComponents()
|
setupComponents()
|
||||||
setupObservers()
|
setupObservers()
|
||||||
setupDrawer()
|
setupDrawer()
|
||||||
@@ -108,10 +116,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers() {
|
private fun setupObservers() {
|
||||||
viewModel.getDebugMessage().observe(this, Observer { message ->
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.getGSP().observe(this, Observer { gsp ->
|
viewModel.getGSP().observe(this, Observer { gsp ->
|
||||||
drawerBinding.drawerLatValue.text =
|
drawerBinding.drawerLatValue.text =
|
||||||
String.format(getString(R.string.pat_location), gsp.latitude)
|
String.format(getString(R.string.pat_location), gsp.latitude)
|
||||||
@@ -126,11 +130,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
it.lockButton()
|
it.lockButton()
|
||||||
}
|
}
|
||||||
drawerBinding.drawerBtnTle.setOnClickListener {
|
drawerBinding.drawerBtnTle.setOnClickListener {
|
||||||
viewModel.updateAndSaveTleFile()
|
viewModel.updateEntries()
|
||||||
it.lockButton()
|
it.lockButton()
|
||||||
}
|
}
|
||||||
drawerBinding.drawerBtnTrans.setOnClickListener {
|
drawerBinding.drawerBtnTrans.setOnClickListener {
|
||||||
viewModel.updateTransmittersDatabase()
|
viewModel.updateTransmitters()
|
||||||
it.lockButton()
|
it.lockButton()
|
||||||
}
|
}
|
||||||
drawerBinding.drawerBtnGithub.setOnClickListener {
|
drawerBinding.drawerBtnGithub.setOnClickListener {
|
||||||
@@ -157,7 +161,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
ActivityCompat.requestPermissions(this, arrayOf(permLocation), permLocationCode)
|
ActivityCompat.requestPermissions(this, arrayOf(permLocation), permLocationCode)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.updateLocation()
|
viewModel.updatePosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +169,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
when (reqCode) {
|
when (reqCode) {
|
||||||
permLocationCode -> {
|
permLocationCode -> {
|
||||||
if (res.isNotEmpty() && res[0] == permGranted) {
|
if (res.isNotEmpty() && res[0] == permGranted) {
|
||||||
viewModel.updateLocation()
|
viewModel.updatePosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.ui
|
||||||
|
|
||||||
|
import androidx.lifecycle.*
|
||||||
|
import com.github.amsacode.predict4java.GroundStationPosition
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.SatPass
|
||||||
|
import com.rtbishop.look4sat.repo.Repository
|
||||||
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
|
import com.rtbishop.look4sat.utility.PrefsManager
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class SharedViewModel @Inject constructor(
|
||||||
|
private val prefsManager: PrefsManager,
|
||||||
|
private val repository: Repository
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
var isFirstLaunch = true
|
||||||
|
private var calculationJob: Job? = null
|
||||||
|
private val urlList = listOf("https://celestrak.com/NORAD/elements/active.txt")
|
||||||
|
|
||||||
|
private val _satPassList = MutableLiveData<MutableList<SatPass>>()
|
||||||
|
fun getSatPassList(): LiveData<MutableList<SatPass>> = _satPassList
|
||||||
|
|
||||||
|
private val _gsp = MutableLiveData(prefsManager.getPosition())
|
||||||
|
fun getGSP(): LiveData<GroundStationPosition> = _gsp
|
||||||
|
|
||||||
|
private val _isListRefreshing = MutableLiveData<Boolean>()
|
||||||
|
fun getRefreshing(): LiveData<Boolean> = _isListRefreshing
|
||||||
|
|
||||||
|
fun getRefreshRate() = prefsManager.getRefreshRate()
|
||||||
|
fun getHoursAhead() = prefsManager.getHoursAhead()
|
||||||
|
fun getMinElevation() = prefsManager.getMinElevation()
|
||||||
|
fun setPositionFromPref() = _gsp.postValue(prefsManager.getPosition())
|
||||||
|
|
||||||
|
fun getTransmittersForSat(id: Int) = liveData { emit(repository.getTransmittersByCatNum(id)) }
|
||||||
|
|
||||||
|
fun updateEntries() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val selected = repository.getSelectedEntries()
|
||||||
|
repository.updateEntriesFrom(urlList)
|
||||||
|
repository.updateEntriesSelection(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateEntriesSelection(entries: List<SatEntry>) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.updateEntriesSelection(entries)
|
||||||
|
calculatePasses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePosition() {
|
||||||
|
prefsManager.getLastKnownPosition().let {
|
||||||
|
prefsManager.setPosition(it)
|
||||||
|
_gsp.postValue(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateTransmitters() {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
repository.updateTransmitters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getAllEntries(): List<SatEntry> {
|
||||||
|
return repository.getAllEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculatePasses() {
|
||||||
|
_isListRefreshing.postValue(true)
|
||||||
|
calculationJob?.cancel()
|
||||||
|
var passList = mutableListOf<SatPass>()
|
||||||
|
val dateNow = Date()
|
||||||
|
val gsp = getGSP().value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
||||||
|
calculationJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
|
repository.getSelectedEntries().forEach {
|
||||||
|
passList.addAll(getPassesForEntries(it, dateNow, gsp))
|
||||||
|
}
|
||||||
|
passList = filterAndSortPasses(passList, dateNow, getHoursAhead())
|
||||||
|
_satPassList.postValue(passList)
|
||||||
|
_isListRefreshing.postValue(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
||||||
|
prefsManager.setHoursAhead(hoursAhead)
|
||||||
|
prefsManager.setMinElevation(minEl)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPassesForEntries(
|
||||||
|
entry: SatEntry,
|
||||||
|
dateNow: Date,
|
||||||
|
gsp: GroundStationPosition
|
||||||
|
): MutableList<SatPass> {
|
||||||
|
val passList = mutableListOf<SatPass>()
|
||||||
|
val predictor = PassPredictor(entry.tle, gsp)
|
||||||
|
val passes = predictor.getPasses(dateNow, getHoursAhead(), true)
|
||||||
|
passes.forEach { passList.add(SatPass(entry.tle, predictor, it)) }
|
||||||
|
return passList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filterAndSortPasses(
|
||||||
|
passes: MutableList<SatPass>,
|
||||||
|
dateNow: Date,
|
||||||
|
hoursAhead: Int
|
||||||
|
): MutableList<SatPass> {
|
||||||
|
val dateFuture = Calendar.getInstance().let {
|
||||||
|
it.time = dateNow
|
||||||
|
it.add(Calendar.HOUR, hoursAhead)
|
||||||
|
it.time
|
||||||
|
}
|
||||||
|
passes.removeAll { it.pass.startTime.after(dateFuture) }
|
||||||
|
passes.removeAll { it.pass.endTime.before(dateNow) }
|
||||||
|
passes.removeAll { it.pass.maxEl < getMinElevation() }
|
||||||
|
passes.sortBy { it.pass.startTime }
|
||||||
|
return passes
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,10 +23,10 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
import com.rtbishop.look4sat.databinding.ItemSatEntryBinding
|
import com.rtbishop.look4sat.databinding.ItemSatEntryBinding
|
||||||
import com.rtbishop.look4sat.repo.SatEntry
|
|
||||||
|
|
||||||
internal class SatEntryAdapter(private var entriesList: MutableList<SatEntry>) :
|
class SatEntryAdapter(private var entries: MutableList<SatEntry>) :
|
||||||
RecyclerView.Adapter<SatEntryAdapter.SatEntryHolder>() {
|
RecyclerView.Adapter<SatEntryAdapter.SatEntryHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatEntryHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatEntryHolder {
|
||||||
@@ -36,25 +36,27 @@ internal class SatEntryAdapter(private var entriesList: MutableList<SatEntry>) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: SatEntryHolder, position: Int) {
|
override fun onBindViewHolder(holder: SatEntryHolder, position: Int) {
|
||||||
holder.bind(entriesList[position])
|
holder.bind(entries[position])
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return entriesList.size
|
return entries.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEntries(entries: MutableList<SatEntry>) {
|
fun setEntries(list: MutableList<SatEntry>) {
|
||||||
entriesList = entries
|
entries = list
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) :
|
inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) :
|
||||||
RecyclerView.ViewHolder(itemView) {
|
RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
fun bind(satEntry: SatEntry) {
|
fun bind(satEntry: SatEntry) {
|
||||||
binding.satEntryCheckbox.text = satEntry.name
|
binding.satEntryCheckbox.text = satEntry.name
|
||||||
binding.satEntryCheckbox.isChecked = satEntry.isSelected
|
binding.satEntryCheckbox.isChecked = satEntry.isSelected
|
||||||
itemView.setOnClickListener { satEntry.isSelected = binding.satEntryCheckbox.isChecked }
|
itemView.setOnClickListener {
|
||||||
|
satEntry.isSelected = binding.satEntryCheckbox.isChecked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,16 +25,16 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.data.SatPass
|
||||||
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.repo.SatPass
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
import com.rtbishop.look4sat.ui.PassListFragmentDirections
|
import com.rtbishop.look4sat.ui.fragments.PassListFragmentDirections
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SatPassAdapter(val viewModel: MainViewModel) :
|
class SatPassAdapter(val viewModel: SharedViewModel) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private var satPassList = mutableListOf<SatPass>()
|
private var satPassList = mutableListOf<SatPass>()
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.data.Transmitter
|
||||||
import com.rtbishop.look4sat.databinding.ItemTransmitterBinding
|
import com.rtbishop.look4sat.databinding.ItemTransmitterBinding
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
|
||||||
|
|
||||||
class TransmitterAdapter : RecyclerView.Adapter<TransmitterAdapter.TransmitterHolder>() {
|
class TransmitterAdapter : RecyclerView.Adapter<TransmitterAdapter.TransmitterHolder>() {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
+13
-6
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.*
|
import android.graphics.*
|
||||||
@@ -33,20 +33,26 @@ import com.github.amsacode.predict4java.GroundStationPosition
|
|||||||
import com.github.amsacode.predict4java.Position
|
import com.github.amsacode.predict4java.Position
|
||||||
import com.github.amsacode.predict4java.SatPos
|
import com.github.amsacode.predict4java.SatPos
|
||||||
import com.github.amsacode.predict4java.TLE
|
import com.github.amsacode.predict4java.TLE
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
import com.rtbishop.look4sat.Look4SatApp
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||||
|
import com.rtbishop.look4sat.data.SatPass
|
||||||
import com.rtbishop.look4sat.databinding.FragmentMapViewBinding
|
import com.rtbishop.look4sat.databinding.FragmentMapViewBinding
|
||||||
import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
import com.rtbishop.look4sat.ui.MainActivity
|
||||||
import com.rtbishop.look4sat.repo.SatPass
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var modelFactory: ViewModelFactory
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: SharedViewModel
|
||||||
private lateinit var mapView: MapView
|
private lateinit var mapView: MapView
|
||||||
private lateinit var predictor: PassPredictor
|
private lateinit var predictor: PassPredictor
|
||||||
private lateinit var selectedSat: TLE
|
private lateinit var selectedSat: TLE
|
||||||
@@ -58,7 +64,8 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val binding = FragmentMapViewBinding.bind(view)
|
val binding = FragmentMapViewBinding.bind(view)
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||||
|
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||||
gsp = viewModel.getGSP().value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
gsp = viewModel.getGSP().value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
||||||
satPassList = viewModel.getSatPassList().value ?: emptyList()
|
satPassList = viewModel.getSatPassList().value ?: emptyList()
|
||||||
|
|
||||||
+56
-59
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
@@ -30,68 +30,55 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
import com.github.amsacode.predict4java.TLE
|
import com.rtbishop.look4sat.Look4SatApp
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
|
import com.rtbishop.look4sat.data.SatPass
|
||||||
import com.rtbishop.look4sat.databinding.FragmentPassListBinding
|
import com.rtbishop.look4sat.databinding.FragmentPassListBinding
|
||||||
import com.rtbishop.look4sat.repo.SatEntry
|
import com.rtbishop.look4sat.ui.MainActivity
|
||||||
import com.rtbishop.look4sat.repo.SatPass
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
import com.rtbishop.look4sat.ui.adapters.SatPassAdapter
|
import com.rtbishop.look4sat.ui.adapters.SatPassAdapter
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
@Inject
|
||||||
|
lateinit var modelFactory: ViewModelFactory
|
||||||
|
private lateinit var viewModel: SharedViewModel
|
||||||
private lateinit var satPassAdapter: SatPassAdapter
|
private lateinit var satPassAdapter: SatPassAdapter
|
||||||
private lateinit var btnPassPrefs: ImageButton
|
private lateinit var btnPassPrefs: ImageButton
|
||||||
private lateinit var aosTimer: CountDownTimer
|
private lateinit var aosTimer: CountDownTimer
|
||||||
private lateinit var aosTimerText: TextView
|
private lateinit var aosTimerText: TextView
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
private var satPassList: MutableList<SatPass> = mutableListOf()
|
|
||||||
private var isTimerSet: Boolean = false
|
private var isTimerSet: Boolean = false
|
||||||
|
private var satPassList: MutableList<SatPass> = mutableListOf()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val fragmentBinding = FragmentPassListBinding.bind(view)
|
val binding = FragmentPassListBinding.bind(view)
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||||
|
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||||
satPassAdapter = SatPassAdapter(viewModel)
|
satPassAdapter = SatPassAdapter(viewModel)
|
||||||
aosTimerText = mainActivity.findViewById(R.id.toolbar_timer)
|
aosTimerText = mainActivity.findViewById(R.id.toolbar_timer)
|
||||||
btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter)
|
btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter)
|
||||||
|
|
||||||
setupComponents(fragmentBinding)
|
setupObservers(binding)
|
||||||
setupObservers(fragmentBinding)
|
setupComponents(binding)
|
||||||
|
|
||||||
if (viewModel.tleSelection.isNotEmpty() && viewModel.isFirstLaunch) {
|
if (viewModel.isFirstLaunch) {
|
||||||
viewModel.getPasses()
|
viewModel.calculatePasses()
|
||||||
viewModel.isFirstLaunch = false
|
viewModel.isFirstLaunch = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents(binding: FragmentPassListBinding) {
|
|
||||||
binding.recPassList.apply {
|
|
||||||
layoutManager = LinearLayoutManager(mainActivity)
|
|
||||||
adapter = satPassAdapter
|
|
||||||
isVerticalScrollBarEnabled = false
|
|
||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
|
||||||
}
|
|
||||||
satPassAdapter.setList(satPassList)
|
|
||||||
setTimer()
|
|
||||||
|
|
||||||
binding.refLayoutPassList.setProgressBackgroundColorSchemeResource(R.color.themeAccent)
|
|
||||||
binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark)
|
|
||||||
binding.refLayoutPassList.setOnRefreshListener { viewModel.getPasses() }
|
|
||||||
btnPassPrefs.setOnClickListener {
|
|
||||||
showSatPassPrefsDialog(viewModel.getHoursAhead(), viewModel.getMinElevation())
|
|
||||||
}
|
|
||||||
binding.fabSatSelect.setOnClickListener {
|
|
||||||
showSelectSatDialog(viewModel.tleMainList, viewModel.tleSelection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupObservers(binding: FragmentPassListBinding) {
|
private fun setupObservers(binding: FragmentPassListBinding) {
|
||||||
viewModel.getSatPassList().observe(viewLifecycleOwner, Observer {
|
viewModel.getSatPassList().observe(viewLifecycleOwner, Observer {
|
||||||
satPassList = it
|
satPassList = it
|
||||||
@@ -110,6 +97,30 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupComponents(binding: FragmentPassListBinding) {
|
||||||
|
binding.recPassList.apply {
|
||||||
|
layoutManager = LinearLayoutManager(mainActivity)
|
||||||
|
adapter = satPassAdapter
|
||||||
|
isVerticalScrollBarEnabled = false
|
||||||
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
|
}
|
||||||
|
satPassAdapter.setList(satPassList)
|
||||||
|
setTimer()
|
||||||
|
|
||||||
|
binding.refLayoutPassList.setProgressBackgroundColorSchemeResource(R.color.themeAccent)
|
||||||
|
binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark)
|
||||||
|
binding.refLayoutPassList.setOnRefreshListener { viewModel.calculatePasses() }
|
||||||
|
btnPassPrefs.setOnClickListener {
|
||||||
|
showSatPassPrefsDialog(viewModel.getHoursAhead(), viewModel.getMinElevation())
|
||||||
|
}
|
||||||
|
binding.fabSatSelect.setOnClickListener {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val list = viewModel.getAllEntries() as MutableList
|
||||||
|
showSelectSatDialog(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showSatPassPrefsDialog(hoursAhead: Int, minEl: Double) {
|
private fun showSatPassPrefsDialog(hoursAhead: Int, minEl: Double) {
|
||||||
val satPassPrefView = View.inflate(mainActivity, R.layout.dialog_pass_pref, null)
|
val satPassPrefView = View.inflate(mainActivity, R.layout.dialog_pass_pref, null)
|
||||||
val etHoursAhead = satPassPrefView.findViewById<EditText>(R.id.pref_et_hoursAhead)
|
val etHoursAhead = satPassPrefView.findViewById<EditText>(R.id.pref_et_hoursAhead)
|
||||||
@@ -142,7 +153,7 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
viewModel.setPassPrefs(hours, elevation)
|
viewModel.setPassPrefs(hours, elevation)
|
||||||
viewModel.getPasses()
|
viewModel.calculatePasses()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else Toast.makeText(
|
} else Toast.makeText(
|
||||||
@@ -160,31 +171,17 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSelectSatDialog(tleMainList: List<TLE>, selection: MutableList<Int>) {
|
private fun showSelectSatDialog(tleMainList: MutableList<SatEntry>) {
|
||||||
if (tleMainList.isEmpty()) {
|
val listener = object : SatEntryDialogFragment.EntriesSubmitListener {
|
||||||
Toast.makeText(mainActivity, getString(R.string.err_update_tle), Toast.LENGTH_SHORT)
|
override fun onEntriesSubmit(entries: MutableList<SatEntry>) {
|
||||||
.show()
|
viewModel.updateEntriesSelection(entries)
|
||||||
} else {
|
|
||||||
val entriesList = mutableListOf<SatEntry>().apply {
|
|
||||||
tleMainList.withIndex().forEach {
|
|
||||||
this.add(SatEntry(it.index, it.value.name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val listener = object : SatEntryDialog.EntriesSubmitListener {
|
|
||||||
override fun onEntriesSubmit(list: MutableList<Int>) {
|
|
||||||
viewModel.updateAndSaveSelectionList(list)
|
|
||||||
viewModel.getPasses()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val dialogFragment = SatEntryDialog().apply {
|
|
||||||
setEntriesList(entriesList)
|
|
||||||
setSelectionList(selection)
|
|
||||||
setEntriesListener(listener)
|
|
||||||
}
|
|
||||||
dialogFragment.show(mainActivity.supportFragmentManager, "SatEntryDialog")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dialogFragment = SatEntryDialogFragment(tleMainList).apply {
|
||||||
|
setEntriesListener(listener)
|
||||||
|
}
|
||||||
|
dialogFragment.show(mainActivity.supportFragmentManager, "SatEntryDialogFragment")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setTimer() {
|
private fun setTimer() {
|
||||||
@@ -229,7 +226,7 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
|||||||
val millisBeforeEnd = lastPass.pass.endTime.time.minus(timeNow.time)
|
val millisBeforeEnd = lastPass.pass.endTime.time.minus(timeNow.time)
|
||||||
aosTimer = object : CountDownTimer(millisBeforeEnd, 1000) {
|
aosTimer = object : CountDownTimer(millisBeforeEnd, 1000) {
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
viewModel.getPasses()
|
viewModel.calculatePasses()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTick(millisUntilFinished: Long) {
|
override fun onTick(millisUntilFinished: Long) {
|
||||||
+38
-34
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
@@ -32,43 +32,65 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.amsacode.predict4java.SatPos
|
import com.github.amsacode.predict4java.SatPos
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
import com.rtbishop.look4sat.Look4SatApp
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||||
|
import com.rtbishop.look4sat.data.SatPass
|
||||||
import com.rtbishop.look4sat.databinding.FragmentPolarViewBinding
|
import com.rtbishop.look4sat.databinding.FragmentPolarViewBinding
|
||||||
import com.rtbishop.look4sat.repo.SatPass
|
import com.rtbishop.look4sat.ui.MainActivity
|
||||||
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
import com.rtbishop.look4sat.ui.adapters.TransmitterAdapter
|
import com.rtbishop.look4sat.ui.adapters.TransmitterAdapter
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
class PolarViewFragment : Fragment(R.layout.fragment_polar_view) {
|
class PolarViewFragment : Fragment(R.layout.fragment_polar_view) {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var modelFactory: ViewModelFactory
|
||||||
private val args: PolarViewFragmentArgs by navArgs()
|
private val args: PolarViewFragmentArgs by navArgs()
|
||||||
|
private lateinit var viewModel: SharedViewModel
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
private lateinit var satPass: SatPass
|
private lateinit var satPass: SatPass
|
||||||
private lateinit var polarView: PolarView
|
private lateinit var polarView: PolarView
|
||||||
private lateinit var transmitterAdapter: TransmitterAdapter
|
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
|
private var transmitterAdapter: TransmitterAdapter = TransmitterAdapter()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val binding = FragmentPolarViewBinding.bind(view)
|
val binding = FragmentPolarViewBinding.bind(view)
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||||
viewModel.getSatPassList().value?.let {
|
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||||
val refreshRate = viewModel.getRefreshRate()
|
val refreshRate = viewModel.getRefreshRate()
|
||||||
satPass = it[args.satPassIndex]
|
|
||||||
mainActivity.supportActionBar?.title = satPass.tle.name
|
|
||||||
|
|
||||||
polarView = PolarView(mainActivity, refreshRate, binding)
|
binding.recPolar.apply {
|
||||||
binding.framePolar.addView(polarView)
|
layoutManager = LinearLayoutManager(mainActivity)
|
||||||
|
adapter = transmitterAdapter
|
||||||
setupTransRecycler(binding)
|
|
||||||
refreshView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.getSatPassList()
|
||||||
|
.observe(viewLifecycleOwner, androidx.lifecycle.Observer { mutableList ->
|
||||||
|
satPass = mutableList[args.satPassIndex]
|
||||||
|
mainActivity.supportActionBar?.title = satPass.tle.name
|
||||||
|
polarView = PolarView(mainActivity, refreshRate, binding)
|
||||||
|
binding.framePolar.addView(polarView)
|
||||||
|
refreshView()
|
||||||
|
viewModel.getTransmittersForSat(satPass.tle.catnum)
|
||||||
|
.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
transmitterAdapter.setList(it)
|
||||||
|
transmitterAdapter.notifyDataSetChanged()
|
||||||
|
binding.recPolar.visibility = View.VISIBLE
|
||||||
|
binding.tvPolarNoTrans.visibility = View.INVISIBLE
|
||||||
|
} else {
|
||||||
|
binding.recPolar.visibility = View.INVISIBLE
|
||||||
|
binding.tvPolarNoTrans.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshView() {
|
private fun refreshView() {
|
||||||
@@ -80,24 +102,6 @@ class PolarViewFragment : Fragment(R.layout.fragment_polar_view) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTransRecycler(binding: FragmentPolarViewBinding) {
|
|
||||||
transmitterAdapter = TransmitterAdapter()
|
|
||||||
binding.recPolar.apply {
|
|
||||||
layoutManager = LinearLayoutManager(mainActivity)
|
|
||||||
adapter = transmitterAdapter
|
|
||||||
}
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val transList = viewModel.getTransmittersForSat(satPass.tle.catnum)
|
|
||||||
if (transList.isNotEmpty()) {
|
|
||||||
transmitterAdapter.setList(transList)
|
|
||||||
transmitterAdapter.notifyDataSetChanged()
|
|
||||||
} else {
|
|
||||||
binding.recPolar.visibility = View.INVISIBLE
|
|
||||||
binding.tvPolarNoTrans.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class PolarView(
|
inner class PolarView(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val updateFreq: Long,
|
private val updateFreq: Long,
|
||||||
+7
-6
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -26,14 +26,15 @@ import android.widget.Toast
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.EditTextPreference
|
import androidx.preference.EditTextPreference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.rtbishop.look4sat.MainViewModel
|
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.ui.MainActivity
|
||||||
|
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat(),
|
class PreferencesFragment : PreferenceFragmentCompat(),
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: SharedViewModel
|
||||||
private lateinit var keyLat: String
|
private lateinit var keyLat: String
|
||||||
private lateinit var keyLon: String
|
private lateinit var keyLon: String
|
||||||
private lateinit var keyAlt: String
|
private lateinit var keyAlt: String
|
||||||
@@ -44,7 +45,7 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
val provider = EditTextPreference.SimpleSummaryProvider.getInstance()
|
val provider = EditTextPreference.SimpleSummaryProvider.getInstance()
|
||||||
|
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(mainActivity).get(SharedViewModel::class.java)
|
||||||
|
|
||||||
keyLat = mainActivity.getString(R.string.pref_lat_key)
|
keyLat = mainActivity.getString(R.string.pref_lat_key)
|
||||||
keyLon = mainActivity.getString(R.string.pref_lon_key)
|
keyLon = mainActivity.getString(R.string.pref_lon_key)
|
||||||
@@ -139,7 +140,7 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
if (key == keyLat || key == keyLon || key == keyAlt) viewModel.setGroundStationPosition()
|
if (key == keyLat || key == keyLon || key == keyAlt) viewModel.setPositionFromPref()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
+29
-43
@@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.rtbishop.look4sat.ui
|
package com.rtbishop.look4sat.ui.fragments
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -26,18 +26,16 @@ import android.view.Window
|
|||||||
import android.widget.SearchView
|
import android.widget.SearchView
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment
|
import androidx.appcompat.app.AppCompatDialogFragment
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.rtbishop.look4sat.data.SatEntry
|
||||||
import com.rtbishop.look4sat.databinding.DialogSatEntryBinding
|
import com.rtbishop.look4sat.databinding.DialogSatEntryBinding
|
||||||
import com.rtbishop.look4sat.repo.SatEntry
|
|
||||||
import com.rtbishop.look4sat.ui.adapters.SatEntryAdapter
|
import com.rtbishop.look4sat.ui.adapters.SatEntryAdapter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener {
|
class SatEntryDialogFragment(private var entries: MutableList<SatEntry>) :
|
||||||
|
AppCompatDialogFragment(), SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
private lateinit var satEntryAdapter: SatEntryAdapter
|
|
||||||
private lateinit var entriesListener: EntriesSubmitListener
|
private lateinit var entriesListener: EntriesSubmitListener
|
||||||
|
private val entryAdapter = SatEntryAdapter(entries)
|
||||||
private var entriesList = mutableListOf<SatEntry>()
|
|
||||||
private var selectionList = mutableListOf<Int>()
|
|
||||||
private var selectAllToggle = true
|
private var selectAllToggle = true
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
@@ -51,18 +49,15 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
entriesList = checkSelectedEntries(entriesList, selectionList)
|
|
||||||
satEntryAdapter = SatEntryAdapter(entriesList)
|
|
||||||
|
|
||||||
binding.dialogSearch.apply {
|
binding.dialogSearch.apply {
|
||||||
setOnQueryTextListener(this@SatEntryDialog)
|
setOnQueryTextListener(this@SatEntryDialogFragment)
|
||||||
onActionViewExpanded()
|
onActionViewExpanded()
|
||||||
clearFocus()
|
clearFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.dialogRecycler.apply {
|
binding.dialogRecycler.apply {
|
||||||
layoutManager = LinearLayoutManager(activity)
|
layoutManager = LinearLayoutManager(activity)
|
||||||
adapter = satEntryAdapter
|
adapter = entryAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() }
|
binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() }
|
||||||
@@ -72,32 +67,27 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
|||||||
return satEntryDialog
|
return satEntryDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEntriesList(list: MutableList<SatEntry>): SatEntryDialog {
|
fun setEntriesListener(listener: EntriesSubmitListener): SatEntryDialogFragment {
|
||||||
entriesList = list
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSelectionList(list: MutableList<Int>): SatEntryDialog {
|
|
||||||
selectAllToggle = list.isEmpty()
|
|
||||||
selectionList = list
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setEntriesListener(listener: EntriesSubmitListener): SatEntryDialog {
|
|
||||||
entriesListener = listener
|
entriesListener = listener
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkSelectedEntries(entries: MutableList<SatEntry>, selection: MutableList<Int>)
|
private fun filterEntries(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||||
: MutableList<SatEntry> {
|
if (query.isEmpty()) return list
|
||||||
selection.forEach { entries[it].isSelected = true }
|
return try {
|
||||||
return entries
|
filterByCatNum(list, query.toInt())
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
filterByName(list, query)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterEntries(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
private fun filterByCatNum(list: MutableList<SatEntry>, catNum: Int): MutableList<SatEntry> {
|
||||||
val searchQuery = query.toLowerCase(Locale.getDefault())
|
val filteredList = list.filter { it.catNum == catNum }
|
||||||
if ((searchQuery == "") or searchQuery.isEmpty()) return list
|
return filteredList as MutableList<SatEntry>
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun filterByName(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||||
|
val searchQuery = query.toLowerCase(Locale.getDefault())
|
||||||
val filteredList = mutableListOf<SatEntry>()
|
val filteredList = mutableListOf<SatEntry>()
|
||||||
list.forEach {
|
list.forEach {
|
||||||
val name = it.name.toLowerCase(Locale.getDefault())
|
val name = it.name.toLowerCase(Locale.getDefault())
|
||||||
@@ -107,10 +97,7 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onPositiveClicked() {
|
private fun onPositiveClicked() {
|
||||||
val listToSubmit = mutableListOf<Int>().apply {
|
entriesListener.onEntriesSubmit(entries)
|
||||||
entriesList.forEach { if (it.isSelected) this.add(it.id) }
|
|
||||||
}
|
|
||||||
entriesListener.onEntriesSubmit(listToSubmit)
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,20 +107,19 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
|||||||
|
|
||||||
private fun onNeutralClicked() {
|
private fun onNeutralClicked() {
|
||||||
selectAllToggle = if (selectAllToggle) {
|
selectAllToggle = if (selectAllToggle) {
|
||||||
entriesList.forEach { it.isSelected = true }
|
entries.forEach { it.isSelected = true }
|
||||||
satEntryAdapter.setEntries(entriesList)
|
entryAdapter.setEntries(entries)
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
entriesList.forEach { it.isSelected = false }
|
entries.forEach { it.isSelected = false }
|
||||||
satEntryAdapter.setEntries(entriesList)
|
entryAdapter.setEntries(entries)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String): Boolean {
|
override fun onQueryTextChange(newText: String): Boolean {
|
||||||
entriesList = checkSelectedEntries(entriesList, selectionList)
|
val filteredList = filterEntries(entries, newText)
|
||||||
val filteredList = filterEntries(entriesList, newText)
|
entryAdapter.setEntries(filteredList)
|
||||||
satEntryAdapter.setEntries(filteredList)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +128,6 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface EntriesSubmitListener {
|
interface EntriesSubmitListener {
|
||||||
fun onEntriesSubmit(list: MutableList<Int>)
|
fun onEntriesSubmit(entries: MutableList<SatEntry>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import com.github.amsacode.predict4java.TLE
|
||||||
|
import com.google.gson.Gson
|
||||||
|
|
||||||
|
class Converters {
|
||||||
|
private val gSon = Gson()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun tleToString(tle: TLE): String {
|
||||||
|
return gSon.toJson(tle)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun tleFromString(string: String): TLE {
|
||||||
|
return gSon.fromJson(string, TLE::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
|
||||||
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.rtbishop.look4sat.utility
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.location.LocationManager
|
|
||||||
import android.util.Log
|
|
||||||
import com.github.amsacode.predict4java.GroundStationPosition
|
|
||||||
import com.github.amsacode.predict4java.TLE
|
|
||||||
import com.rtbishop.look4sat.R
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.ObjectInputStream
|
|
||||||
import java.io.ObjectOutputStream
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class DataManager @Inject constructor(
|
|
||||||
private val locationManager: LocationManager,
|
|
||||||
private val context: Context
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val tag = "DataManager"
|
|
||||||
private val tleMainListFileName = "tleFile.txt"
|
|
||||||
private val tleSelectionFileName = "tleSelection"
|
|
||||||
|
|
||||||
fun getLastKnownLocation(): GroundStationPosition? {
|
|
||||||
val passiveProvider = LocationManager.PASSIVE_PROVIDER
|
|
||||||
var groundStationPosition: GroundStationPosition? = null
|
|
||||||
return try {
|
|
||||||
val location = locationManager.getLastKnownLocation(passiveProvider)
|
|
||||||
location?.let {
|
|
||||||
groundStationPosition =
|
|
||||||
GroundStationPosition(it.latitude, it.longitude, it.altitude)
|
|
||||||
}
|
|
||||||
groundStationPosition
|
|
||||||
} catch (e: SecurityException) {
|
|
||||||
Log.w(tag, "No permissions")
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveSelectionList(selectionList: MutableList<Int>) {
|
|
||||||
try {
|
|
||||||
val fileOutputStream =
|
|
||||||
context.openFileOutput(tleSelectionFileName, Context.MODE_PRIVATE)
|
|
||||||
ObjectOutputStream(fileOutputStream).apply {
|
|
||||||
writeObject(selectionList)
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, "Can't save selection list")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveTleList(tleList: MutableList<TLE>) {
|
|
||||||
try {
|
|
||||||
val fileOutStream = context.openFileOutput(tleMainListFileName, Context.MODE_PRIVATE)
|
|
||||||
ObjectOutputStream(fileOutStream).apply {
|
|
||||||
writeObject(tleList)
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, "Can't save TLE list")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun loadTleList(): List<TLE> {
|
|
||||||
return try {
|
|
||||||
val tleStream = context.openFileInput(tleMainListFileName)
|
|
||||||
val tleList = ObjectInputStream(tleStream).readObject()
|
|
||||||
tleList as List<TLE>
|
|
||||||
} catch (exception: FileNotFoundException) {
|
|
||||||
Log.w(tag, context.getString(R.string.err_no_tle_file))
|
|
||||||
emptyList()
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, exception.toString())
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun loadSelectionList(): MutableList<Int> {
|
|
||||||
return try {
|
|
||||||
val selectionStream = context.openFileInput(tleSelectionFileName)
|
|
||||||
val selectionList = ObjectInputStream(selectionStream).readObject()
|
|
||||||
selectionList as MutableList<Int>
|
|
||||||
} catch (exception: FileNotFoundException) {
|
|
||||||
Log.w(tag, context.getString(R.string.err_no_selection_file))
|
|
||||||
mutableListOf()
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, exception.toString())
|
|
||||||
mutableListOf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+10
-6
@@ -35,7 +35,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, visit http://www.fsf.org/
|
* along with this program; if not, visit http://www.fsf.org/
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.predict4kotlin
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
import com.github.amsacode.predict4java.*
|
import com.github.amsacode.predict4java.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -253,14 +253,18 @@ class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition
|
|||||||
var polePassed = deadSpotNone
|
var polePassed = deadSpotNone
|
||||||
val az1 = prevPos.azimuth / twoPi * 360.0
|
val az1 = prevPos.azimuth / twoPi * 360.0
|
||||||
val az2 = satPos.azimuth / twoPi * 360.0
|
val az2 = satPos.azimuth / twoPi * 360.0
|
||||||
if (az1 > az2) { // we may be moving from 350 or greater through north
|
if (az1 > az2) {
|
||||||
|
// we may be moving from 350 or greater through north
|
||||||
if (az1 > 350 && az2 < 10) polePassed = north
|
if (az1 > 350 && az2 < 10) polePassed = north
|
||||||
else { // we may be moving from 190 or greater through south
|
else {
|
||||||
|
// we may be moving from 190 or greater through south
|
||||||
if (az1 > 180 && az2 < 180) polePassed = south
|
if (az1 > 180 && az2 < 180) polePassed = south
|
||||||
}
|
}
|
||||||
} else { // we may be moving from 10 or less through north
|
} else {
|
||||||
|
// we may be moving from 10 or less through north
|
||||||
if (az1 < 10 && az2 > 350) polePassed = north
|
if (az1 < 10 && az2 > 350) polePassed = north
|
||||||
else { // we may be moving from 170 or more through south
|
else {
|
||||||
|
// we may be moving from 170 or more through south
|
||||||
if (az1 < 180 && az2 > 180) polePassed = south
|
if (az1 < 180 && az2 > 180) polePassed = south
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,4 +274,4 @@ class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition
|
|||||||
private fun threeQuarterOrbitMinutes(): Int {
|
private fun threeQuarterOrbitMinutes(): Int {
|
||||||
return (24.0 * 60.0 / tle.meanmo * 0.75).toInt()
|
return (24.0 * 60.0 / tle.meanmo * 0.75).toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,35 +20,44 @@
|
|||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.location.LocationManager
|
||||||
|
import android.util.Log
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.github.amsacode.predict4java.GroundStationPosition
|
import com.github.amsacode.predict4java.GroundStationPosition
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class PrefsManager @Inject constructor(private val preferences: SharedPreferences) {
|
class PrefsManager @Inject constructor(
|
||||||
|
private val preferences: SharedPreferences,
|
||||||
|
private val locationManager: LocationManager
|
||||||
|
) {
|
||||||
|
private val tag = "prefsManager"
|
||||||
private val keyHoursAhead = "hoursAhead"
|
private val keyHoursAhead = "hoursAhead"
|
||||||
private val keyMinElevation = "minEl"
|
private val keyMinElevation = "minEl"
|
||||||
private val keyLatitude = "latitude"
|
private val keyLatitude = "latitude"
|
||||||
private val keyLongitude = "longitude"
|
private val keyLongitude = "longitude"
|
||||||
private val keyAltitude = "altitude"
|
private val keyAltitude = "altitude"
|
||||||
private val keyRefreshRate = "rate"
|
private val keyRefreshRate = "rate"
|
||||||
|
private val defaultHoursAhead = 8
|
||||||
|
private val defaultMinEl = 16.0
|
||||||
|
private val defaultRefreshRate = "3000"
|
||||||
|
private val defaultGSP = "0.0"
|
||||||
|
|
||||||
fun getHoursAhead(): Int {
|
fun getHoursAhead(): Int {
|
||||||
return preferences.getInt(keyHoursAhead, 8)
|
return preferences.getInt(keyHoursAhead, defaultHoursAhead)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMinElevation(): Double {
|
fun getMinElevation(): Double {
|
||||||
return preferences.getDouble(keyMinElevation, 16.0)
|
return preferences.getDouble(keyMinElevation, defaultMinEl)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRefreshRate(): Long {
|
fun getRefreshRate(): Long {
|
||||||
return preferences.getString(keyRefreshRate, "3000")!!.toLong()
|
return preferences.getString(keyRefreshRate, defaultRefreshRate)!!.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGroundStationPosition(): GroundStationPosition {
|
fun getPosition(): GroundStationPosition {
|
||||||
val lat = preferences.getString(keyLatitude, "0.0")!!.toDouble()
|
val lat = preferences.getString(keyLatitude, defaultGSP)!!.toDouble()
|
||||||
val lon = preferences.getString(keyLongitude, "0.0")!!.toDouble()
|
val lon = preferences.getString(keyLongitude, defaultGSP)!!.toDouble()
|
||||||
val alt = preferences.getString(keyAltitude, "0.0")!!.toDouble()
|
val alt = preferences.getString(keyAltitude, defaultGSP)!!.toDouble()
|
||||||
return GroundStationPosition(lat, lon, alt)
|
return GroundStationPosition(lat, lon, alt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +82,7 @@ class PrefsManager @Inject constructor(private val preferences: SharedPreference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setGroundStationPosition(gsp: GroundStationPosition) {
|
fun setPosition(gsp: GroundStationPosition) {
|
||||||
preferences.edit {
|
preferences.edit {
|
||||||
putString(keyLatitude, gsp.latitude.toString())
|
putString(keyLatitude, gsp.latitude.toString())
|
||||||
putString(keyLongitude, gsp.longitude.toString())
|
putString(keyLongitude, gsp.longitude.toString())
|
||||||
@@ -82,6 +91,22 @@ class PrefsManager @Inject constructor(private val preferences: SharedPreference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLastKnownPosition(): GroundStationPosition {
|
||||||
|
val provider = LocationManager.PASSIVE_PROVIDER
|
||||||
|
var gsp = GroundStationPosition(0.0, 0.0, 0.0)
|
||||||
|
return try {
|
||||||
|
val location = locationManager.getLastKnownLocation(provider)
|
||||||
|
location?.let {
|
||||||
|
gsp =
|
||||||
|
GroundStationPosition(it.latitude, it.longitude, it.altitude)
|
||||||
|
}
|
||||||
|
gsp
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
Log.w(tag, "No permissions")
|
||||||
|
gsp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
|
private fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
|
||||||
putLong(key, double.toRawBits())
|
putLong(key, double.toRawBits())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.AboutFragment">
|
tools:context=".ui.fragments.AboutFragment">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.MapViewFragment">
|
tools:context=".ui.fragments.MapViewFragment">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/frameMap"
|
android:id="@+id/frameMap"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.PolarViewFragment">
|
tools:context=".ui.fragments.PolarViewFragment">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/frame_polar"
|
android:id="@+id/frame_polar"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_pass_list"
|
android:id="@+id/nav_pass_list"
|
||||||
android:name="com.rtbishop.look4sat.ui.PassListFragment"
|
android:name="com.rtbishop.look4sat.ui.fragments.PassListFragment"
|
||||||
android:label="@string/menu_pass_list"
|
android:label="@string/menu_pass_list"
|
||||||
tools:layout="@layout/fragment_pass_list">
|
tools:layout="@layout/fragment_pass_list">
|
||||||
<action
|
<action
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_polar_view"
|
android:id="@+id/nav_polar_view"
|
||||||
android:name="com.rtbishop.look4sat.ui.PolarViewFragment"
|
android:name="com.rtbishop.look4sat.ui.fragments.PolarViewFragment"
|
||||||
android:label="@string/menu_polar_view"
|
android:label="@string/menu_polar_view"
|
||||||
tools:layout="@layout/fragment_polar_view">
|
tools:layout="@layout/fragment_polar_view">
|
||||||
<argument
|
<argument
|
||||||
@@ -50,18 +50,18 @@
|
|||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_map_view"
|
android:id="@+id/nav_map_view"
|
||||||
android:name="com.rtbishop.look4sat.ui.MapViewFragment"
|
android:name="com.rtbishop.look4sat.ui.fragments.MapViewFragment"
|
||||||
android:label="@string/menu_map_view"
|
android:label="@string/menu_map_view"
|
||||||
tools:layout="@layout/fragment_map_view" />
|
tools:layout="@layout/fragment_map_view" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_settings"
|
android:id="@+id/nav_settings"
|
||||||
android:name="com.rtbishop.look4sat.ui.SettingsFragment"
|
android:name="com.rtbishop.look4sat.ui.fragments.PreferencesFragment"
|
||||||
android:label="@string/menu_settings" />
|
android:label="@string/menu_settings" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_about"
|
android:id="@+id/nav_about"
|
||||||
android:name="com.rtbishop.look4sat.ui.AboutFragment"
|
android:name="com.rtbishop.look4sat.ui.fragments.AboutFragment"
|
||||||
android:label="@string/menu_about"
|
android:label="@string/menu_about"
|
||||||
tools:layout="@layout/fragment_about" />
|
tools:layout="@layout/fragment_about" />
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -26,9 +26,9 @@ buildscript {
|
|||||||
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.71"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
|
||||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.1"
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,15 +44,15 @@ task clean(type: Delete) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
material = '1.2.0-alpha05'
|
material = '1.1.0'
|
||||||
appCompat = '1.1.0'
|
appCompat = '1.1.0'
|
||||||
supportLib = '1.0.0'
|
supportLib = '1.0.0'
|
||||||
constraintLayout = '1.1.3'
|
constraintLayout = '1.1.3'
|
||||||
|
|
||||||
ktx = '1.2.0'
|
ktx = '1.2.0'
|
||||||
preference = '1.1.0'
|
preference = '1.1.1'
|
||||||
|
|
||||||
navigation = '2.2.1'
|
navigation = '2.2.2'
|
||||||
lifecycle = '2.2.0'
|
lifecycle = '2.2.0'
|
||||||
|
|
||||||
room = '2.2.5'
|
room = '2.2.5'
|
||||||
|
|||||||
Reference in new issue
Block a user