diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 88b972cc..653a6688 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,4 +23,4 @@ - \ No newline at end of file + diff --git a/app/src/main/java/com/rtbishop/look4sat/Look4SatApp.kt b/app/src/main/java/com/rtbishop/look4sat/Look4SatApp.kt index ac716654..ef73006b 100644 --- a/app/src/main/java/com/rtbishop/look4sat/Look4SatApp.kt +++ b/app/src/main/java/com/rtbishop/look4sat/Look4SatApp.kt @@ -29,4 +29,4 @@ class Look4SatApp : Application() { Timber.plant(Timber.DebugTree()) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt b/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt index 26653565..d9772c4d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt +++ b/app/src/main/java/com/rtbishop/look4sat/data/repository/PassesRepo.kt @@ -41,8 +41,10 @@ class PassesRepo @Inject constructor( private var selectedSatellites = emptyList() suspend fun calculatePasses(satellites: List) { - if (satellites !== selectedSatellites) { - withContext(defaultDispatcher) { + withContext(defaultDispatcher) { + val newCatNums = satellites.map { it.tle.catnum } + val oldCatNums = selectedSatellites.map { it.tle.catnum } + if (newCatNums != oldCatNums) { _passes.value = Result.InProgress selectedSatellites = satellites val refDate = Date(System.currentTimeMillis()) @@ -75,4 +77,4 @@ class PassesRepo @Inject constructor( passes.sortBy { it.pass.startTime } return passes } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt b/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt index 22335213..ac3c1529 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt @@ -43,4 +43,4 @@ class MainActivity : AppCompatActivity() { if (prefsRepo.isFirstLaunch()) navHost.navController.navigate(R.id.nav_dialog_splash) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt index c08a699a..c2f6bebd 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt @@ -17,26 +17,24 @@ */ package com.rtbishop.look4sat.ui -import androidx.lifecycle.* -import com.github.amsacode.predict4java.Satellite +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData +import androidx.lifecycle.liveData import com.rtbishop.look4sat.data.model.Result import com.rtbishop.look4sat.data.model.SatPass import com.rtbishop.look4sat.data.repository.PrefsRepo import com.rtbishop.look4sat.data.repository.SatelliteRepo -import com.rtbishop.look4sat.utility.getPredictor import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.launch -import java.util.* import javax.inject.Inject @FlowPreview @HiltViewModel class SharedViewModel @Inject constructor( - private val prefsRepo: PrefsRepo, + prefsRepo: PrefsRepo, private val satelliteRepo: SatelliteRepo, ) : ViewModel() { @@ -47,7 +45,6 @@ class SharedViewModel @Inject constructor( if (prefsRepo.isFirstLaunch()) { prefsRepo.setFirstLaunchDone() } - calculatePasses() } fun getAppTimer() = liveData { @@ -58,36 +55,4 @@ class SharedViewModel @Inject constructor( } fun getTransmittersForSat(satId: Int) = satelliteRepo.getSatTransmitters(satId).asLiveData() - - fun calculatePasses(dateNow: Date = Date(System.currentTimeMillis())) { - _passes.value = Result.InProgress - viewModelScope.launch(Dispatchers.Default) { - val passes = mutableListOf() - satelliteRepo.getSelectedSatellites().forEach { satellite -> - passes.addAll(getPasses(satellite, dateNow)) - } - val filteredPasses = sortList(passes, dateNow) - _passes.value = Result.Success(filteredPasses) - } - } - - private fun getPasses(satellite: Satellite, dateNow: Date): MutableList { - val predictor = satellite.getPredictor(prefsRepo.getStationPosition()) - val passes = predictor.getPasses(dateNow, prefsRepo.getHoursAhead(), true) - val passList = passes.map { SatPass(satellite.tle, predictor, it) } - return passList as MutableList - } - - private fun sortList(passes: MutableList, dateNow: Date): MutableList { - val hoursAhead = prefsRepo.getHoursAhead() - val dateFuture = Calendar.getInstance().apply { - this.time = dateNow - this.add(Calendar.HOUR, hoursAhead) - }.time - passes.removeAll { it.pass.startTime.after(dateFuture) } - passes.removeAll { it.pass.endTime.before(dateNow) } - passes.removeAll { it.pass.maxEl < prefsRepo.getMinElevation() } - passes.sortBy { it.pass.startTime } - return passes - } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt index 6f7ac96c..e1779c67 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesFragment.kt @@ -145,4 +145,4 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr binding = null super.onDestroyView() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt index 8ddff484..98347132 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/entriesScreen/EntriesViewModel.kt @@ -79,4 +79,4 @@ class EntriesViewModel @Inject constructor( satelliteRepo.updateEntriesSelection(items, isSelected) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt index 47ad5d01..cab2a7ff 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapFragment.kt @@ -204,4 +204,4 @@ class MapFragment : Fragment(R.layout.fragment_map) { ) return XYTileSource("wikimedia", 0, 6, 256, ".png", sources, copyright, policy) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapViewModel.kt index 73637d62..8bd56e6d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/mapScreen/MapViewModel.kt @@ -196,4 +196,4 @@ class MapViewModel @Inject constructor( Position(osmLat, osmLon) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt index 5690f43d..da136fd6 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesFragment.kt @@ -20,32 +20,26 @@ package com.rtbishop.look4sat.ui.passesScreen import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator import com.rtbishop.look4sat.R import com.rtbishop.look4sat.data.model.Result import com.rtbishop.look4sat.data.model.SatPass import com.rtbishop.look4sat.databinding.FragmentPassesBinding -import com.rtbishop.look4sat.ui.SharedViewModel -import com.rtbishop.look4sat.data.repository.PrefsRepo import com.rtbishop.look4sat.utility.RecyclerDivider import com.rtbishop.look4sat.utility.formatForTimer import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.FlowPreview import java.util.* -import javax.inject.Inject @FlowPreview @AndroidEntryPoint class PassesFragment : Fragment(R.layout.fragment_passes) { - @Inject - lateinit var prefsRepo: PrefsRepo - private var binding: FragmentPassesBinding? = null private var passesAdapter: PassesAdapter? = null - private val viewModel: SharedViewModel by activityViewModels() + private val viewModel: PassesViewModel by viewModels() private var passes = mutableListOf() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -90,7 +84,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes) { } private fun setupComponents() { - passesAdapter = PassesAdapter(requireContext(), prefsRepo.shouldUseUTC()) + passesAdapter = PassesAdapter(requireContext(), viewModel.shouldUseUTC()) binding?.apply { passesRecycler.apply { setHasFixedSize(true) @@ -100,7 +94,6 @@ class PassesFragment : Fragment(R.layout.fragment_passes) { (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark)) } - passesFab.setOnClickListener { viewModel.calculatePasses() } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt new file mode 100644 index 00000000..e11f91e2 --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/ui/passesScreen/PassesViewModel.kt @@ -0,0 +1,60 @@ +/* + * 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 . + */ +package com.rtbishop.look4sat.ui.passesScreen + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData +import androidx.lifecycle.liveData +import androidx.lifecycle.viewModelScope +import com.rtbishop.look4sat.data.repository.PassesRepo +import com.rtbishop.look4sat.data.repository.PrefsRepo +import com.rtbishop.look4sat.data.repository.SatelliteRepo +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class PassesViewModel @Inject constructor( + private val prefsRepo: PrefsRepo, + private val satelliteRepo: SatelliteRepo, + private val passesRepo: PassesRepo +) : ViewModel() { + + val passes = passesRepo.passes.asLiveData() + + init { + viewModelScope.launch { + satelliteRepo.getSelectedSatellitesFlow().collect { selectedSatellites -> + passesRepo.calculatePasses(selectedSatellites) + } + } + } + + fun getAppTimer() = liveData { + while (true) { + emit(System.currentTimeMillis()) + delay(1000) + } + } + + fun shouldUseUTC(): Boolean { + return prefsRepo.shouldUseUTC() + } +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt index 9339e50e..5ddf4d1f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/polarScreen/PolarView.kt @@ -127,4 +127,4 @@ class PolarView(context: Context) : View(context) { val radius = r * (piDiv2 - elevation) / piDiv2 return (radius * sin(piDiv2 - azimuth)).toFloat() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesAdapter.kt index af0ffe01..75fca2a8 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesAdapter.kt @@ -71,4 +71,4 @@ class SourcesAdapter : RecyclerView.Adapter() { } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesDialog.kt index 7580db9b..8120efbc 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesDialog.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/sourcesDialog/SourcesDialog.kt @@ -63,4 +63,4 @@ class SourcesDialog : AppCompatDialogFragment() { tleSourcesBtnNeg.setOnClickListener { dismiss() } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/splashDialog/SplashDialog.kt b/app/src/main/java/com/rtbishop/look4sat/ui/splashDialog/SplashDialog.kt index 5f0b453a..49df826d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/splashDialog/SplashDialog.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/splashDialog/SplashDialog.kt @@ -42,4 +42,4 @@ class SplashDialog : AppCompatDialogFragment() { splashButton.setOnClickListener { dismiss() } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/PassPredictor.kt b/app/src/main/java/com/rtbishop/look4sat/utility/PassPredictor.kt index 80c41794..e5609114 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/PassPredictor.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/PassPredictor.kt @@ -26,8 +26,7 @@ import java.util.* class PassPredictor(private val satellite: Satellite, private val qth: GroundStationPosition) { private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt() private val speedOfLight = 2.99792458E8 - private val polePassed = "none" - + fun getDownlinkFreq(freq: Long, date: Date): Long { val rangeRate = getSatPos(date).rangeRate return (freq.toDouble() * (speedOfLight - rangeRate * 1000.0) / speedOfLight).toLong() @@ -47,7 +46,6 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta val endDate = Date(refDate.time + minAfter * 60L * 1000L) val startDate = Date(refDate.time - minBefore * 60L * 1000L) var currentDate = startDate - while (currentDate.before(endDate)) { positions.add(getSatPos(currentDate)) currentDate = Date(currentDate.time + stepSeconds * 1000) @@ -62,7 +60,6 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta var shouldWindBack = windBack var lastAosDate: Date var count = 0 - if (satellite.willBeSeen(qth)) { if (satellite.tle.isDeepspace) { passes.add(nextDeepSpacePass(refDate)) @@ -87,7 +84,7 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta val aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt() val losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt() val maxEl = satPos.elevation / (2.0 * Math.PI) * 360.0 - return SatPassTime(startDate, endDate, polePassed, aosAzimuth, losAzimuth, maxEl) + return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl) } private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime { @@ -101,27 +98,26 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta // wind back time 1/4 of an orbit if (windBack) calendar.add(Calendar.MINUTE, -oneQuarterOrbitMin) var satPos = getSatPos(calendar.time) - - // test for the elevation being above the horizon + if (satPos.elevation > 0.0) { - // move time forward in 30 second intervals until the sat goes below the horizon + // move forward in 30 second intervals until the sat goes below the horizon do { calendar.add(Calendar.SECOND, 30) satPos = getSatPos(calendar.time) } while (satPos.elevation > 0.0) - // move time forward 3/4 orbit + // move forward 3/4 of an orbit calendar.add(Calendar.MINUTE, oneQuarterOrbitMin * 3) } - - // find the next time it comes above the horizon + + // find the next time sat comes above the horizon do { calendar.add(Calendar.SECOND, 60) satPos = getSatPos(calendar.time) elevation = satPos.elevation if (elevation > maxElevation) maxElevation = elevation } while (satPos.elevation < 0.0) - - // refine it to 3 seconds + + // refine to 3 seconds calendar.add(Calendar.SECOND, -60) do { calendar.add(Calendar.SECOND, 3) @@ -129,19 +125,19 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta elevation = satPos.elevation if (elevation > maxElevation) maxElevation = elevation } while (satPos.elevation < 0.0) - + val startDate = satPos.time val aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt() - - // now find when it goes below + + // find when sat goes below do { calendar.add(Calendar.SECOND, 30) satPos = getSatPos(calendar.time) elevation = satPos.elevation if (elevation > maxElevation) maxElevation = elevation } while (satPos.elevation > 0.0) - - // refine it to 3 seconds + + // refine to 3 seconds calendar.add(Calendar.SECOND, -30) do { calendar.add(Calendar.SECOND, 3) @@ -149,10 +145,10 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta elevation = satPos.elevation if (elevation > maxElevation) maxElevation = elevation } while (satPos.elevation > 0.0) - + val endDate = satPos.time val losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt() val maxEl = maxElevation / (2.0 * Math.PI) * 360.0 - return SatPassTime(startDate, endDate, polePassed, aosAzimuth, losAzimuth, maxEl) + return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt b/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt index 1f426f14..5c755b05 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt @@ -60,4 +60,4 @@ class QthConverter @Inject constructor() { private fun isValidLocation(lat: Double, lon: Double): Boolean { return (lat > -90.0 && lat < 90.0) && (lon > -180.0 && lon < 360.0) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/RecyclerDivider.kt b/app/src/main/java/com/rtbishop/look4sat/utility/RecyclerDivider.kt index 9dfdf202..206a2992 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/RecyclerDivider.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/RecyclerDivider.kt @@ -23,7 +23,7 @@ import androidx.recyclerview.widget.RecyclerView class RecyclerDivider(private val resId: Int) : RecyclerView.ItemDecoration() { - override fun onDrawOver(c: Canvas, parent: RecyclerView) { + override fun onDrawOver(canvas: Canvas, parent: RecyclerView) { ContextCompat.getDrawable(parent.context, resId)?.let { drawable -> val leftPos = parent.paddingLeft val rightPos = parent.width - parent.paddingRight @@ -35,10 +35,10 @@ class RecyclerDivider(private val resId: Int) : RecyclerView.ItemDecoration() { val topPos = view.bottom + params.bottomMargin val bottomPos = topPos + drawable.intrinsicHeight drawable.setBounds(leftPos, topPos, rightPos, bottomPos) - drawable.draw(c) + drawable.draw(canvas) } } } } } -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/fragment_passes.xml b/app/src/main/res/layout/fragment_passes.xml index fcbb1f32..c3cc0e16 100644 --- a/app/src/main/res/layout/fragment_passes.xml +++ b/app/src/main/res/layout/fragment_passes.xml @@ -65,13 +65,4 @@ - - diff --git a/app/src/test/java/com/rtbishop/look4sat/CoroutineTestRule.kt b/app/src/test/java/com/rtbishop/look4sat/CoroutineTestRule.kt index 8b335328..7f6cd069 100644 --- a/app/src/test/java/com/rtbishop/look4sat/CoroutineTestRule.kt +++ b/app/src/test/java/com/rtbishop/look4sat/CoroutineTestRule.kt @@ -39,4 +39,4 @@ class CoroutineTestRule(private val dispatcher: TestCoroutineDispatcher = TestCo Dispatchers.resetMain() dispatcher.cleanupTestCoroutines() } -} \ No newline at end of file +} diff --git a/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt b/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt index 92a6a5bd..d6d72d01 100644 --- a/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt +++ b/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt @@ -57,4 +57,4 @@ class QthConverterTest { assert(converter.locationToQTH(91.0542, -170.1142) == null) assert(converter.locationToQTH(89.0542, -240.1142) == null) } -} \ No newline at end of file +}