mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Repositories refactoring and merge
This commit is contained in:
1 parent
1a59b5e3e1
commit
0110de8104
28 files changed
+309
-577
No files matched your search
@@ -23,7 +23,7 @@ import android.location.LocationManager
|
||||
import androidx.room.Room
|
||||
import com.rtbishop.look4sat.data.*
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||
import com.rtbishop.look4sat.framework.DefaultLocationSource
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import com.rtbishop.look4sat.framework.api.NetworkDataSource
|
||||
import com.rtbishop.look4sat.framework.api.SatelliteService
|
||||
import com.rtbishop.look4sat.framework.db.RoomConverters
|
||||
@@ -52,20 +52,21 @@ object DataSourceModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLocationSource(
|
||||
fun providePreferenceSource(
|
||||
qthConverter: QthConverter,
|
||||
locationManager: LocationManager,
|
||||
preferences: SharedPreferences
|
||||
): LocationSource {
|
||||
return DefaultLocationSource(locationManager, preferences)
|
||||
): PreferenceSource {
|
||||
return PreferencesProvider(qthConverter, locationManager, preferences)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLocationRepo(
|
||||
locationSource: LocationSource,
|
||||
qthConverter: QthConverter
|
||||
): LocationRepo {
|
||||
return LocationRepo(locationSource, qthConverter)
|
||||
fun providePassesRepo(
|
||||
preferenceSource: PreferenceSource,
|
||||
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
||||
): PassesRepo {
|
||||
return PassesRepo(preferenceSource, defaultDispatcher)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -39,18 +39,18 @@ object InteractorsModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideGetTransmittersForSatUseCase(satelliteRepo: SatelliteRepo): GetTransmittersForSat {
|
||||
return GetTransmittersForSat(satelliteRepo)
|
||||
fun provideGetSatTransmittersUseCase(satelliteRepo: SatelliteRepo): GetSatTransmitters {
|
||||
return GetSatTransmitters(satelliteRepo)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideImportDataFromStreamUseCase(satelliteRepo: SatelliteRepo): ImportDataFromStream {
|
||||
return ImportDataFromStream(satelliteRepo)
|
||||
fun provideUpdateEntriesFromFileUseCase(satelliteRepo: SatelliteRepo): UpdateEntriesFromFile {
|
||||
return UpdateEntriesFromFile(satelliteRepo)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideImportDataFromWebUseCase(satelliteRepo: SatelliteRepo): ImportDataFromWeb {
|
||||
return ImportDataFromWeb(satelliteRepo)
|
||||
fun provideUpdateEntriesFromWebUseCase(satelliteRepo: SatelliteRepo): UpdateEntriesFromWeb {
|
||||
return UpdateEntriesFromWeb(satelliteRepo)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.rtbishop.look4sat.framework
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.hardware.GeomagneticField
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.edit
|
||||
import com.rtbishop.look4sat.data.LocationSource
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
import com.rtbishop.look4sat.utility.round
|
||||
import javax.inject.Inject
|
||||
|
||||
class DefaultLocationSource @Inject constructor(
|
||||
private val locationManager: LocationManager,
|
||||
private val preferences: SharedPreferences
|
||||
) : LocationSource {
|
||||
|
||||
companion object {
|
||||
const val keyLatitude = "stationLat"
|
||||
const val keyLongitude = "stationLon"
|
||||
const val keyAltitude = "stationAlt"
|
||||
const val keyPositionGPS = "setPositionGPS"
|
||||
const val keyPositionQTH = "setPositionQTH"
|
||||
}
|
||||
|
||||
override fun getLastKnownLocation(): StationPosition? {
|
||||
return try {
|
||||
val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
|
||||
if (location == null) null
|
||||
else {
|
||||
val latitude = location.latitude.round(4)
|
||||
val longitude = location.longitude.round(4)
|
||||
val altitude = location.altitude.round(1)
|
||||
return StationPosition(latitude, longitude, altitude)
|
||||
}
|
||||
} catch (exception: SecurityException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMagDeclination(position: StationPosition): Float {
|
||||
val lat = position.latitude.toFloat()
|
||||
val lon = position.longitude.toFloat()
|
||||
val alt = position.altitude.toFloat()
|
||||
return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination
|
||||
}
|
||||
|
||||
override fun loadStationPosition(): StationPosition {
|
||||
val defaultSP = "0.0"
|
||||
val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
|
||||
val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
|
||||
val altitude = preferences.getString(keyAltitude, null) ?: defaultSP
|
||||
return StationPosition(latitude.toDouble(), longitude.toDouble(), altitude.toDouble())
|
||||
}
|
||||
|
||||
override fun saveStationPosition(position: StationPosition) {
|
||||
preferences.edit {
|
||||
putString(keyLatitude, position.latitude.toString())
|
||||
putString(keyLongitude, position.longitude.toString())
|
||||
putString(keyAltitude, position.altitude.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.framework
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.hardware.GeomagneticField
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.edit
|
||||
import com.rtbishop.look4sat.data.PreferenceSource
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
import com.rtbishop.look4sat.utility.round
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferencesProvider @Inject constructor(
|
||||
private val qthConverter: QthConverter,
|
||||
private val locationManager: LocationManager,
|
||||
private val preferences: SharedPreferences
|
||||
) : PreferenceSource {
|
||||
|
||||
companion object {
|
||||
const val keyModes = "satModes"
|
||||
const val keyCompass = "compass"
|
||||
const val keyTextLabels = "shouldUseTextLabels"
|
||||
const val keyTimeUTC = "timeUTC"
|
||||
const val keyHoursAhead = "hoursAhead"
|
||||
const val keyMinElevation = "minElevation"
|
||||
const val keyIsFirstLaunch = "shouldShowSplash"
|
||||
const val keyRotator = "isRotatorEnabled"
|
||||
const val keyRotatorAddress = "rotatorAddress"
|
||||
const val keyRotatorPort = "rotatorPort"
|
||||
const val keyLatitude = "stationLat"
|
||||
const val keyLongitude = "stationLon"
|
||||
const val keyAltitude = "stationAlt"
|
||||
const val keyPositionGPS = "setPositionGPS"
|
||||
const val keyPositionQTH = "setPositionQTH"
|
||||
}
|
||||
|
||||
override fun positionToQTH(lat: Double, lon: Double): String? {
|
||||
return qthConverter.positionToQTH(lat, lon)
|
||||
}
|
||||
|
||||
override fun loadStationPosition(): StationPosition {
|
||||
val defaultSP = "0.0"
|
||||
val latitude = preferences.getString(keyLatitude, null) ?: defaultSP
|
||||
val longitude = preferences.getString(keyLongitude, null) ?: defaultSP
|
||||
val altitude = preferences.getString(keyAltitude, null) ?: defaultSP
|
||||
return StationPosition(latitude.toDouble(), longitude.toDouble(), altitude.toDouble())
|
||||
}
|
||||
|
||||
override fun saveStationPosition(position: StationPosition) {
|
||||
preferences.edit {
|
||||
putString(keyLatitude, position.latitude.toString())
|
||||
putString(keyLongitude, position.longitude.toString())
|
||||
putString(keyAltitude, position.altitude.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun updatePositionFromGPS(): Boolean {
|
||||
return try {
|
||||
val location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
|
||||
if (location == null) false
|
||||
else {
|
||||
val latitude = location.latitude.round(4)
|
||||
val longitude = location.longitude.round(4)
|
||||
val altitude = location.altitude.round(1)
|
||||
val stationPosition = StationPosition(latitude, longitude, altitude)
|
||||
saveStationPosition(stationPosition)
|
||||
return true
|
||||
}
|
||||
} catch (exception: SecurityException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun updatePositionFromQTH(qthString: String): Boolean {
|
||||
val position = qthConverter.qthToPosition(qthString) ?: return false
|
||||
val stationPosition = StationPosition(position.latitude, position.longitude, 0.0)
|
||||
saveStationPosition(stationPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getMagDeclination(): Float {
|
||||
val stationPosition = loadStationPosition()
|
||||
val lat = stationPosition.latitude.toFloat()
|
||||
val lon = stationPosition.longitude.toFloat()
|
||||
val alt = stationPosition.altitude.toFloat()
|
||||
return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination
|
||||
}
|
||||
|
||||
override fun getHoursAhead(): Int {
|
||||
return preferences.getInt(keyHoursAhead, 8)
|
||||
}
|
||||
|
||||
override fun getMinElevation(): Double {
|
||||
return preferences.getInt(keyMinElevation, 16).toDouble()
|
||||
}
|
||||
|
||||
override fun shouldUseTextLabels(): Boolean {
|
||||
return preferences.getBoolean(keyTextLabels, false)
|
||||
}
|
||||
|
||||
override fun shouldUseUTC(): Boolean {
|
||||
return preferences.getBoolean(keyTimeUTC, false)
|
||||
}
|
||||
|
||||
override fun shouldUseCompass(): Boolean {
|
||||
return preferences.getBoolean(keyCompass, true)
|
||||
}
|
||||
|
||||
override fun isFirstLaunch(): Boolean {
|
||||
return preferences.getBoolean(keyIsFirstLaunch, true)
|
||||
}
|
||||
|
||||
override fun setFirstLaunchDone() {
|
||||
preferences.edit { putBoolean(keyIsFirstLaunch, false) }
|
||||
}
|
||||
|
||||
override fun saveModesSelection(modes: List<String>) {
|
||||
val modesSet = modes.toSet()
|
||||
preferences.edit {
|
||||
putStringSet(keyModes, modesSet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadModesSelection(): List<String> {
|
||||
preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
|
||||
return modesSet.toList().sorted()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getRotatorServer(): Pair<String, Int>? {
|
||||
return if (preferences.getBoolean(keyRotator, false)) {
|
||||
val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
|
||||
val port = preferences.getString(keyRotatorPort, null) ?: "4096"
|
||||
Pair(address, port.toInt())
|
||||
} else null
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.framework
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.rtbishop.look4sat.framework.model.TleSource
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class PrefsManager @Inject constructor(private val preferences: SharedPreferences, moshi: Moshi) {
|
||||
|
||||
private val sourcesType = Types.newParameterizedType(List::class.java, TleSource::class.java)
|
||||
private val sourcesAdapter = moshi.adapter<List<TleSource>>(sourcesType)
|
||||
|
||||
companion object {
|
||||
const val keySources = "sourcesListJson"
|
||||
const val keyModes = "satModes"
|
||||
const val keyCompass = "compass"
|
||||
const val keyTextLabels = "shouldUseTextLabels"
|
||||
const val keyTimeUTC = "timeUTC"
|
||||
const val keyHoursAhead = "hoursAhead"
|
||||
const val keyMinElevation = "minElevation"
|
||||
const val keyIsFirstLaunch = "shouldShowSplash"
|
||||
const val keyRotator = "isRotatorEnabled"
|
||||
const val keyRotatorAddress = "rotatorAddress"
|
||||
const val keyRotatorPort = "rotatorPort"
|
||||
}
|
||||
|
||||
fun getHoursAhead(): Int {
|
||||
return preferences.getInt(keyHoursAhead, 8)
|
||||
}
|
||||
|
||||
fun getMinElevation(): Double {
|
||||
return preferences.getInt(keyMinElevation, 16).toDouble()
|
||||
}
|
||||
|
||||
fun shouldUseTextLabels(): Boolean {
|
||||
return preferences.getBoolean(keyTextLabels, false)
|
||||
}
|
||||
|
||||
fun shouldUseUTC(): Boolean {
|
||||
return preferences.getBoolean(keyTimeUTC, false)
|
||||
}
|
||||
|
||||
fun shouldUseCompass(): Boolean {
|
||||
return preferences.getBoolean(keyCompass, true)
|
||||
}
|
||||
|
||||
fun isFirstLaunch(): Boolean {
|
||||
return preferences.getBoolean(keyIsFirstLaunch, true)
|
||||
}
|
||||
|
||||
fun setFirstLaunchDone() {
|
||||
preferences.edit { putBoolean(keyIsFirstLaunch, false) }
|
||||
}
|
||||
|
||||
fun loadTleSources(): List<TleSource> {
|
||||
return try {
|
||||
val sourcesString = preferences.getString(keySources, String())
|
||||
if (sourcesString.isNullOrEmpty()) {
|
||||
loadDefaultSources()
|
||||
} else {
|
||||
sourcesAdapter.fromJson(sourcesString) ?: loadDefaultSources()
|
||||
}
|
||||
} catch (exception: ClassCastException) {
|
||||
loadDefaultSources()
|
||||
}
|
||||
}
|
||||
|
||||
fun saveTleSources(sources: List<TleSource>) {
|
||||
val sourcesJson = sourcesAdapter.toJson(sources)
|
||||
preferences.edit { putString(keySources, sourcesJson) }
|
||||
}
|
||||
|
||||
fun loadDefaultSources(): List<TleSource> {
|
||||
return listOf(
|
||||
TleSource("https://celestrak.com/NORAD/elements/active.txt"),
|
||||
TleSource("https://amsat.org/tle/current/nasabare.txt"),
|
||||
TleSource("https://www.prismnet.com/~mmccants/tles/classfd.zip"),
|
||||
TleSource("https://www.prismnet.com/~mmccants/tles/inttles.zip")
|
||||
)
|
||||
}
|
||||
|
||||
fun saveModesSelection(modes: List<String>) {
|
||||
val modesSet = modes.toSet()
|
||||
preferences.edit {
|
||||
putStringSet(keyModes, modesSet)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadModesSelection(): List<String> {
|
||||
preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
|
||||
return modesSet.toList().sorted()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun getRotatorServer(): Pair<String, Int>? {
|
||||
return if (preferences.getBoolean(keyRotator, false)) {
|
||||
val address = preferences.getString(keyRotatorAddress, null) ?: "127.0.0.1"
|
||||
val port = preferences.getString(keyRotatorPort, null) ?: "4096"
|
||||
Pair(address, port.toInt())
|
||||
} else null
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ class RoomDataSource(private val satelliteDao: SatelliteDao) : LocalDataSource {
|
||||
satelliteDao.updateEntriesSelection(catNums, isSelected)
|
||||
}
|
||||
|
||||
override fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>> {
|
||||
override fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||
return satelliteDao.getSatTransmitters(catNum)
|
||||
.map { satTransList -> DataMapper.satTransListToDomainTransList(satTransList) }
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.framework.model
|
||||
|
||||
class TleSource(var url: String = String())
|
||||
@@ -25,7 +25,7 @@ import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import com.rtbishop.look4sat.utility.navigateSafe
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
@@ -34,7 +34,7 @@ import javax.inject.Inject
|
||||
class Look4SatActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
lateinit var preferenceSource: PreferencesProvider
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -45,8 +45,8 @@ class Look4SatActivity : AppCompatActivity() {
|
||||
setContentView(binding.root)
|
||||
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
|
||||
binding.navBottom.setupWithNavController(navHost.navController)
|
||||
if (prefsManager.isFirstLaunch()) {
|
||||
prefsManager.setFirstLaunchDone()
|
||||
if (preferenceSource.isFirstLaunch()) {
|
||||
preferenceSource.setFirstLaunchDone()
|
||||
navHost.navController.navigateSafe(R.id.nav_dialog_splash)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-20
@@ -22,18 +22,14 @@ import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
||||
import com.rtbishop.look4sat.domain.model.SatItem
|
||||
import com.rtbishop.look4sat.framework.model.TleSource
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||
import com.rtbishop.look4sat.utility.getNavResult
|
||||
import com.rtbishop.look4sat.utility.navigateSafe
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -42,7 +38,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
private val viewModel: EntriesViewModel by viewModels()
|
||||
private val contentContract = ActivityResultContracts.GetContent()
|
||||
private val filePicker = registerForActivityResult(contentContract) { uri ->
|
||||
uri?.let { viewModel.importSatDataFromFile(uri) }
|
||||
uri?.let { viewModel.updateEntriesFromFile(uri) }
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -62,9 +58,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light))
|
||||
}
|
||||
importWeb.setOnClickListener {
|
||||
findNavController().navigateSafe(R.id.action_entries_to_sources)
|
||||
}
|
||||
importWeb.setOnClickListener { viewModel.updateEntriesFromWeb(null) }
|
||||
importFile.setOnClickListener { filePicker.launch("*/*") }
|
||||
selectMode.setOnClickListener { viewModel.createModesDialog(requireContext()).show() }
|
||||
selectAll.setOnClickListener { viewModel.selectCurrentItems() }
|
||||
@@ -73,9 +67,6 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
viewModel.satData.observe(viewLifecycleOwner, { satData ->
|
||||
handleSatData(satData, binding, entriesAdapter)
|
||||
})
|
||||
getNavResult<List<String>>(R.id.nav_entries, "sources") { navResult ->
|
||||
handleNavResult(navResult)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSatData(
|
||||
@@ -97,15 +88,11 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
is Result.Error -> {
|
||||
binding.entriesProgress.visibility = View.INVISIBLE
|
||||
binding.entriesRecycler.visibility = View.VISIBLE
|
||||
Snackbar.make(requireView(), R.string.entries_update_error, Snackbar.LENGTH_SHORT)
|
||||
.setAnchorView(R.id.nav_bottom).show()
|
||||
val errorMsg = getString(R.string.entries_update_error)
|
||||
Snackbar.make(requireView(), errorMsg, Snackbar.LENGTH_SHORT).apply {
|
||||
setAnchorView(R.id.nav_bottom)
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNavResult(result: List<String>) {
|
||||
result.map { sourceUrl -> TleSource(sourceUrl) }.let { sources ->
|
||||
viewModel.importSatDataFromSources(sources)
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-29
@@ -26,32 +26,29 @@ import androidx.lifecycle.*
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.domain.model.SatItem
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
import com.rtbishop.look4sat.framework.model.TleSource
|
||||
import com.rtbishop.look4sat.interactors.GetSatItems
|
||||
import com.rtbishop.look4sat.interactors.ImportDataFromStream
|
||||
import com.rtbishop.look4sat.interactors.ImportDataFromWeb
|
||||
import com.rtbishop.look4sat.interactors.UpdateEntriesFromFile
|
||||
import com.rtbishop.look4sat.interactors.UpdateEntriesFromWeb
|
||||
import com.rtbishop.look4sat.interactors.UpdateEntriesSelection
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@HiltViewModel
|
||||
class EntriesViewModel @Inject constructor(
|
||||
private val prefsManager: PrefsManager,
|
||||
private val preferenceSource: PreferencesProvider,
|
||||
private val resolver: ContentResolver,
|
||||
private val getSatItems: GetSatItems,
|
||||
private val importDataFromStream: ImportDataFromStream,
|
||||
private val importDataFromWeb: ImportDataFromWeb,
|
||||
private val updateEntriesFromFile: UpdateEntriesFromFile,
|
||||
private val updateEntriesFromWeb: UpdateEntriesFromWeb,
|
||||
private val updateEntriesSelection: UpdateEntriesSelection,
|
||||
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
||||
|
||||
private val transModes = MutableLiveData(prefsManager.loadModesSelection())
|
||||
private val transModes = MutableLiveData(preferenceSource.loadModesSelection())
|
||||
private val currentQuery = MutableLiveData(String())
|
||||
private val itemsWithModes = transModes.switchMap { modes ->
|
||||
liveData { getSatItems().collect { emit(filterByModes(it, modes)) } }
|
||||
@@ -65,32 +62,22 @@ class EntriesViewModel @Inject constructor(
|
||||
private var shouldSelectAll = true
|
||||
val satData: LiveData<Result<List<SatItem>>> = _satData
|
||||
|
||||
fun importSatDataFromFile(uri: Uri) {
|
||||
fun updateEntriesFromFile(uri: Uri) {
|
||||
viewModelScope.launch {
|
||||
_satData.value = Result.InProgress
|
||||
runCatching {
|
||||
resolver.openInputStream(uri)?.use { stream ->
|
||||
importDataFromStream(stream)
|
||||
}
|
||||
resolver.openInputStream(uri)?.use { stream -> updateEntriesFromFile(stream) }
|
||||
}.onFailure { _satData.value = Result.Error(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun importSatDataFromSources(sources: List<TleSource>) {
|
||||
fun updateEntriesFromWeb(sources: List<String>?) {
|
||||
viewModelScope.launch {
|
||||
_satData.value = Result.InProgress
|
||||
val satSources = if (sources.isNotEmpty()) sources
|
||||
else prefsManager.loadDefaultSources()
|
||||
val updateMillis = measureTimeMillis {
|
||||
try {
|
||||
prefsManager.saveTleSources(satSources)
|
||||
importDataFromWeb(satSources.map { it.url })
|
||||
} catch (exception: Exception) {
|
||||
_satData.value = Result.Error(exception)
|
||||
Timber.d(exception)
|
||||
}
|
||||
}
|
||||
Timber.d("Update from WEB took $updateMillis ms")
|
||||
runCatching {
|
||||
if (sources == null) updateEntriesFromWeb()
|
||||
else updateEntriesFromWeb(sources)
|
||||
}.onFailure { _satData.value = Result.Error(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +98,7 @@ class EntriesViewModel @Inject constructor(
|
||||
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
|
||||
)
|
||||
val savedModes = BooleanArray(modes.size)
|
||||
val selectedModes = prefsManager.loadModesSelection().toMutableList()
|
||||
val selectedModes = preferenceSource.loadModesSelection().toMutableList()
|
||||
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
|
||||
val dialogBuilder = MaterialAlertDialogBuilder(context).apply {
|
||||
setTitle(context.getString(R.string.modes_title))
|
||||
@@ -123,7 +110,7 @@ class EntriesViewModel @Inject constructor(
|
||||
}
|
||||
setPositiveButton(context.getString(android.R.string.ok)) { _, _ ->
|
||||
transModes.value = selectedModes
|
||||
prefsManager.saveModesSelection(selectedModes)
|
||||
preferenceSource.saveModesSelection(selectedModes)
|
||||
}
|
||||
setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
package com.rtbishop.look4sat.presentation.mapScreen
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import com.rtbishop.look4sat.data.LocationRepo
|
||||
import com.rtbishop.look4sat.data.PreferenceSource
|
||||
import com.rtbishop.look4sat.di.DefaultDispatcher
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.Position
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
import com.rtbishop.look4sat.framework.model.SatData
|
||||
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
@@ -38,12 +37,11 @@ import kotlin.math.sqrt
|
||||
@HiltViewModel
|
||||
class MapViewModel @Inject constructor(
|
||||
private val getSelectedSatellites: GetSelectedSatellites,
|
||||
private val prefsManager: PrefsManager,
|
||||
private val locationRepo: LocationRepo,
|
||||
private val preferenceSource: PreferenceSource,
|
||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
||||
) : ViewModel() {
|
||||
|
||||
private val gsp = locationRepo.getStationPosition()
|
||||
private val gsp = preferenceSource.loadStationPosition()
|
||||
private var dataUpdateJob: Job? = null
|
||||
private var allSatList = listOf<Satellite>()
|
||||
private lateinit var selectedSat: Satellite
|
||||
@@ -78,7 +76,7 @@ class MapViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun shouldUseTextLabels(): Boolean {
|
||||
return prefsManager.shouldUseTextLabels()
|
||||
return preferenceSource.shouldUseTextLabels()
|
||||
}
|
||||
|
||||
fun scrollSelection(decrement: Boolean) {
|
||||
@@ -172,7 +170,8 @@ class MapViewModel @Inject constructor(
|
||||
val osmLat = getOsmLat(Math.toDegrees(satPos.latitude))
|
||||
val osmLon = getOsmLon(Math.toDegrees(satPos.longitude))
|
||||
val osmPos = Position(osmLat, osmLon)
|
||||
val qthLoc = locationRepo.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
||||
val qthLoc =
|
||||
preferenceSource.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
|
||||
val velocity = getOrbitalVelocity(satPos.altitude)
|
||||
val satData = SatData(
|
||||
sat, sat.tle.catnum, sat.tle.name, satPos.range,
|
||||
|
||||
+4
-4
@@ -22,10 +22,10 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
import com.rtbishop.look4sat.utility.PassesRepo
|
||||
import com.rtbishop.look4sat.data.PassesRepo
|
||||
import com.rtbishop.look4sat.interactors.GetSelectedSatellites
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@@ -35,7 +35,7 @@ import javax.inject.Inject
|
||||
class PassesViewModel @Inject constructor(
|
||||
private val getSelectedSatellites: GetSelectedSatellites,
|
||||
private val passesRepo: PassesRepo,
|
||||
private val prefsManager: PrefsManager
|
||||
private val preferenceSource: PreferencesProvider
|
||||
) : ViewModel() {
|
||||
|
||||
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
||||
@@ -64,7 +64,7 @@ class PassesViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun shouldUseUTC(): Boolean {
|
||||
return prefsManager.shouldUseUTC()
|
||||
return preferenceSource.shouldUseUTC()
|
||||
}
|
||||
|
||||
private suspend fun tickPasses(passes: List<SatPass>) = withContext(Dispatchers.Default) {
|
||||
|
||||
+10
-12
@@ -18,14 +18,13 @@
|
||||
package com.rtbishop.look4sat.presentation.polarScreen
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import com.rtbishop.look4sat.data.LocationRepo
|
||||
import com.rtbishop.look4sat.data.PreferenceSource
|
||||
import com.rtbishop.look4sat.di.IoDispatcher
|
||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||
import com.rtbishop.look4sat.interactors.GetTransmittersForSat
|
||||
import com.rtbishop.look4sat.interactors.GetSatTransmitters
|
||||
import com.rtbishop.look4sat.framework.OrientationProvider
|
||||
import com.rtbishop.look4sat.utility.PassesRepo
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import com.rtbishop.look4sat.data.PassesRepo
|
||||
import com.rtbishop.look4sat.utility.round
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.*
|
||||
@@ -37,11 +36,10 @@ import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class PolarViewModel @Inject constructor(
|
||||
private val locationRepo: LocationRepo,
|
||||
private val orientationProvider: OrientationProvider,
|
||||
private val prefsManager: PrefsManager,
|
||||
private val preferenceSource: PreferenceSource,
|
||||
private val passesRepo: PassesRepo,
|
||||
private val getTransmittersForSat: GetTransmittersForSat,
|
||||
private val getSatTransmitters: GetSatTransmitters,
|
||||
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
||||
) : ViewModel(), OrientationProvider.OrientationListener {
|
||||
|
||||
@@ -62,20 +60,20 @@ class PolarViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun enableSensor() {
|
||||
if (prefsManager.shouldUseCompass()) orientationProvider.startListening(this)
|
||||
if (preferenceSource.shouldUseCompass()) orientationProvider.startListening(this)
|
||||
}
|
||||
|
||||
fun disableSensor() {
|
||||
if (prefsManager.shouldUseCompass()) orientationProvider.stopListening()
|
||||
if (preferenceSource.shouldUseCompass()) orientationProvider.stopListening()
|
||||
}
|
||||
|
||||
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
||||
_orientation.value = Triple(azimuth + locationRepo.getMagDeclination(), pitch, roll)
|
||||
_orientation.value = Triple(azimuth + preferenceSource.getMagDeclination(), pitch, roll)
|
||||
}
|
||||
|
||||
private fun initRotatorControl(satPass: SatPass) {
|
||||
viewModelScope.launch {
|
||||
val rotatorPrefs = prefsManager.getRotatorServer()
|
||||
val rotatorPrefs = preferenceSource.getRotatorServer()
|
||||
if (rotatorPrefs != null) {
|
||||
runCatching {
|
||||
withContext(ioDispatcher) {
|
||||
@@ -99,7 +97,7 @@ class PolarViewModel @Inject constructor(
|
||||
|
||||
private fun processTransmitters(satPass: SatPass) {
|
||||
viewModelScope.launch {
|
||||
getTransmittersForSat(satPass.catNum).collect { transList ->
|
||||
getSatTransmitters(satPass.catNum).collect { transList ->
|
||||
while (isActive) {
|
||||
val timeNow = Date()
|
||||
val copiedList = transList.map { it.copy() }
|
||||
|
||||
@@ -30,9 +30,8 @@ import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.LocationRepo
|
||||
import com.rtbishop.look4sat.framework.DefaultLocationSource
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import com.rtbishop.look4sat.data.PreferenceSource
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -40,10 +39,7 @@ import javax.inject.Inject
|
||||
class PrefsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
@Inject
|
||||
lateinit var locationRepo: LocationRepo
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
lateinit var preferenceSource: PreferenceSource
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
@@ -61,20 +57,20 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
findPreference<Preference>(DefaultLocationSource.keyPositionGPS)?.apply {
|
||||
findPreference<Preference>(PreferencesProvider.keyPositionGPS)?.apply {
|
||||
setOnPreferenceClickListener {
|
||||
updatePositionFromGPS()
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<Preference>(DefaultLocationSource.keyPositionQTH)?.apply {
|
||||
findPreference<Preference>(PreferencesProvider.keyPositionQTH)?.apply {
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
updatePositionFromQth(newValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<EditTextPreference>(PrefsManager.keyRotatorAddress)?.apply {
|
||||
findPreference<EditTextPreference>(PreferencesProvider.keyRotatorAddress)?.apply {
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
if (Patterns.IP_ADDRESS.matcher(newValue.toString()).matches()) {
|
||||
return@setOnPreferenceChangeListener true
|
||||
@@ -85,7 +81,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<EditTextPreference>(PrefsManager.keyRotatorPort)?.apply {
|
||||
findPreference<EditTextPreference>(PreferencesProvider.keyRotatorPort)?.apply {
|
||||
setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER }
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val portValue = newValue.toString()
|
||||
@@ -100,7 +96,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
private fun updatePositionFromQth(qthString: String): Boolean {
|
||||
return if (locationRepo.updatePositionFromQTH(qthString)) {
|
||||
return if (preferenceSource.updatePositionFromQTH(qthString)) {
|
||||
showSnack(getString(R.string.pref_pos_success))
|
||||
true
|
||||
} else {
|
||||
@@ -113,7 +109,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
|
||||
val locPermString = Manifest.permission.ACCESS_FINE_LOCATION
|
||||
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
||||
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
||||
if (locationRepo.updatePositionFromGPS()) {
|
||||
if (preferenceSource.updatePositionFromGPS()) {
|
||||
showSnack(getString(R.string.pref_pos_success))
|
||||
} else showSnack(getString(R.string.pref_pos_gps_null))
|
||||
} else requestPermissionLauncher.launch(locPermString)
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.sourcesDialog
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.databinding.ItemTleSourceBinding
|
||||
import com.rtbishop.look4sat.framework.model.TleSource
|
||||
|
||||
class SourcesAdapter(private val sources: MutableList<TleSource> = mutableListOf()) :
|
||||
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
|
||||
|
||||
fun getSources(): List<TleSource> {
|
||||
return sources.filter { it.url.contains("https://") }
|
||||
}
|
||||
|
||||
fun setSources(list: List<TleSource>) {
|
||||
sources.clear()
|
||||
sources.addAll(list)
|
||||
}
|
||||
|
||||
fun addSource() {
|
||||
sources.add(TleSource())
|
||||
notifyItemInserted(itemCount - 1)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TleSourceHolder {
|
||||
val binding = ItemTleSourceBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return TleSourceHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TleSourceHolder, position: Int) {
|
||||
holder.bind(sources[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return sources.size
|
||||
}
|
||||
|
||||
inner class TleSourceHolder(private val binding: ItemTleSourceBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(source: TleSource) {
|
||||
binding.tleSourceUrl.setText(source.url)
|
||||
binding.tleSourceUrl.doOnTextChanged { text, _, _, _ -> source.url = text.toString() }
|
||||
binding.tleSourceInputLayout.setEndIconOnClickListener {
|
||||
sources.remove(source)
|
||||
notifyItemRemoved(adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.sourcesDialog
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
|
||||
import com.rtbishop.look4sat.utility.setNavResult
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SourcesDialog : AppCompatDialogFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_sources, group, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, state: Bundle?) {
|
||||
super.onViewCreated(view, state)
|
||||
val sourcesAdapter = SourcesAdapter().apply { setSources(prefsManager.loadTleSources()) }
|
||||
DialogSourcesBinding.bind(view).apply {
|
||||
dialog?.window?.setLayout(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
sourcesRecycler.apply {
|
||||
adapter = sourcesAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
}
|
||||
sourceBtnAdd.setOnClickListener {
|
||||
sourcesAdapter.addSource()
|
||||
}
|
||||
sourcesBtnPos.setOnClickListener {
|
||||
setNavResult("sources", sourcesAdapter.getSources().map { it.url })
|
||||
dismiss()
|
||||
}
|
||||
sourcesBtnNeg.setOnClickListener { dismiss() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,9 @@ package com.rtbishop.look4sat.utility
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.Navigator
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
fun Long.toTimerString(): String {
|
||||
@@ -53,26 +49,3 @@ fun NavController.navigateSafe(
|
||||
navigate(resId, args, navOptions, navExtras)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Fragment.setNavResult(key: String, value: T) {
|
||||
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
|
||||
}
|
||||
|
||||
fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
|
||||
val navBackStackEntry = findNavController().getBackStackEntry(id)
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME
|
||||
&& navBackStackEntry.savedStateHandle.contains(key)
|
||||
) {
|
||||
val result = navBackStackEntry.savedStateHandle.get<T>(key)
|
||||
result?.let(onResult)
|
||||
navBackStackEntry.savedStateHandle.remove<T>(key)
|
||||
}
|
||||
}
|
||||
navBackStackEntry.lifecycle.addObserver(observer)
|
||||
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||
navBackStackEntry.lifecycle.removeObserver(observer)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -16,13 +16,6 @@
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_entries_to_sources"
|
||||
app:destination="@id/nav_dialog_sources"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
@@ -66,10 +59,6 @@
|
||||
android:id="@+id/nav_info"
|
||||
android:name="com.rtbishop.look4sat.presentation.infoScreen.InfoFragment"
|
||||
tools:layout="@layout/fragment_info" />
|
||||
<dialog
|
||||
android:id="@+id/nav_dialog_sources"
|
||||
android:name="com.rtbishop.look4sat.presentation.sourcesDialog.SourcesDialog"
|
||||
tools:layout="@layout/dialog_sources" />
|
||||
<dialog
|
||||
android:id="@+id/nav_dialog_splash"
|
||||
android:name="com.rtbishop.look4sat.presentation.splashDialog.SplashDialog"
|
||||
|
||||
@@ -10,13 +10,13 @@ interface LocalDataSource {
|
||||
|
||||
fun getSatItems(): Flow<List<SatItem>>
|
||||
|
||||
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>>
|
||||
|
||||
suspend fun getSelectedSatellites(): List<Satellite>
|
||||
|
||||
suspend fun updateEntries(entries: List<SatEntry>)
|
||||
|
||||
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean)
|
||||
|
||||
fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>>
|
||||
|
||||
suspend fun updateTransmitters(satelliteTrans: List<SatTrans>)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
|
||||
class LocationRepo(
|
||||
private val locationSource: LocationSource,
|
||||
private val qthConverter: QthConverter
|
||||
) {
|
||||
|
||||
fun getStationPosition(): StationPosition {
|
||||
return locationSource.loadStationPosition()
|
||||
}
|
||||
|
||||
fun getMagDeclination(): Float {
|
||||
return locationSource.getMagDeclination(getStationPosition())
|
||||
}
|
||||
|
||||
fun positionToQTH(lat: Double, lon: Double): String? {
|
||||
return qthConverter.positionToQTH(lat, lon)
|
||||
}
|
||||
|
||||
fun updatePositionFromGPS(): Boolean {
|
||||
val stationPosition = locationSource.getLastKnownLocation() ?: return false
|
||||
locationSource.saveStationPosition(stationPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
fun updatePositionFromQTH(qthString: String): Boolean {
|
||||
val position = qthConverter.qthToPosition(qthString) ?: return false
|
||||
val stationPosition = StationPosition(position.latitude, position.longitude, 0.0)
|
||||
locationSource.saveStationPosition(stationPosition)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
|
||||
interface LocationSource {
|
||||
|
||||
fun getLastKnownLocation(): StationPosition?
|
||||
|
||||
fun getMagDeclination(position: StationPosition): Float
|
||||
|
||||
fun loadStationPosition(): StationPosition
|
||||
|
||||
fun saveStationPosition(position: StationPosition)
|
||||
}
|
||||
+8
-15
@@ -15,26 +15,19 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.utility
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.rtbishop.look4sat.data.LocationRepo
|
||||
import com.rtbishop.look4sat.di.DefaultDispatcher
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.SatPass
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.Satellite
|
||||
import com.rtbishop.look4sat.framework.PrefsManager
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class PassesRepo @Inject constructor(
|
||||
private val locationRepo: LocationRepo,
|
||||
private val prefsManager: PrefsManager,
|
||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
||||
class PassesRepo(
|
||||
private val preferenceSource: PreferenceSource,
|
||||
private val defaultDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
private val _passes = MutableSharedFlow<List<SatPass>>(replay = 1)
|
||||
private var selectedSatellites = emptyList<Satellite>()
|
||||
@@ -64,15 +57,15 @@ class PassesRepo @Inject constructor(
|
||||
}
|
||||
|
||||
private fun getPasses(satellite: Satellite, refDate: Date): List<SatPass> {
|
||||
val predictor = satellite.getPredictor(locationRepo.getStationPosition())
|
||||
return predictor.getPasses(refDate, prefsManager.getHoursAhead(), true)
|
||||
val predictor = satellite.getPredictor(preferenceSource.loadStationPosition())
|
||||
return predictor.getPasses(refDate, preferenceSource.getHoursAhead(), true)
|
||||
}
|
||||
|
||||
private fun filterPasses(passes: List<SatPass>, refDate: Date): List<SatPass> {
|
||||
val timeFuture = Date(refDate.time + (prefsManager.getHoursAhead() * 3600 * 1000))
|
||||
val timeFuture = Date(refDate.time + (preferenceSource.getHoursAhead() * 3600 * 1000))
|
||||
return passes.filter { it.losDate.after(refDate) }
|
||||
.filter { it.aosDate.before(timeFuture) }
|
||||
.filter { it.maxElevation > prefsManager.getMinElevation() }
|
||||
.filter { it.maxElevation > preferenceSource.getMinElevation() }
|
||||
.sortedBy { it.aosDate }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
|
||||
interface PreferenceSource {
|
||||
|
||||
fun positionToQTH(lat: Double, lon: Double): String?
|
||||
|
||||
fun loadStationPosition(): StationPosition
|
||||
|
||||
fun saveStationPosition(position: StationPosition)
|
||||
|
||||
fun updatePositionFromGPS(): Boolean
|
||||
|
||||
fun updatePositionFromQTH(qthString: String): Boolean
|
||||
|
||||
fun getMagDeclination(): Float
|
||||
|
||||
fun getHoursAhead(): Int
|
||||
|
||||
fun getMinElevation(): Double
|
||||
|
||||
fun shouldUseTextLabels(): Boolean
|
||||
|
||||
fun shouldUseUTC(): Boolean
|
||||
|
||||
fun shouldUseCompass(): Boolean
|
||||
|
||||
fun isFirstLaunch(): Boolean
|
||||
|
||||
fun setFirstLaunchDone()
|
||||
|
||||
fun saveModesSelection(modes: List<String>)
|
||||
|
||||
fun loadModesSelection(): List<String>
|
||||
|
||||
fun getRotatorServer(): Pair<String, Int>?
|
||||
}
|
||||
@@ -22,24 +22,23 @@ class SatelliteRepo(
|
||||
return localSource.getSatItems()
|
||||
}
|
||||
|
||||
fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>> {
|
||||
return localSource.getTransmittersForSat(catNum)
|
||||
fun getSatTransmitters(catNum: Int): Flow<List<SatTrans>> {
|
||||
return localSource.getSatTransmitters(catNum)
|
||||
}
|
||||
|
||||
suspend fun getSelectedSatellites(): List<Satellite> {
|
||||
return localSource.getSelectedSatellites()
|
||||
}
|
||||
|
||||
suspend fun importDataFromStream(stream: InputStream) = withContext(ioDispatcher) {
|
||||
val importedEntries = Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
||||
localSource.updateEntries(importedEntries)
|
||||
suspend fun updateEntriesFromFile(stream: InputStream) = withContext(ioDispatcher) {
|
||||
localSource.updateEntries(importSatEntries(stream))
|
||||
}
|
||||
|
||||
suspend fun importDataFromWeb(sources: List<String>) {
|
||||
suspend fun updateEntriesFromWeb(sources: List<String>) {
|
||||
coroutineScope {
|
||||
launch(ioDispatcher) {
|
||||
val importedEntries = mutableListOf<SatEntry>()
|
||||
val streams = mutableListOf<InputStream>()
|
||||
val entries = mutableListOf<SatEntry>()
|
||||
sources.forEach { source ->
|
||||
remoteSource.fetchDataStream(source)?.let { stream ->
|
||||
if (source.contains(".zip", true)) {
|
||||
@@ -50,11 +49,8 @@ class SatelliteRepo(
|
||||
}
|
||||
}
|
||||
}
|
||||
streams.forEach { stream ->
|
||||
val entries = Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
||||
importedEntries.addAll(entries)
|
||||
}
|
||||
localSource.updateEntries(importedEntries)
|
||||
streams.forEach { stream -> entries.addAll(importSatEntries(stream)) }
|
||||
localSource.updateEntries(entries)
|
||||
}
|
||||
launch(ioDispatcher) {
|
||||
val transmitters = remoteSource.fetchTransmitters().filter { it.isAlive }
|
||||
@@ -66,4 +62,8 @@ class SatelliteRepo(
|
||||
suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||
localSource.updateEntriesSelection(catNums, isSelected)
|
||||
}
|
||||
|
||||
private fun importSatEntries(stream: InputStream): List<SatEntry> {
|
||||
return Satellite.importElements(stream).map { tle -> SatEntry(tle) }
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -4,9 +4,9 @@ import com.rtbishop.look4sat.data.SatelliteRepo
|
||||
import com.rtbishop.look4sat.domain.model.SatTrans
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class GetTransmittersForSat(private val satelliteRepo: SatelliteRepo) {
|
||||
class GetSatTransmitters(private val satelliteRepo: SatelliteRepo) {
|
||||
|
||||
operator fun invoke(catNum: Int): Flow<List<SatTrans>> {
|
||||
return satelliteRepo.getTransmittersForSat(catNum)
|
||||
return satelliteRepo.getSatTransmitters(catNum)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.rtbishop.look4sat.interactors
|
||||
|
||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||
|
||||
class ImportDataFromWeb(private val satelliteRepo: SatelliteRepo) {
|
||||
|
||||
suspend operator fun invoke(sources: List<String>) {
|
||||
satelliteRepo.importDataFromWeb(sources)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -3,9 +3,9 @@ package com.rtbishop.look4sat.interactors
|
||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||
import java.io.InputStream
|
||||
|
||||
class ImportDataFromStream(private val satelliteRepo: SatelliteRepo) {
|
||||
class UpdateEntriesFromFile(private val satelliteRepo: SatelliteRepo) {
|
||||
|
||||
suspend operator fun invoke(stream: InputStream) {
|
||||
satelliteRepo.importDataFromStream(stream)
|
||||
satelliteRepo.updateEntriesFromFile(stream)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.rtbishop.look4sat.interactors
|
||||
|
||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||
|
||||
class UpdateEntriesFromWeb(private val satelliteRepo: SatelliteRepo) {
|
||||
|
||||
private val defaultSources = listOf(
|
||||
"https://celestrak.com/NORAD/elements/active.txt",
|
||||
"https://amsat.org/tle/current/nasabare.txt",
|
||||
"https://www.prismnet.com/~mmccants/tles/classfd.zip",
|
||||
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
||||
)
|
||||
|
||||
suspend operator fun invoke(sources: List<String> = defaultSources) {
|
||||
satelliteRepo.updateEntriesFromWeb(sources)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user