diff --git a/app/build.gradle b/app/build.gradle index 205ab162..6075fe2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/java/com/rtbishop/look4sat/repo/DefaultRepository.kt b/app/src/main/java/com/rtbishop/look4sat/repo/DefaultRepository.kt index 974836a5..81e4ba1d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/repo/DefaultRepository.kt +++ b/app/src/main/java/com/rtbishop/look4sat/repo/DefaultRepository.kt @@ -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> { + return sourcesDao.getSources() + } + + override suspend fun updateSources(sources: List) { + sourcesDao.clearSources() + sourcesDao.insertSources(sources) + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + override fun getAllEntries(): LiveData> { + return entriesDao.getAllEntries() + } + + override fun getSelectedEntries(): LiveData> { + 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) { - withContext(Dispatchers.IO) { - val streams = fetchTleStreams(urlList) - val entries = mutableListOf() - streams.forEach { - val list = TLE.importSat(it).map { tle -> SatEntry(tle) } - entries.addAll(list) - } - clearEntries() - insertEntries(entries) - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - override suspend fun fetchTleStreams(urlList: List): List = withContext(Dispatchers.IO) { val streams = mutableListOf() 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() + streams.forEach { + val list = TLE.importSat(it).map { tle -> SatEntry(tle) } + entries.addAll(list) + } + entriesDao.clearEntries() + entriesDao.insertEntries(entries) } - - override suspend fun fetchTransmitters(): List { - return api.fetchTransList() - } - - override suspend fun insertEntries(entries: List) { - entriesDao.insertEntries(entries) - } - - override suspend fun getAllEntries(): List { - return entriesDao.getAllEntries() - } - - override suspend fun getSelectedEntries(): List { - return entriesDao.getSelectedEntries() } override suspend fun updateEntriesSelection(catNumList: List) { @@ -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 { return transDao.getTransmittersForCatNum(catNum) } - - override suspend fun clearTransmitters() { - transDao.clearTransmitters() - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - override suspend fun updateSources(sources: List) { - clearSources() - sourcesDao.insertSources(sources) - } - - override suspend fun getSources(): List { - return sourcesDao.getSources() - } - - override suspend fun clearSources() { - sourcesDao.clearSources() - } } diff --git a/app/src/main/java/com/rtbishop/look4sat/repo/Repository.kt b/app/src/main/java/com/rtbishop/look4sat/repo/Repository.kt index 343d87a0..7eb6cdfc 100644 --- a/app/src/main/java/com/rtbishop/look4sat/repo/Repository.kt +++ b/app/src/main/java/com/rtbishop/look4sat/repo/Repository.kt @@ -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> + + suspend fun updateSources(sources: List) + + //////////////////////////////////////////////////////////////////////////////////////////////// + + fun getAllEntries(): LiveData> + + fun getSelectedEntries(): LiveData> + suspend fun updateEntriesFromFile(tleUri: Uri) suspend fun updateEntriesFromUrl(urlList: List) - //////////////////////////////////////////////////////////////////////////////////////////////// - - suspend fun fetchTleStreams(urlList: List): List - - suspend fun fetchTransmitters(): List - - suspend fun insertEntries(entries: List) - - suspend fun getAllEntries(): List - - suspend fun getSelectedEntries(): List - suspend fun updateEntriesSelection(catNumList: List) - suspend fun clearEntries() - //////////////////////////////////////////////////////////////////////////////////////////////// suspend fun updateTransmitters() suspend fun getTransmittersByCatNum(catNum: Int): List - - suspend fun clearTransmitters() - - //////////////////////////////////////////////////////////////////////////////////////////////// - - suspend fun updateSources(sources: List) - - suspend fun getSources(): List - - suspend fun clearSources() } diff --git a/app/src/main/java/com/rtbishop/look4sat/repo/local/EntriesDao.kt b/app/src/main/java/com/rtbishop/look4sat/repo/local/EntriesDao.kt index 94250859..b28c00a0 100644 --- a/app/src/main/java/com/rtbishop/look4sat/repo/local/EntriesDao.kt +++ b/app/src/main/java/com/rtbishop/look4sat/repo/local/EntriesDao.kt @@ -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) @Query("SELECT * FROM entries ORDER BY name ASC") - suspend fun getAllEntries(): List + fun getAllEntries(): LiveData> @Query("SELECT * FROM entries WHERE isSelected = 1 ORDER BY name ASC") - suspend fun getSelectedEntries(): List + fun getSelectedEntries(): LiveData> @Query("UPDATE entries SET isSelected = 1 WHERE catNum == :catNum") suspend fun updateEntrySelection(catNum: Int) diff --git a/app/src/main/java/com/rtbishop/look4sat/repo/local/SourcesDao.kt b/app/src/main/java/com/rtbishop/look4sat/repo/local/SourcesDao.kt index 54393ae0..3921f923 100644 --- a/app/src/main/java/com/rtbishop/look4sat/repo/local/SourcesDao.kt +++ b/app/src/main/java/com/rtbishop/look4sat/repo/local/SourcesDao.kt @@ -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) @Query("SELECT * FROM sources") - suspend fun getSources(): List + fun getSources(): LiveData> @Query("DELETE FROM sources") suspend fun clearSources() 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 049c215f..b4cf7035 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt @@ -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() } } \ 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 fe68586d..ce3bcc7d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/SharedViewModel.kt @@ -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>>() - private val _updateStatus = MutableLiveData>() - private val _gsp = MutableLiveData>().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>>() + fun getPassList(): LiveData>> = _satPassList fun getTransmittersForSat(id: Int) = liveData { emit(repository.getTransmittersByCatNum(id)) } - fun getPassList(): LiveData>> = _satPassList - fun getGSP(): LiveData> = _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) { + fun updateSatelliteData(list: List) { 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() 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 = runBlocking { - return@runBlocking repository.getSources() - } - private fun getPassesForEntries( entry: SatEntry, dateNow: Date, gsp: GroundStationPosition ): MutableList { 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 } @@ -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 } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/EntriesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/EntriesAdapter.kt index 43ed20b9..6b8fe9fd 100755 --- a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/EntriesAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/EntriesAdapter.kt @@ -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) : +class EntriesAdapter(private var entries: MutableList = mutableListOf()) : RecyclerView.Adapter() { + 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) : return entries.size } + fun getEntries(): MutableList { + return entries + } + fun setEntries(list: MutableList) { entries = list notifyDataSetChanged() } - fun getEntries(): MutableList { - 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, query: String): MutableList { + if (query.isEmpty()) return list + return try { + filterByCatNum(list, query.toInt()) + } catch (e: NumberFormatException) { + filterByName(list, query) + } + } + + private fun filterByCatNum(list: MutableList, catNum: Int): MutableList { + val filteredList = list.filter { it.catNum == catNum } + return filteredList as MutableList + } + + private fun filterByName(list: MutableList, query: String): MutableList { + val searchQuery = query.toLowerCase(Locale.getDefault()) + val filteredList = mutableListOf() + list.forEach { + val entryName = it.name.toLowerCase(Locale.getDefault()) + if (entryName.contains(searchQuery)) filteredList.add(it) + } + return filteredList + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesDialog.kt deleted file mode 100755 index 0c4c21a8..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/EntriesDialog.kt +++ /dev/null @@ -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) : - 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, query: String): MutableList { - if (query.isEmpty()) return list - return try { - filterByCatNum(list, query.toInt()) - } catch (e: NumberFormatException) { - filterByName(list, query) - } - } - - private fun filterByCatNum(list: MutableList, catNum: Int): MutableList { - val filteredList = list.filter { it.catNum == catNum } - return filteredList as MutableList - } - - private fun filterByName(list: MutableList, query: String): MutableList { - val searchQuery = query.toLowerCase(Locale.getDefault()) - val filteredList = mutableListOf() - list.forEach { - val name = it.name.toLowerCase(Locale.getDefault()) - if (name.contains(searchQuery)) filteredList.add(it) - } - return filteredList - } - - private fun onPositiveClicked() { - val catNumList = mutableListOf().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) - } -} 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 9ca0b12d..de121eec 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 @@ -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() 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) + }) + } + + // 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) { + 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) { - 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().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 + } } \ No newline at end of file diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/MapFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/MapFragment.kt index 69f81a75..8382be29 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/fragments/MapFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/fragments/MapFragment.kt @@ -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 -> { 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 4d96e150..b0814372 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 @@ -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() } } 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 cda828ac..816f2508 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 @@ -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() { diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt b/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt index a4cd2db7..141c859b 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt @@ -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 } } diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 021b216d..01d3cdf5 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -26,7 +26,15 @@ + tools:layout="@layout/fragment_entries"> + + + app:popEnterAnim="@anim/nav_default_pop_enter_anim" + app:popExitAnim="@anim/nav_default_pop_exit_anim" />