Further code refactoring in Repository.kt and EntriesFragment.kt
This commit is contained in:
1 parent
58fe352e30
commit
6b39a6759a
16 files changed
+231
-341
No files matched your search
@@ -63,7 +63,6 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "com.google.android.material:material:$material_version"
|
||||
implementation "androidx.appcompat:appcompat:$app_compat_version"
|
||||
implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version"
|
||||
implementation "androidx.core:core-ktx:$ktx_version"
|
||||
implementation "androidx.preference:preference:$preference_version"
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.rtbishop.look4sat.repo
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatTrans
|
||||
@@ -45,33 +46,37 @@ class DefaultRepository @Inject constructor(
|
||||
private val transDao: TransDao
|
||||
) : Repository {
|
||||
|
||||
override fun getSources(): LiveData<List<TleSource>> {
|
||||
return sourcesDao.getSources()
|
||||
}
|
||||
|
||||
override suspend fun updateSources(sources: List<TleSource>) {
|
||||
sourcesDao.clearSources()
|
||||
sourcesDao.insertSources(sources)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override fun getAllEntries(): LiveData<List<SatEntry>> {
|
||||
return entriesDao.getAllEntries()
|
||||
}
|
||||
|
||||
override fun getSelectedEntries(): LiveData<List<SatEntry>> {
|
||||
return entriesDao.getSelectedEntries()
|
||||
}
|
||||
|
||||
override suspend fun updateEntriesFromFile(tleUri: Uri) {
|
||||
withContext(Dispatchers.IO) {
|
||||
resolver.openInputStream(tleUri)?.use { stream ->
|
||||
val tleList = TLE.importSat(stream)
|
||||
val entries = tleList.map { SatEntry(it) }
|
||||
clearEntries()
|
||||
insertEntries(entries)
|
||||
entriesDao.clearEntries()
|
||||
entriesDao.insertEntries(entries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateEntriesFromUrl(urlList: List<TleSource>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val streams = fetchTleStreams(urlList)
|
||||
val entries = mutableListOf<SatEntry>()
|
||||
streams.forEach {
|
||||
val list = TLE.importSat(it).map { tle -> SatEntry(tle) }
|
||||
entries.addAll(list)
|
||||
}
|
||||
clearEntries()
|
||||
insertEntries(entries)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun fetchTleStreams(urlList: List<TleSource>): List<InputStream> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val streams = mutableListOf<InputStream>()
|
||||
urlList.withIndex().forEach {
|
||||
@@ -79,23 +84,15 @@ class DefaultRepository @Inject constructor(
|
||||
val stream = client.newCall(request).execute().body?.byteStream()
|
||||
stream?.let { inputStream -> streams.add(inputStream) }
|
||||
}
|
||||
return@withContext streams
|
||||
|
||||
val entries = mutableListOf<SatEntry>()
|
||||
streams.forEach {
|
||||
val list = TLE.importSat(it).map { tle -> SatEntry(tle) }
|
||||
entries.addAll(list)
|
||||
}
|
||||
entriesDao.clearEntries()
|
||||
entriesDao.insertEntries(entries)
|
||||
}
|
||||
|
||||
override suspend fun fetchTransmitters(): List<SatTrans> {
|
||||
return api.fetchTransList()
|
||||
}
|
||||
|
||||
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(catNumList: List<Int>) {
|
||||
@@ -103,35 +100,14 @@ class DefaultRepository @Inject constructor(
|
||||
catNumList.forEach { entriesDao.updateEntrySelection(it) }
|
||||
}
|
||||
|
||||
override suspend fun clearEntries() {
|
||||
entriesDao.clearEntries()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun updateTransmitters() {
|
||||
transDao.clearTransmitters()
|
||||
transDao.insertTransmitters(api.fetchTransList())
|
||||
}
|
||||
|
||||
override suspend fun getTransmittersByCatNum(catNum: Int): List<SatTrans> {
|
||||
return transDao.getTransmittersForCatNum(catNum)
|
||||
}
|
||||
|
||||
override suspend fun clearTransmitters() {
|
||||
transDao.clearTransmitters()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun updateSources(sources: List<TleSource>) {
|
||||
clearSources()
|
||||
sourcesDao.insertSources(sources)
|
||||
}
|
||||
|
||||
override suspend fun getSources(): List<TleSource> {
|
||||
return sourcesDao.getSources()
|
||||
}
|
||||
|
||||
override suspend fun clearSources() {
|
||||
sourcesDao.clearSources()
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,32 @@
|
||||
package com.rtbishop.look4sat.repo
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatTrans
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import java.io.InputStream
|
||||
|
||||
interface Repository {
|
||||
|
||||
fun getSources(): LiveData<List<TleSource>>
|
||||
|
||||
suspend fun updateSources(sources: List<TleSource>)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fun getAllEntries(): LiveData<List<SatEntry>>
|
||||
|
||||
fun getSelectedEntries(): LiveData<List<SatEntry>>
|
||||
|
||||
suspend fun updateEntriesFromFile(tleUri: Uri)
|
||||
|
||||
suspend fun updateEntriesFromUrl(urlList: List<TleSource>)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun fetchTleStreams(urlList: List<TleSource>): List<InputStream>
|
||||
|
||||
suspend fun fetchTransmitters(): List<SatTrans>
|
||||
|
||||
suspend fun insertEntries(entries: List<SatEntry>)
|
||||
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
|
||||
suspend fun getSelectedEntries(): List<SatEntry>
|
||||
|
||||
suspend fun updateEntriesSelection(catNumList: List<Int>)
|
||||
|
||||
suspend fun clearEntries()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun updateTransmitters()
|
||||
|
||||
suspend fun getTransmittersByCatNum(catNum: Int): List<SatTrans>
|
||||
|
||||
suspend fun clearTransmitters()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun updateSources(sources: List<TleSource>)
|
||||
|
||||
suspend fun getSources(): List<TleSource>
|
||||
|
||||
suspend fun clearSources()
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.rtbishop.look4sat.repo.local
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
@@ -32,10 +33,10 @@ interface EntriesDao {
|
||||
suspend fun insertEntries(entries: List<SatEntry>)
|
||||
|
||||
@Query("SELECT * FROM entries ORDER BY name ASC")
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
fun getAllEntries(): LiveData<List<SatEntry>>
|
||||
|
||||
@Query("SELECT * FROM entries WHERE isSelected = 1 ORDER BY name ASC")
|
||||
suspend fun getSelectedEntries(): List<SatEntry>
|
||||
fun getSelectedEntries(): LiveData<List<SatEntry>>
|
||||
|
||||
@Query("UPDATE entries SET isSelected = 1 WHERE catNum == :catNum")
|
||||
suspend fun updateEntrySelection(catNum: Int)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.rtbishop.look4sat.repo.local
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
@@ -13,7 +14,7 @@ interface SourcesDao {
|
||||
suspend fun insertSources(sources: List<TleSource>)
|
||||
|
||||
@Query("SELECT * FROM sources")
|
||||
suspend fun getSources(): List<TleSource>
|
||||
fun getSources(): LiveData<List<TleSource>>
|
||||
|
||||
@Query("DELETE FROM sources")
|
||||
suspend fun clearSources()
|
||||
|
||||
@@ -27,5 +27,6 @@ class MainActivity : AppCompatActivity() {
|
||||
binding.navBottom.setupWithNavController(navHost.navController)
|
||||
(application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(this, factory).get(SharedViewModel::class.java)
|
||||
viewModel.setDefaultTleSources()
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -43,62 +42,34 @@ class SharedViewModel @Inject constructor(
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _satPassList = MutableLiveData<Result<MutableList<SatPass>>>()
|
||||
private val _updateStatus = MutableLiveData<Result<Int>>()
|
||||
private val _gsp = MutableLiveData<Result<GroundStationPosition>>().apply {
|
||||
value = Result.Success(prefsManager.getPosition())
|
||||
}
|
||||
val tleSources = repository.getSources()
|
||||
val allEntries = repository.getAllEntries()
|
||||
val selectedEntries = repository.getSelectedEntries()
|
||||
|
||||
private var calculationJob: Job? = null
|
||||
private val _satPassList = MutableLiveData<Result<MutableList<SatPass>>>()
|
||||
fun getPassList(): LiveData<Result<MutableList<SatPass>>> = _satPassList
|
||||
|
||||
fun getTransmittersForSat(id: Int) = liveData { emit(repository.getTransmittersByCatNum(id)) }
|
||||
fun getPassList(): LiveData<Result<MutableList<SatPass>>> = _satPassList
|
||||
fun getGSP(): LiveData<Result<GroundStationPosition>> = _gsp
|
||||
|
||||
fun getCompass() = prefsManager.getCompass()
|
||||
fun getHoursAhead() = prefsManager.getHoursAhead()
|
||||
fun getMinElevation() = prefsManager.getMinElevation()
|
||||
suspend fun getAllEntries() = repository.getAllEntries()
|
||||
|
||||
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
||||
prefsManager.setHoursAhead(hoursAhead)
|
||||
prefsManager.setMinElevation(minEl)
|
||||
}
|
||||
|
||||
fun updatePosition() {
|
||||
val lastLoc = prefsManager.getLastKnownLocation()
|
||||
if (lastLoc == null) {
|
||||
_gsp.postValue(Result.Error(Exception()))
|
||||
} else {
|
||||
val gsp = GroundStationPosition(lastLoc.latitude, lastLoc.longitude, lastLoc.altitude)
|
||||
_gsp.postValue(Result.Success(gsp))
|
||||
}
|
||||
prefsManager.updateLocation()
|
||||
}
|
||||
|
||||
fun updateEntriesFromFile(uri: Uri) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val selected = repository.getSelectedEntries().map { it.catNum }
|
||||
repository.updateEntriesFromFile(uri)
|
||||
repository.updateEntriesSelection(selected)
|
||||
_updateStatus.postValue(Result.Success(0))
|
||||
} catch (e: Exception) {
|
||||
_updateStatus.postValue(Result.Error(e))
|
||||
}
|
||||
val selected = selectedEntries.value!!.map { it.catNum }
|
||||
repository.updateEntriesFromFile(uri)
|
||||
repository.updateEntriesSelection(selected)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSatData(list: List<TleSource>) {
|
||||
fun updateSatelliteData(list: List<TleSource>) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val selected = repository.getSelectedEntries().map { it.catNum }
|
||||
repository.updateSources(list)
|
||||
repository.updateEntriesFromUrl(list)
|
||||
repository.updateTransmitters()
|
||||
repository.updateEntriesSelection(selected)
|
||||
_updateStatus.postValue(Result.Success(0))
|
||||
} catch (e: Exception) {
|
||||
_updateStatus.postValue(Result.Error(e))
|
||||
}
|
||||
val selected = selectedEntries.value!!.map { it.catNum }
|
||||
repository.updateSources(list)
|
||||
repository.updateEntriesFromUrl(list)
|
||||
repository.updateTransmitters()
|
||||
repository.updateEntriesSelection(selected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,12 +85,12 @@ class SharedViewModel @Inject constructor(
|
||||
calculationJob?.cancel()
|
||||
var passList = mutableListOf<SatPass>()
|
||||
val dateNow = Date()
|
||||
val gsp = prefsManager.getPosition()
|
||||
val gsp = prefsManager.getStationPosition()
|
||||
calculationJob = viewModelScope.launch(Dispatchers.Default) {
|
||||
repository.getSelectedEntries().forEach {
|
||||
repository.getSelectedEntries().value?.forEach {
|
||||
passList.addAll(getPassesForEntries(it, dateNow, gsp))
|
||||
}
|
||||
passList = filterAndSortPasses(passList, dateNow, getHoursAhead())
|
||||
passList = filterAndSortPasses(passList, dateNow, prefsManager.getHoursAhead())
|
||||
_satPassList.postValue(Result.Success(passList))
|
||||
}
|
||||
}
|
||||
@@ -136,17 +107,13 @@ class SharedViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun getTleSources(): List<TleSource> = runBlocking {
|
||||
return@runBlocking repository.getSources()
|
||||
}
|
||||
|
||||
private fun getPassesForEntries(
|
||||
entry: SatEntry,
|
||||
dateNow: Date,
|
||||
gsp: GroundStationPosition
|
||||
): MutableList<SatPass> {
|
||||
val predictor = PassPredictor(entry.tle, gsp)
|
||||
val passes = predictor.getPasses(dateNow, getHoursAhead(), true)
|
||||
val passes = predictor.getPasses(dateNow, prefsManager.getHoursAhead(), true)
|
||||
val passList = passes.map { SatPass(entry.tle, predictor, it) }
|
||||
return passList as MutableList<SatPass>
|
||||
}
|
||||
@@ -163,7 +130,7 @@ class SharedViewModel @Inject constructor(
|
||||
}
|
||||
passes.removeAll { it.pass.startTime.after(dateFuture) }
|
||||
passes.removeAll { it.pass.endTime.before(dateNow) }
|
||||
passes.removeAll { it.pass.maxEl < getMinElevation() }
|
||||
passes.removeAll { it.pass.maxEl < prefsManager.getMinElevation() }
|
||||
passes.sortBy { it.pass.startTime }
|
||||
return passes
|
||||
}
|
||||
|
||||
@@ -25,10 +25,25 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.databinding.ItemSatEntryBinding
|
||||
import java.util.*
|
||||
|
||||
class EntriesAdapter(private var entries: MutableList<SatEntry>) :
|
||||
class EntriesAdapter(private var entries: MutableList<SatEntry> = mutableListOf()) :
|
||||
RecyclerView.Adapter<EntriesAdapter.SatEntryHolder>() {
|
||||
|
||||
private var selectAllToggle = true
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatEntryHolder {
|
||||
val binding = ItemSatEntryBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
@@ -43,24 +58,50 @@ class EntriesAdapter(private var entries: MutableList<SatEntry>) :
|
||||
return entries.size
|
||||
}
|
||||
|
||||
fun getEntries(): MutableList<SatEntry> {
|
||||
return entries
|
||||
}
|
||||
|
||||
fun setEntries(list: MutableList<SatEntry>) {
|
||||
entries = list
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getEntries(): MutableList<SatEntry> {
|
||||
return entries
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
fun selectAll() {
|
||||
selectAllToggle = if (selectAllToggle) {
|
||||
val currentList = getEntries()
|
||||
currentList.forEach { it.isSelected = true }
|
||||
setEntries(currentList)
|
||||
false
|
||||
} else {
|
||||
val currentList = getEntries()
|
||||
currentList.forEach { it.isSelected = false }
|
||||
setEntries(currentList)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
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 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 entryName = it.name.toLowerCase(Locale.getDefault())
|
||||
if (entryName.contains(searchQuery)) filteredList.add(it)
|
||||
}
|
||||
return filteredList
|
||||
}
|
||||
}
|
||||
@@ -1,138 +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.ui.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
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.DialogEntriesBinding
|
||||
import com.rtbishop.look4sat.ui.adapters.EntriesAdapter
|
||||
import java.util.*
|
||||
|
||||
class EntriesDialog(private var entries: MutableList<SatEntry>) :
|
||||
AppCompatDialogFragment(), SearchView.OnQueryTextListener {
|
||||
|
||||
private lateinit var entriesListener: EntriesSubmitListener
|
||||
private val entryAdapter = EntriesAdapter(entries)
|
||||
private var selectAllToggle = true
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogEntriesBinding.inflate(requireActivity().layoutInflater)
|
||||
val satEntryDialog = Dialog(requireActivity()).apply {
|
||||
window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(binding.root)
|
||||
window?.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
binding.dialogSearch.apply {
|
||||
setOnQueryTextListener(this@EntriesDialog)
|
||||
onActionViewExpanded()
|
||||
clearFocus()
|
||||
}
|
||||
|
||||
binding.dialogRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(activity)
|
||||
adapter = entryAdapter
|
||||
}
|
||||
|
||||
binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() }
|
||||
binding.dialogBtnNegative.setOnClickListener { onNegativeClicked() }
|
||||
binding.dialogBtnNeutral.setOnClickListener { onNeutralClicked() }
|
||||
|
||||
return satEntryDialog
|
||||
}
|
||||
|
||||
fun setEntriesListener(listener: EntriesSubmitListener): EntriesDialog {
|
||||
entriesListener = listener
|
||||
return this
|
||||
}
|
||||
|
||||
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 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())
|
||||
if (name.contains(searchQuery)) filteredList.add(it)
|
||||
}
|
||||
return filteredList
|
||||
}
|
||||
|
||||
private fun onPositiveClicked() {
|
||||
val catNumList = mutableListOf<Int>().apply {
|
||||
entries.forEach { if (it.isSelected) this.add(it.catNum) }
|
||||
}
|
||||
entriesListener.onEntriesSubmit(catNumList)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun onNegativeClicked() {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun onNeutralClicked() {
|
||||
selectAllToggle = if (selectAllToggle) {
|
||||
val currentList = entryAdapter.getEntries()
|
||||
currentList.forEach { it.isSelected = true }
|
||||
entryAdapter.setEntries(currentList)
|
||||
false
|
||||
} else {
|
||||
val currentList = entryAdapter.getEntries()
|
||||
currentList.forEach { it.isSelected = false }
|
||||
entryAdapter.setEntries(currentList)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
val filteredList = filterEntries(entries, newText)
|
||||
entryAdapter.setEntries(filteredList)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
interface EntriesSubmitListener {
|
||||
fun onEntriesSubmit(catNumList: MutableList<Int>)
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,25 @@ package com.rtbishop.look4sat.ui.fragments
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.SearchView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.TleSource
|
||||
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.adapters.EntriesAdapter
|
||||
import javax.inject.Inject
|
||||
|
||||
class EntriesFragment : Fragment(R.layout.fragment_entries), SourcesDialog.SourcesSubmitListener {
|
||||
class EntriesFragment : Fragment(R.layout.fragment_entries),
|
||||
SourcesDialog.SourcesSubmitListener,
|
||||
SearchView.OnQueryTextListener {
|
||||
|
||||
@Inject
|
||||
lateinit var factory: ViewModelFactory
|
||||
@@ -22,25 +29,55 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), SourcesDialog.Sourc
|
||||
private lateinit var binding: FragmentEntriesBinding
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private val pickFileReqCode = 100
|
||||
private val entriesAdapter = EntriesAdapter()
|
||||
private var tleSources = listOf<TleSource>()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentEntriesBinding.bind(view)
|
||||
(requireActivity().application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(requireActivity(), factory).get(SharedViewModel::class.java)
|
||||
|
||||
binding.importWeb.setOnClickListener { showSourcesDialog() }
|
||||
binding.importFile.setOnClickListener { showFileDialog() }
|
||||
setupUI()
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
private fun setupUI() {
|
||||
binding.apply {
|
||||
importWeb.setOnClickListener { showSourcesDialog() }
|
||||
importFile.setOnClickListener { showFileDialog() }
|
||||
selectAll.setOnClickListener { entriesAdapter.selectAll() }
|
||||
entriesFab.setOnClickListener { goToPassesAndCalculateForSelection() }
|
||||
searchBar.setOnQueryTextListener(this@EntriesFragment)
|
||||
entriesRecycler.layoutManager = LinearLayoutManager(requireActivity())
|
||||
entriesRecycler.adapter = entriesAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.tleSources.observe(viewLifecycleOwner, { sources ->
|
||||
tleSources = sources
|
||||
})
|
||||
viewModel.allEntries.observe(viewLifecycleOwner, { entries ->
|
||||
entriesAdapter.setEntries(entries as MutableList<SatEntry>)
|
||||
})
|
||||
}
|
||||
|
||||
// Entries update from web
|
||||
|
||||
private fun showSourcesDialog() {
|
||||
val fragmentManager = childFragmentManager
|
||||
SourcesDialog(viewModel.getTleSources()).apply {
|
||||
SourcesDialog(tleSources).apply {
|
||||
setSourcesListener(this@EntriesFragment)
|
||||
show(fragmentManager, "TleSourcesDialog")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSourcesSubmit(list: List<TleSource>) {
|
||||
viewModel.updateSatelliteData(list)
|
||||
}
|
||||
|
||||
// Entries update from file
|
||||
|
||||
private fun showFileDialog() {
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
@@ -49,13 +86,29 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), SourcesDialog.Sourc
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSourcesSubmit(list: List<TleSource>) {
|
||||
viewModel.updateSatData(list)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == pickFileReqCode && resultCode == AppCompatActivity.RESULT_OK) {
|
||||
data?.data?.also { uri -> viewModel.updateEntriesFromFile(uri) }
|
||||
} else super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
// Search and select entries
|
||||
|
||||
private fun goToPassesAndCalculateForSelection() {
|
||||
val catNumList = mutableListOf<Int>().apply {
|
||||
entriesAdapter.getEntries().forEach { if (it.isSelected) this.add(it.catNum) }
|
||||
}
|
||||
viewModel.updateEntriesSelection(catNumList)
|
||||
requireView().findNavController().navigate(R.id.action_entries_to_passes)
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
val filteredList = entriesAdapter.filterEntries(entriesAdapter.getEntries(), newText)
|
||||
entriesAdapter.setEntries(filteredList)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import com.rtbishop.look4sat.data.SatItem
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapBinding
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -43,6 +44,10 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
|
||||
private lateinit var mainActivity: FragmentActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var binding: FragmentMapBinding
|
||||
@@ -77,6 +82,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
}
|
||||
|
||||
setupMapView()
|
||||
setupPosOverlay(prefsManager.getStationPosition())
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
@@ -121,14 +127,6 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { stationPosition ->
|
||||
when (stationPosition) {
|
||||
is Result.Success -> {
|
||||
setupPosOverlay(stationPosition.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.getPassList().observe(viewLifecycleOwner, { satPasses ->
|
||||
when (satPasses) {
|
||||
is Result.Success -> {
|
||||
|
||||
@@ -99,7 +99,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes) {
|
||||
setTimer()
|
||||
|
||||
binding.passesFilter.setOnClickListener {
|
||||
showSatPassPrefsDialog(viewModel.getHoursAhead(), viewModel.getMinElevation())
|
||||
showSatPassPrefsDialog(prefsManager.getHoursAhead(), prefsManager.getMinElevation())
|
||||
}
|
||||
binding.passesFab.setOnClickListener {
|
||||
viewModel.calculatePasses()
|
||||
@@ -128,7 +128,8 @@ class PassesFragment : Fragment(R.layout.fragment_passes) {
|
||||
getString(R.string.pref_min_el_input_error).snack(requireView())
|
||||
}
|
||||
else -> {
|
||||
viewModel.setPassPrefs(hours, elevation)
|
||||
prefsManager.setHoursAhead(hours)
|
||||
prefsManager.setMinElevation(elevation)
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.rtbishop.look4sat.databinding.FragmentPolarBinding
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.adapters.TransAdapter
|
||||
import com.rtbishop.look4sat.ui.views.PolarView
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
@@ -48,6 +49,10 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
|
||||
private lateinit var mainActivity: FragmentActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var binding: FragmentPolarBinding
|
||||
@@ -69,13 +74,13 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||
layoutManager = LinearLayoutManager(mainActivity)
|
||||
adapter = transmitterAdapter
|
||||
}
|
||||
calculateMagneticDeclination()
|
||||
observePasses()
|
||||
observeStationPosition()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (viewModel.getCompass()) {
|
||||
if (prefsManager.getCompass()) {
|
||||
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
|
||||
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
|
||||
}
|
||||
@@ -84,7 +89,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (viewModel.getCompass()) {
|
||||
if (prefsManager.getCompass()) {
|
||||
sensorManager.unregisterListener(this)
|
||||
}
|
||||
}
|
||||
@@ -132,18 +137,15 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||
})
|
||||
}
|
||||
|
||||
private fun observeStationPosition() {
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { result ->
|
||||
if (result is Result.Success) {
|
||||
val geoField = GeomagneticField(
|
||||
result.data.latitude.toFloat(),
|
||||
result.data.longitude.toFloat(),
|
||||
result.data.heightAMSL.toFloat(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
magneticDeclination = geoField.declination
|
||||
}
|
||||
})
|
||||
private fun calculateMagneticDeclination() {
|
||||
val position = prefsManager.getStationPosition()
|
||||
val geoField = GeomagneticField(
|
||||
position.latitude.toFloat(),
|
||||
position.longitude.toFloat(),
|
||||
position.heightAMSL.toFloat(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
magneticDeclination = geoField.declination
|
||||
}
|
||||
|
||||
private fun refreshText() {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.edit
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
@@ -72,21 +71,19 @@ class PrefsManager @Inject constructor(
|
||||
return preferences.getBoolean(keyCompass, true)
|
||||
}
|
||||
|
||||
fun getPosition(): GroundStationPosition {
|
||||
fun getStationPosition(): 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)
|
||||
}
|
||||
|
||||
fun getLastKnownLocation(): Location? {
|
||||
val provPassive = LocationManager.PASSIVE_PROVIDER
|
||||
return try {
|
||||
val location = locationManager.getLastKnownLocation(provPassive)
|
||||
location?.let {
|
||||
val lat = location.latitude.round(4)
|
||||
val lon = location.longitude.round(4)
|
||||
val alt = location.altitude.round(1)
|
||||
fun updateLocation() {
|
||||
try {
|
||||
locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)?.let {
|
||||
val lat = it.latitude.round(4)
|
||||
val lon = it.longitude.round(4)
|
||||
val alt = it.altitude.round(1)
|
||||
preferences.edit {
|
||||
putString(keyLatitude, lat.toString())
|
||||
putString(keyLongitude, lon.toString())
|
||||
@@ -94,9 +91,7 @@ class PrefsManager @Inject constructor(
|
||||
apply()
|
||||
}
|
||||
}
|
||||
location
|
||||
} catch (e: SecurityException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,15 @@
|
||||
<fragment
|
||||
android:id="@+id/nav_entries"
|
||||
android:name="com.rtbishop.look4sat.ui.fragments.EntriesFragment"
|
||||
tools:layout="@layout/fragment_entries" />
|
||||
tools:layout="@layout/fragment_entries">
|
||||
<action
|
||||
android:id="@+id/action_entries_to_passes"
|
||||
app:destination="@id/nav_passes"
|
||||
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
|
||||
android:id="@+id/nav_passes"
|
||||
@@ -37,8 +45,8 @@
|
||||
app:destination="@id/nav_polar"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_exit_anim" />
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
||||
@@ -22,7 +22,6 @@ buildscript {
|
||||
gradle_version = '4.0.1'
|
||||
gradle_plugin_version = '1.4.10'
|
||||
material_version = '1.2.1'
|
||||
app_compat_version = '1.2.0'
|
||||
constraint_layout_version = '2.0.1'
|
||||
ktx_version = '1.3.1'
|
||||
preference_version = '1.1.1'
|
||||
|
||||
Reference in new issue
Block a user