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-viewmodel-ktx:$lifecycle"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle"
|
||||
|
||||
// room
|
||||
implementation "androidx.room:room-runtime:$room"
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
package com.rtbishop.look4sat
|
||||
|
||||
import android.app.Application
|
||||
import com.rtbishop.look4sat.di.AppComponent
|
||||
import com.rtbishop.look4sat.di.DaggerAppComponent
|
||||
import com.rtbishop.look4sat.dagger.AppComponent
|
||||
import com.rtbishop.look4sat.dagger.DaggerAppComponent
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.di
|
||||
package com.rtbishop.look4sat.dagger
|
||||
|
||||
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.Component
|
||||
import javax.inject.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 {
|
||||
|
||||
@Component.Factory
|
||||
@@ -34,5 +41,8 @@ interface 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.
|
||||
*/
|
||||
|
||||
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 dagger.Module
|
||||
import dagger.Provides
|
||||
@@ -30,6 +32,18 @@ import javax.inject.Singleton
|
||||
@Module
|
||||
class NetworkModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideOkHttpClient(): OkHttpClient {
|
||||
return OkHttpClient()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideRemoteDataSource(api: TransmittersApi, client: OkHttpClient): RemoteSource {
|
||||
return RemoteDataSource(api, client)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTransmittersApi(): TransmittersApi {
|
||||
@@ -39,10 +53,4 @@ class NetworkModule {
|
||||
.build()
|
||||
.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.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.di
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import com.rtbishop.look4sat.storage.TransmittersDao
|
||||
import com.rtbishop.look4sat.storage.TransmittersDb
|
||||
import com.rtbishop.look4sat.persistence.LocalDataSource
|
||||
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.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class StorageModule {
|
||||
class PersistenceModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTransmittersDb(context: Context): TransmittersDb {
|
||||
return Room.databaseBuilder(context, TransmittersDb::class.java, "transmitters")
|
||||
.build()
|
||||
fun provideEntriesDao(db: SatelliteDb): EntriesDao {
|
||||
return db.entriesDao()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTransmittersDao(db: TransmittersDb): TransmittersDao {
|
||||
fun provideTransmittersDao(db: SatelliteDb): 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.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.di
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.location.LocationManager
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class AndroidModule {
|
||||
class UtilityModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@@ -41,4 +42,13 @@ class AndroidModule {
|
||||
fun provideLocationManager(context: Context): 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.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.repo
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.github.amsacode.predict4java.SatPassTime
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
|
||||
data class SatPass(
|
||||
val tle: TLE,
|
||||
+2
-2
@@ -17,7 +17,7 @@
|
||||
* 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.PrimaryKey
|
||||
@@ -34,5 +34,5 @@ data class Transmitter(
|
||||
@SerializedName("downlink_high") val downlinkHigh: Long?,
|
||||
@SerializedName("mode") val mode: String?,
|
||||
@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
|
||||
|
||||
import com.rtbishop.look4sat.repo.Transmitter
|
||||
import android.util.Log
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.SequenceInputStream
|
||||
import java.util.*
|
||||
@@ -32,20 +34,25 @@ import javax.inject.Inject
|
||||
class RemoteDataSource @Inject constructor(
|
||||
private val api: TransmittersApi,
|
||||
private val client: OkHttpClient
|
||||
) {
|
||||
suspend fun getStreamForUrl(urlList: List<String>): InputStream {
|
||||
) : RemoteSource {
|
||||
|
||||
override suspend fun fetchTleStream(urlList: List<String>): InputStream {
|
||||
val streamTable = Hashtable<String, InputStream>()
|
||||
withContext(Dispatchers.IO) {
|
||||
urlList.forEach {
|
||||
val request = Request.Builder().url(it).build()
|
||||
val stream = client.newCall(request).execute().body()?.byteStream()!!
|
||||
streamTable[it] = stream
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
urlList.forEach {
|
||||
val request = Request.Builder().url(it).build()
|
||||
val stream = client.newCall(request).execute().body()?.byteStream()
|
||||
streamTable[it] = stream
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.w("remoteDataSource", e.toString())
|
||||
}
|
||||
return SequenceInputStream(streamTable.elements())
|
||||
}
|
||||
|
||||
suspend fun fetchTransmittersList(): List<Transmitter> {
|
||||
return api.fetchTransmittersList()
|
||||
override suspend fun fetchTransmitters(): List<Transmitter> {
|
||||
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
|
||||
|
||||
import com.rtbishop.look4sat.repo.Transmitter
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import retrofit2.http.GET
|
||||
|
||||
interface TransmittersApi {
|
||||
|
||||
@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.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.storage
|
||||
package com.rtbishop.look4sat.persistence
|
||||
|
||||
import androidx.room.Database
|
||||
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)
|
||||
abstract class TransmittersDb : RoomDatabase() {
|
||||
@Database(entities = [Transmitter::class, SatEntry::class], version = 1, exportSchema = false)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class SatelliteDb : RoomDatabase() {
|
||||
|
||||
abstract fun entriesDao(): EntriesDao
|
||||
|
||||
abstract fun transmittersDao(): TransmittersDao
|
||||
}
|
||||
+13
-10
@@ -17,20 +17,23 @@
|
||||
* 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.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.rtbishop.look4sat.repo.Transmitter
|
||||
import androidx.room.*
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
|
||||
@Dao
|
||||
interface TransmittersDao {
|
||||
interface EntriesDao {
|
||||
|
||||
@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")
|
||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter>
|
||||
@Query("SELECT * FROM entries ORDER BY name ASC")
|
||||
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
|
||||
|
||||
import com.rtbishop.look4sat.network.RemoteDataSource
|
||||
import com.rtbishop.look4sat.storage.LocalDataSource
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
|
||||
class Repository @Inject constructor(
|
||||
private val localSource: LocalDataSource,
|
||||
private val remoteSource: RemoteDataSource
|
||||
) {
|
||||
suspend fun getStreamForUrl(urlList: List<String>): InputStream {
|
||||
return remoteSource.getStreamForUrl(urlList)
|
||||
}
|
||||
interface Repository {
|
||||
|
||||
suspend fun updateTransmittersDatabase() {
|
||||
localSource.insertTransmitters(remoteSource.fetchTransmittersList())
|
||||
}
|
||||
suspend fun updateEntriesFrom(urlList: List<String>)
|
||||
|
||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
||||
return localSource.getTransmittersForSat(id)
|
||||
}
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
|
||||
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.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.rtbishop.look4sat.MainViewModel
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||
import com.rtbishop.look4sat.databinding.DrawerHeaderBinding
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@@ -54,19 +56,25 @@ class MainActivity : AppCompatActivity() {
|
||||
private val permGranted = PackageManager.PERMISSION_GRANTED
|
||||
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 drawerBinding: DrawerHeaderBinding
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var appBarConfig: AppBarConfiguration
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(R.style.AppTheme)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mainBinding = ActivityMainBinding.inflate(layoutInflater)
|
||||
drawerBinding = DrawerHeaderBinding.inflate(layoutInflater, mainBinding.navView, true)
|
||||
setContentView(mainBinding.root)
|
||||
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()
|
||||
setupObservers()
|
||||
setupDrawer()
|
||||
@@ -108,10 +116,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.getDebugMessage().observe(this, Observer { message ->
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
})
|
||||
|
||||
viewModel.getGSP().observe(this, Observer { gsp ->
|
||||
drawerBinding.drawerLatValue.text =
|
||||
String.format(getString(R.string.pat_location), gsp.latitude)
|
||||
@@ -126,11 +130,11 @@ class MainActivity : AppCompatActivity() {
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnTle.setOnClickListener {
|
||||
viewModel.updateAndSaveTleFile()
|
||||
viewModel.updateEntries()
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnTrans.setOnClickListener {
|
||||
viewModel.updateTransmittersDatabase()
|
||||
viewModel.updateTransmitters()
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnGithub.setOnClickListener {
|
||||
@@ -157,7 +161,7 @@ class MainActivity : AppCompatActivity() {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(permLocation), permLocationCode)
|
||||
}
|
||||
} else {
|
||||
viewModel.updateLocation()
|
||||
viewModel.updatePosition()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +169,7 @@ class MainActivity : AppCompatActivity() {
|
||||
when (reqCode) {
|
||||
permLocationCode -> {
|
||||
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.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
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>() {
|
||||
|
||||
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) {
|
||||
holder.bind(entriesList[position])
|
||||
holder.bind(entries[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return entriesList.size
|
||||
return entries.size
|
||||
}
|
||||
|
||||
fun setEntries(entries: MutableList<SatEntry>) {
|
||||
entriesList = entries
|
||||
fun setEntries(list: MutableList<SatEntry>) {
|
||||
entries = list
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
internal inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) :
|
||||
inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(satEntry: SatEntry) {
|
||||
binding.satEntryCheckbox.text = satEntry.name
|
||||
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 androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.MainViewModel
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.ItemPassGeoBinding
|
||||
import com.rtbishop.look4sat.databinding.ItemPassLeoBinding
|
||||
import com.rtbishop.look4sat.repo.SatPass
|
||||
import com.rtbishop.look4sat.ui.PassListFragmentDirections
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.fragments.PassListFragmentDirections
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class SatPassAdapter(val viewModel: MainViewModel) :
|
||||
class SatPassAdapter(val viewModel: SharedViewModel) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private var satPassList = mutableListOf<SatPass>()
|
||||
|
||||
@@ -25,8 +25,8 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import com.rtbishop.look4sat.databinding.ItemTransmitterBinding
|
||||
import com.rtbishop.look4sat.repo.Transmitter
|
||||
|
||||
class TransmitterAdapter : RecyclerView.Adapter<TransmitterAdapter.TransmitterHolder>() {
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
* 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.text.method.LinkMovementMethod
|
||||
+13
-6
@@ -17,7 +17,7 @@
|
||||
* 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.graphics.*
|
||||
@@ -33,20 +33,26 @@ import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.github.amsacode.predict4java.SatPos
|
||||
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.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapViewBinding
|
||||
import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
||||
import com.rtbishop.look4sat.repo.SatPass
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var predictor: PassPredictor
|
||||
private lateinit var selectedSat: TLE
|
||||
@@ -58,7 +64,8 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val binding = FragmentMapViewBinding.bind(view)
|
||||
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)
|
||||
satPassList = viewModel.getSatPassList().value ?: emptyList()
|
||||
|
||||
+56
-59
@@ -17,7 +17,7 @@
|
||||
* 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.CountDownTimer
|
||||
@@ -30,68 +30,55 @@ import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
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.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentPassListBinding
|
||||
import com.rtbishop.look4sat.repo.SatEntry
|
||||
import com.rtbishop.look4sat.repo.SatPass
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.adapters.SatPassAdapter
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
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 btnPassPrefs: ImageButton
|
||||
private lateinit var aosTimer: CountDownTimer
|
||||
private lateinit var aosTimerText: TextView
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private var satPassList: MutableList<SatPass> = mutableListOf()
|
||||
private var isTimerSet: Boolean = false
|
||||
private var satPassList: MutableList<SatPass> = mutableListOf()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val fragmentBinding = FragmentPassListBinding.bind(view)
|
||||
val binding = FragmentPassListBinding.bind(view)
|
||||
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)
|
||||
aosTimerText = mainActivity.findViewById(R.id.toolbar_timer)
|
||||
btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter)
|
||||
|
||||
setupComponents(fragmentBinding)
|
||||
setupObservers(fragmentBinding)
|
||||
setupObservers(binding)
|
||||
setupComponents(binding)
|
||||
|
||||
if (viewModel.tleSelection.isNotEmpty() && viewModel.isFirstLaunch) {
|
||||
viewModel.getPasses()
|
||||
if (viewModel.isFirstLaunch) {
|
||||
viewModel.calculatePasses()
|
||||
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) {
|
||||
viewModel.getSatPassList().observe(viewLifecycleOwner, Observer {
|
||||
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) {
|
||||
val satPassPrefView = View.inflate(mainActivity, R.layout.dialog_pass_pref, null)
|
||||
val etHoursAhead = satPassPrefView.findViewById<EditText>(R.id.pref_et_hoursAhead)
|
||||
@@ -142,7 +153,7 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
||||
}
|
||||
else -> {
|
||||
viewModel.setPassPrefs(hours, elevation)
|
||||
viewModel.getPasses()
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
}
|
||||
} else Toast.makeText(
|
||||
@@ -160,31 +171,17 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showSelectSatDialog(tleMainList: List<TLE>, selection: MutableList<Int>) {
|
||||
if (tleMainList.isEmpty()) {
|
||||
Toast.makeText(mainActivity, getString(R.string.err_update_tle), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
} else {
|
||||
val entriesList = mutableListOf<SatEntry>().apply {
|
||||
tleMainList.withIndex().forEach {
|
||||
this.add(SatEntry(it.index, it.value.name))
|
||||
}
|
||||
private fun showSelectSatDialog(tleMainList: MutableList<SatEntry>) {
|
||||
val listener = object : SatEntryDialogFragment.EntriesSubmitListener {
|
||||
override fun onEntriesSubmit(entries: MutableList<SatEntry>) {
|
||||
viewModel.updateEntriesSelection(entries)
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -229,7 +226,7 @@ class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
||||
val millisBeforeEnd = lastPass.pass.endTime.time.minus(timeNow.time)
|
||||
aosTimer = object : CountDownTimer(millisBeforeEnd, 1000) {
|
||||
override fun onFinish() {
|
||||
viewModel.getPasses()
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
+38
-34
@@ -17,7 +17,7 @@
|
||||
* 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.graphics.Canvas
|
||||
@@ -32,43 +32,65 @@ import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
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 kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class PolarViewFragment : Fragment(R.layout.fragment_polar_view) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
private val args: PolarViewFragmentArgs by navArgs()
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var satPass: SatPass
|
||||
private lateinit var polarView: PolarView
|
||||
private lateinit var transmitterAdapter: TransmitterAdapter
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private var transmitterAdapter: TransmitterAdapter = TransmitterAdapter()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val binding = FragmentPolarViewBinding.bind(view)
|
||||
mainActivity = activity as MainActivity
|
||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
||||
viewModel.getSatPassList().value?.let {
|
||||
val refreshRate = viewModel.getRefreshRate()
|
||||
satPass = it[args.satPassIndex]
|
||||
mainActivity.supportActionBar?.title = satPass.tle.name
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
val refreshRate = viewModel.getRefreshRate()
|
||||
|
||||
polarView = PolarView(mainActivity, refreshRate, binding)
|
||||
binding.framePolar.addView(polarView)
|
||||
|
||||
setupTransRecycler(binding)
|
||||
refreshView()
|
||||
binding.recPolar.apply {
|
||||
layoutManager = LinearLayoutManager(mainActivity)
|
||||
adapter = transmitterAdapter
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -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(
|
||||
context: Context,
|
||||
private val updateFreq: Long,
|
||||
+7
-6
@@ -17,7 +17,7 @@
|
||||
* 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.os.Bundle
|
||||
@@ -26,14 +26,15 @@ import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.rtbishop.look4sat.MainViewModel
|
||||
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 {
|
||||
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var keyLat: String
|
||||
private lateinit var keyLon: String
|
||||
private lateinit var keyAlt: String
|
||||
@@ -44,7 +45,7 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
||||
val provider = EditTextPreference.SimpleSummaryProvider.getInstance()
|
||||
|
||||
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)
|
||||
keyLon = mainActivity.getString(R.string.pref_lon_key)
|
||||
@@ -139,7 +140,7 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
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() {
|
||||
+29
-43
@@ -17,7 +17,7 @@
|
||||
* 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.os.Bundle
|
||||
@@ -26,18 +26,16 @@ import android.view.Window
|
||||
import android.widget.SearchView
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.databinding.DialogSatEntryBinding
|
||||
import com.rtbishop.look4sat.repo.SatEntry
|
||||
import com.rtbishop.look4sat.ui.adapters.SatEntryAdapter
|
||||
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 var entriesList = mutableListOf<SatEntry>()
|
||||
private var selectionList = mutableListOf<Int>()
|
||||
private val entryAdapter = SatEntryAdapter(entries)
|
||||
private var selectAllToggle = true
|
||||
|
||||
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 {
|
||||
setOnQueryTextListener(this@SatEntryDialog)
|
||||
setOnQueryTextListener(this@SatEntryDialogFragment)
|
||||
onActionViewExpanded()
|
||||
clearFocus()
|
||||
}
|
||||
|
||||
binding.dialogRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(activity)
|
||||
adapter = satEntryAdapter
|
||||
adapter = entryAdapter
|
||||
}
|
||||
|
||||
binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() }
|
||||
@@ -72,32 +67,27 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
||||
return satEntryDialog
|
||||
}
|
||||
|
||||
fun setEntriesList(list: MutableList<SatEntry>): SatEntryDialog {
|
||||
entriesList = list
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSelectionList(list: MutableList<Int>): SatEntryDialog {
|
||||
selectAllToggle = list.isEmpty()
|
||||
selectionList = list
|
||||
return this
|
||||
}
|
||||
|
||||
fun setEntriesListener(listener: EntriesSubmitListener): SatEntryDialog {
|
||||
fun setEntriesListener(listener: EntriesSubmitListener): SatEntryDialogFragment {
|
||||
entriesListener = listener
|
||||
return this
|
||||
}
|
||||
|
||||
private fun checkSelectedEntries(entries: MutableList<SatEntry>, selection: MutableList<Int>)
|
||||
: MutableList<SatEntry> {
|
||||
selection.forEach { entries[it].isSelected = true }
|
||||
return entries
|
||||
private fun filterEntries(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||
if (query.isEmpty()) return list
|
||||
return try {
|
||||
filterByCatNum(list, query.toInt())
|
||||
} catch (e: NumberFormatException) {
|
||||
filterByName(list, query)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterEntries(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||
val searchQuery = query.toLowerCase(Locale.getDefault())
|
||||
if ((searchQuery == "") or searchQuery.isEmpty()) return list
|
||||
private fun filterByCatNum(list: MutableList<SatEntry>, catNum: Int): MutableList<SatEntry> {
|
||||
val filteredList = list.filter { it.catNum == catNum }
|
||||
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>()
|
||||
list.forEach {
|
||||
val name = it.name.toLowerCase(Locale.getDefault())
|
||||
@@ -107,10 +97,7 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
||||
}
|
||||
|
||||
private fun onPositiveClicked() {
|
||||
val listToSubmit = mutableListOf<Int>().apply {
|
||||
entriesList.forEach { if (it.isSelected) this.add(it.id) }
|
||||
}
|
||||
entriesListener.onEntriesSubmit(listToSubmit)
|
||||
entriesListener.onEntriesSubmit(entries)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
@@ -120,20 +107,19 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
||||
|
||||
private fun onNeutralClicked() {
|
||||
selectAllToggle = if (selectAllToggle) {
|
||||
entriesList.forEach { it.isSelected = true }
|
||||
satEntryAdapter.setEntries(entriesList)
|
||||
entries.forEach { it.isSelected = true }
|
||||
entryAdapter.setEntries(entries)
|
||||
false
|
||||
} else {
|
||||
entriesList.forEach { it.isSelected = false }
|
||||
satEntryAdapter.setEntries(entriesList)
|
||||
entries.forEach { it.isSelected = false }
|
||||
entryAdapter.setEntries(entries)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
entriesList = checkSelectedEntries(entriesList, selectionList)
|
||||
val filteredList = filterEntries(entriesList, newText)
|
||||
satEntryAdapter.setEntries(filteredList)
|
||||
val filteredList = filterEntries(entries, newText)
|
||||
entryAdapter.setEntries(filteredList)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -142,6 +128,6 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener
|
||||
}
|
||||
|
||||
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
|
||||
* 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 java.util.*
|
||||
@@ -253,14 +253,18 @@ class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition
|
||||
var polePassed = deadSpotNone
|
||||
val az1 = prevPos.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
|
||||
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
|
||||
}
|
||||
} 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
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -270,4 +274,4 @@ class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition
|
||||
private fun threeQuarterOrbitMinutes(): Int {
|
||||
return (24.0 * 60.0 / tle.meanmo * 0.75).toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,35 +20,44 @@
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.location.LocationManager
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
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 keyMinElevation = "minEl"
|
||||
private val keyLatitude = "latitude"
|
||||
private val keyLongitude = "longitude"
|
||||
private val keyAltitude = "altitude"
|
||||
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 {
|
||||
return preferences.getInt(keyHoursAhead, 8)
|
||||
return preferences.getInt(keyHoursAhead, defaultHoursAhead)
|
||||
}
|
||||
|
||||
fun getMinElevation(): Double {
|
||||
return preferences.getDouble(keyMinElevation, 16.0)
|
||||
return preferences.getDouble(keyMinElevation, defaultMinEl)
|
||||
}
|
||||
|
||||
fun getRefreshRate(): Long {
|
||||
return preferences.getString(keyRefreshRate, "3000")!!.toLong()
|
||||
return preferences.getString(keyRefreshRate, defaultRefreshRate)!!.toLong()
|
||||
}
|
||||
|
||||
fun getGroundStationPosition(): GroundStationPosition {
|
||||
val lat = preferences.getString(keyLatitude, "0.0")!!.toDouble()
|
||||
val lon = preferences.getString(keyLongitude, "0.0")!!.toDouble()
|
||||
val alt = preferences.getString(keyAltitude, "0.0")!!.toDouble()
|
||||
fun getPosition(): GroundStationPosition {
|
||||
val lat = preferences.getString(keyLatitude, defaultGSP)!!.toDouble()
|
||||
val lon = preferences.getString(keyLongitude, defaultGSP)!!.toDouble()
|
||||
val alt = preferences.getString(keyAltitude, defaultGSP)!!.toDouble()
|
||||
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 {
|
||||
putString(keyLatitude, gsp.latitude.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) {
|
||||
putLong(key, double.toRawBits())
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.AboutFragment">
|
||||
tools:context=".ui.fragments.AboutFragment">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.MapViewFragment">
|
||||
tools:context=".ui.fragments.MapViewFragment">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/frameMap"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.PolarViewFragment">
|
||||
tools:context=".ui.fragments.PolarViewFragment">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/frame_polar"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<fragment
|
||||
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"
|
||||
tools:layout="@layout/fragment_pass_list">
|
||||
<action
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
<fragment
|
||||
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"
|
||||
tools:layout="@layout/fragment_polar_view">
|
||||
<argument
|
||||
@@ -50,18 +50,18 @@
|
||||
|
||||
<fragment
|
||||
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"
|
||||
tools:layout="@layout/fragment_map_view" />
|
||||
|
||||
<fragment
|
||||
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" />
|
||||
|
||||
<fragment
|
||||
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"
|
||||
tools:layout="@layout/fragment_about" />
|
||||
|
||||
|
||||
+6
-6
@@ -26,9 +26,9 @@ buildscript {
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.71"
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.1"
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +44,15 @@ task clean(type: Delete) {
|
||||
}
|
||||
|
||||
ext {
|
||||
material = '1.2.0-alpha05'
|
||||
material = '1.1.0'
|
||||
appCompat = '1.1.0'
|
||||
supportLib = '1.0.0'
|
||||
constraintLayout = '1.1.3'
|
||||
|
||||
ktx = '1.2.0'
|
||||
preference = '1.1.0'
|
||||
preference = '1.1.1'
|
||||
|
||||
navigation = '2.2.1'
|
||||
navigation = '2.2.2'
|
||||
lifecycle = '2.2.0'
|
||||
|
||||
room = '2.2.5'
|
||||
|
||||
Reference in new issue
Block a user