diff --git a/app/src/main/java/com/rtbishop/look4sat/SharedViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/SharedViewModel.kt index 1e416c00..2841b21f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/SharedViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/SharedViewModel.kt @@ -20,10 +20,11 @@ package com.rtbishop.look4sat import android.net.Uri -import androidx.hilt.Assisted import androidx.hilt.lifecycle.ViewModelInject -import androidx.lifecycle.* -import com.github.amsacode.predict4java.GroundStationPosition +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.rtbishop.look4sat.data.* import com.rtbishop.look4sat.repo.EntriesRepo import com.rtbishop.look4sat.repo.SourcesRepo @@ -41,34 +42,27 @@ class SharedViewModel @ViewModelInject constructor( private val prefsManager: PrefsManager, private val sourcesRepo: SourcesRepo, private val entriesRepo: EntriesRepo, - private val transmittersRepo: TransmittersRepo, - @Assisted private val savedStateHandle: SavedStateHandle + private val transmittersRepo: TransmittersRepo ) : ViewModel() { - private val _currentTimeMillis = MutableLiveData(System.currentTimeMillis()) + private val _appTimer = MutableLiveData(System.currentTimeMillis()) private val _passes = MutableLiveData>>() - private val _appEvent = MutableLiveData>() + private val _appEvent = MutableLiveData>() private var selectedEntries = emptyList() private var shouldTriggerCalculation = true init { - if (prefsManager.isFirstLaunch()) { - updateDefaultSourcesAndEntries() - } + if (prefsManager.isFirstLaunch()) updateDefaultSourcesAndEntries() startApplicationTimer() } + fun getAppEvent(): LiveData> = _appEvent + fun getAppTimer(): LiveData = _appTimer fun getSources() = sourcesRepo.getSources() fun getEntries() = entriesRepo.getEntries() - fun getCurrentTimeMillis(): LiveData = _currentTimeMillis fun getPasses(): LiveData>> = _passes - fun getAppEvent(): LiveData> = _appEvent fun getTransmittersForSat(satId: Int) = transmittersRepo.getTransmittersForSat(satId) - fun postAppEvent(event: Event) { - _appEvent.value = event - } - fun triggerCalculation() { if (shouldTriggerCalculation) { shouldTriggerCalculation = false @@ -76,28 +70,41 @@ class SharedViewModel @ViewModelInject constructor( } } - fun setSelectedEntries(entries: List) { + fun calculatePasses(dateNow: Date = Date(System.currentTimeMillis())) { + shouldTriggerCalculation = false + _passes.value = Result.InProgress + viewModelScope.launch(Dispatchers.Default) { + val passes = mutableListOf() + selectedEntries.forEach { passes.addAll(getPasses(it, dateNow)) } + val filteredPasses = sortList(passes, dateNow) + _passes.postValue(Result.Success(filteredPasses)) + } + } + + fun setEntries(entries: List) { selectedEntries = entries.filter { it.isSelected } } fun updateEntriesFromFile(uri: Uri) { + postAppEvent(Event(0)) viewModelScope.launch { try { entriesRepo.updateEntriesFromFile(uri) } catch (exception: Exception) { - postAppEvent(Event(exception)) + postAppEvent(Event(1)) } } } fun updateEntriesFromSources(sources: List) { + postAppEvent(Event(0)) viewModelScope.launch { try { sourcesRepo.updateSources(sources) entriesRepo.updateEntriesFromSources(sources) transmittersRepo.updateTransmitters() } catch (exception: Exception) { - postAppEvent(Event(exception)) + postAppEvent(Event(1)) } } } @@ -110,20 +117,41 @@ class SharedViewModel @ViewModelInject constructor( } } - fun calculatePasses(dateNow: Date = Date(System.currentTimeMillis())) { - shouldTriggerCalculation = false - _passes.value = Result.InProgress - viewModelScope.launch(Dispatchers.Default) { - val passes = mutableListOf() - selectedEntries.forEach { - passes.addAll(getPassesForEntries(it, dateNow, prefsManager.getStationPosition())) + private fun postAppEvent(event: Event) { + _appEvent.value = event + } + + private fun startApplicationTimer(tickMillis: Long = 1000L) { + viewModelScope.launch(Dispatchers.IO) { + while (true) { + delay(tickMillis) + _appTimer.postValue(System.currentTimeMillis()) } - val filteredPasses = - filterAndSortPasses(passes, dateNow, prefsManager.getPassPrefs().hoursAhead) - _passes.postValue(Result.Success(filteredPasses)) } } + private fun getPasses(entry: SatEntry, dateNow: Date): MutableList { + val gsp = prefsManager.getStationPosition() + val predictor = PassPredictor(entry.tle, gsp) + val hoursAhead = prefsManager.getPassPrefs().hoursAhead + val passes = predictor.getPasses(dateNow, hoursAhead, true) + val passList = passes.map { SatPass(entry.tle, predictor, it) } + return passList as MutableList + } + + private fun sortList(passes: MutableList, dateNow: Date): MutableList { + val hoursAhead = prefsManager.getPassPrefs().hoursAhead + 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 < prefsManager.getPassPrefs().minEl } + passes.sortBy { it.pass.startTime } + return passes + } + private fun updateDefaultSourcesAndEntries() { val defaultTleSources = listOf( TleSource("https://celestrak.com/NORAD/elements/active.txt"), @@ -131,43 +159,4 @@ class SharedViewModel @ViewModelInject constructor( ) updateEntriesFromSources(defaultTleSources) } - - private fun startApplicationTimer(tickMillis: Long = 1000L) { - viewModelScope.launch(Dispatchers.IO) { - while (true) { - delay(tickMillis) - _currentTimeMillis.postValue(System.currentTimeMillis()) - } - } - } - - private fun getPassesForEntries( - entry: SatEntry, - dateNow: Date, - gsp: GroundStationPosition - ): MutableList { - val predictor = PassPredictor(entry.tle, gsp) - val hoursAhead = prefsManager.getPassPrefs().hoursAhead - val passes = predictor.getPasses(dateNow, hoursAhead, true) - val passList = passes.map { SatPass(entry.tle, predictor, it) } - return passList as MutableList - } - - private fun filterAndSortPasses( - passes: MutableList, - dateNow: Date, - hoursAhead: Int - ): MutableList { - val dateFuture = Calendar.getInstance().let { - it.time = dateNow - it.add(Calendar.HOUR, hoursAhead) - it.time - } - val minEl = prefsManager.getPassPrefs().minEl - passes.removeAll { it.pass.startTime.after(dateFuture) } - passes.removeAll { it.pass.endTime.before(dateNow) } - passes.removeAll { it.pass.maxEl < minEl } - passes.sortBy { it.pass.startTime } - return passes - } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesFragment.kt index a8bdb527..a53cfc24 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesFragment.kt @@ -55,12 +55,20 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { private fun setupObservers() { viewModel.getSources().observe(viewLifecycleOwner, { tleSources = it }) viewModel.getEntries().observe(viewLifecycleOwner, { - viewModel.setSelectedEntries(it) - entriesAdapter.setEntries(it as MutableList) + if (it.isNullOrEmpty()) setError() + else { + viewModel.setEntries(it) + entriesAdapter.setEntries(it as MutableList) + setLoaded() + } }) viewModel.getAppEvent().observe(viewLifecycleOwner, { event -> event.getContentIfNotHandled()?.let { - getString(R.string.error_updating_data).snack(requireView()) + if (it == 0) setLoading() + else if (it == 1) { + getString(R.string.error_updating_data).snack(requireView()) + setError() + } } }) } @@ -77,6 +85,24 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { } } + private fun setLoaded() { + binding.entriesError.visibility = View.INVISIBLE + binding.entriesProgress.visibility = View.INVISIBLE + binding.entriesRecycler.visibility = View.VISIBLE + } + + private fun setLoading() { + binding.entriesError.visibility = View.INVISIBLE + binding.entriesRecycler.visibility = View.INVISIBLE + binding.entriesProgress.visibility = View.VISIBLE + } + + private fun setError() { + binding.entriesProgress.visibility = View.INVISIBLE + binding.entriesRecycler.visibility = View.INVISIBLE + binding.entriesError.visibility = View.VISIBLE + } + private fun navigateToPasses() { binding.searchBar.clearFocus() viewModel.updateEntriesSelection(entriesAdapter.getEntries()) diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PassesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PassesFragment.kt index 13133186..914aba91 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PassesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PassesFragment.kt @@ -68,7 +68,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes) { binding.passesProgress.visibility = View.VISIBLE } }) - viewModel.getCurrentTimeMillis().observe(viewLifecycleOwner, { currentTime -> + viewModel.getAppTimer().observe(viewLifecycleOwner, { currentTime -> tickMainTimer(currentTime) passesAdapter.tickPasses(currentTime) }) diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PolarFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PolarFragment.kt index edd47179..258153ea 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PolarFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/PolarFragment.kt @@ -134,7 +134,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener { } private fun observeTimer() { - viewModel.getCurrentTimeMillis().observe(viewLifecycleOwner, { + viewModel.getAppTimer().observe(viewLifecycleOwner, { setPassText(it) polarView?.invalidate() transmitterAdapter.notifyDataSetChanged() diff --git a/app/src/main/res/layout/fragment_entries.xml b/app/src/main/res/layout/fragment_entries.xml index 11416905..281a22c2 100644 --- a/app/src/main/res/layout/fragment_entries.xml +++ b/app/src/main/res/layout/fragment_entries.xml @@ -39,7 +39,7 @@ android:layout_height="wrap_content" android:layout_marginStart="24dp" android:elevation="4dp" - android:text="@string/sat_import" + android:text="@string/entries_update" android:textSize="18sp" app:layout_constraintBottom_toBottomOf="@+id/import_web" app:layout_constraintStart_toStartOf="parent" @@ -94,11 +94,35 @@ android:id="@+id/entries_recycler" android:layout_width="0dp" android:layout_height="0dp" + android:visibility="invisible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/search_bar" /> + + + + Источник TLE Используйте HTTPS - Импорт спутников + Обновить данные TLE: + Пожалуйста, обновите данные TLE diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 462a2ede..f304ec4d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -118,7 +118,8 @@ Please use HTTPS URLs only Placeholder Wikimedia maps | Map data © OpenStreetMap contributors - Import satellite data 00:00:00 - + TLE data update: + Please update TLE data