Added sat items filtering by transmitter mode

This commit is contained in:
Arty Bishop committed 2021-03-27 16:54:03 +00:00
1 parent 995953b823
commit 8d8e0bb7ac
6 files changed
+108 -22

No files matched your search

@@ -35,6 +35,7 @@ class PrefsRepo @Inject constructor(val preferences: SharedPreferences, moshi: M
companion object {
const val keySources = "sourcesListJson"
const val keyModes = "satModes"
const val keyLatitude = "latitude"
const val keyLongitude = "longitude"
const val keyAltitude = "altitude"
@@ -117,7 +118,7 @@ class PrefsRepo @Inject constructor(val preferences: SharedPreferences, moshi: M
val sourcesJson = sourcesAdapter.toJson(sources)
preferences.edit { putString(keySources, sourcesJson) }
}
fun loadDefaultSources(): List<TleSource> {
return listOf(
TleSource("https://celestrak.com/NORAD/elements/active.txt"),
@@ -126,4 +127,18 @@ class PrefsRepo @Inject constructor(val preferences: SharedPreferences, moshi: M
TleSource("https://www.prismnet.com/~mmccants/tles/inttles.zip")
)
}
fun saveModesSelection(modes: List<String>) {
val modesSet = modes.toSet()
preferences.edit {
putStringSet(keyModes, modesSet)
}
}
fun loadModesSelection(): List<String> {
preferences.getStringSet(keyModes, setOf())?.let { modesSet ->
return modesSet.toList().sorted()
}
return emptyList()
}
}
@@ -27,6 +27,7 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.model.Result
@@ -71,6 +72,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
}
importWeb.setOnClickListener { showImportFromWebDialog() }
importFile.setOnClickListener { filePicker.launch("*/*") }
selectMode.setOnClickListener { showModesDialog() }
selectAll.setOnClickListener { entriesAdapter?.selectAllItems() }
searchBar.addTextChangedListener { query -> filterByQuery(query) }
searchBar.clearFocus()
@@ -85,6 +87,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
setEmpty()
} else {
entriesAdapter?.submitAllItems(result.data)
binding?.entriesRecycler?.smoothScrollToPosition(0)
setLoaded()
}
}
@@ -101,11 +104,12 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
private fun observeSourcesResult() {
getNavResult<List<String>>(R.id.nav_entries, "sources") { result ->
val sources = result.map { TleSource(it) }
if (sources.isNullOrEmpty()) {
viewModel.importSatDataFromSources()
} else {
viewModel.importSatDataFromSources(sources)
result.map { TleSource(it) }.let { sources ->
if (sources.isNullOrEmpty()) {
viewModel.importSatDataFromSources()
} else {
viewModel.importSatDataFromSources(sources)
}
}
}
}
@@ -134,15 +138,46 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
}
}
private fun filterByQuery(it: Editable?) {
entriesAdapter?.filterItems(it.toString())
binding?.entriesRecycler?.scrollToPosition(0)
private fun filterByQuery(query: Editable?) {
entriesAdapter?.filterItems(query.toString())
binding?.entriesRecycler?.smoothScrollToPosition(0)
}
private fun showImportFromWebDialog() {
findNavController().navigate(R.id.nav_dialog_sources)
}
private fun showModesDialog() {
val modes = arrayOf(
"AFSK", "AFSK S-Net", "AFSK SALSAT", "AHRPT", "AM", "APT", "BPSK", "BPSK PMT-A3",
"CERTO", "CW", "DQPSK", "DSTAR", "DUV", "FFSK", "FM", "FMN", "FSK", "FSK AX.100 Mode 5",
"FSK AX.100 Mode 6", "FSK AX.25 G3RUH", "GFSK", "GFSK Rktr", "GMSK", "HRPT", "LoRa",
"LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK",
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
)
val savedModes = BooleanArray(modes.size)
val selectedModes = viewModel.getModesSelection().toMutableList()
selectedModes.forEach { savedModes[modes.indexOf(it)] = true }
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(getString(R.string.modes_title))
setMultiChoiceItems(modes, savedModes) { _, which, isChecked ->
if (isChecked) {
selectedModes.add(modes[which])
} else if (selectedModes.contains(modes[which])) {
selectedModes.remove(modes[which])
}
}
setPositiveButton(getString(android.R.string.ok)) { _, _ ->
viewModel.filterByModes(selectedModes)
}
setNeutralButton(getString(android.R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
create()
show()
}
}
override fun updateSelection(catNums: List<Int>, isSelected: Boolean) {
viewModel.updateEntriesSelection(catNums, isSelected)
}
@@ -28,10 +28,8 @@ import com.rtbishop.look4sat.data.repository.PrefsRepo
import com.rtbishop.look4sat.data.repository.SatelliteRepo
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.flattenMerge
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@@ -44,31 +42,56 @@ class EntriesViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo
) : ViewModel() {
private val satDataState = MutableSharedFlow<Result<List<SatItem>>>(replay = 0)
private val satDataFlow = satelliteRepo.getAllSatItems().map { Result.Success(it) }
val satData =
flowOf(satDataState, satDataFlow).flattenMerge().asLiveData(viewModelScope.coroutineContext)
private val allSatItems = mutableListOf<SatItem>()
private val satDataState = MutableStateFlow<Result<List<SatItem>>>(Result.InProgress)
val satData = satDataState.asLiveData(viewModelScope.coroutineContext)
init {
viewModelScope.launch {
satelliteRepo.getAllSatItems().collect { items ->
allSatItems.clear()
allSatItems.addAll(items)
filterByModes(getModesSelection())
}
}
}
fun getModesSelection(): List<String> {
return prefsRepo.loadModesSelection()
}
fun filterByModes(modes: List<String>) {
if (modes.isEmpty()) {
satDataState.value = Result.Success(allSatItems)
} else {
val itemsWithModes = allSatItems.filter { item ->
item.modes.any { mode -> mode in modes }
}
satDataState.value = Result.Success(itemsWithModes)
}
prefsRepo.saveModesSelection(modes)
}
fun importSatDataFromFile(uri: Uri) {
viewModelScope.launch {
satDataState.emit(Result.InProgress)
satDataState.value = Result.InProgress
try {
satelliteRepo.importSatDataFromFile(uri)
} catch (exception: Exception) {
satDataState.emit(Result.Error(exception))
satDataState.value = Result.Error(exception)
}
}
}
fun importSatDataFromSources(sources: List<TleSource> = prefsRepo.loadDefaultSources()) {
viewModelScope.launch {
satDataState.emit(Result.InProgress)
satDataState.value = Result.InProgress
val updateMillis = measureTimeMillis {
try {
prefsRepo.saveTleSources(sources)
satelliteRepo.importSatDataFromWeb(sources)
} catch (exception: Exception) {
satDataState.emit(Result.Error(exception))
satDataState.value = Result.Error(exception)
}
}
Timber.d("Update from WEB took $updateMillis ms")
+12 -1
View File
@@ -60,10 +60,21 @@
android:iconifiedByDefault="false"
android:importantForAutofill="no"
android:inputType="text"
app:layout_constraintEnd_toStartOf="@+id/select_all"
app:layout_constraintEnd_toStartOf="@+id/select_mode"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/entries_bar" />
<ImageButton
android:id="@+id/select_mode"
android:layout_width="64dp"
android:layout_height="48dp"
android:backgroundTint="@color/greySurface"
android:contentDescription="@string/placeholder"
android:src="@drawable/ic_satellite"
app:layout_constraintBottom_toBottomOf="@+id/select_all"
app:layout_constraintEnd_toStartOf="@+id/select_all"
app:layout_constraintTop_toTopOf="@+id/select_all" />
<ImageButton
android:id="@+id/select_all"
android:layout_width="64dp"
+1
View File
@@ -79,4 +79,5 @@
к ним по лицензии <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></string>
<string name="info_warranty"><a href="https://sites.google.com/view/look4sat-privacy-policy/home">Политика конфиденциальности</a>
\nЭто ПО поставляется без гарантий. \nПодробности в лицензии <a href="https://www.gnu.org/licenses/gpl-3.0.html">GNU GPLv3</a>.</string>
<string name="modes_title">Выберите модуляцию трансивера</string>
</resources>
+1
View File
@@ -99,4 +99,5 @@
</string>
<string name="info_warranty"><a href="https://sites.google.com/view/look4sat-privacy-policy/home">Privacy Policy</a>
\nThis app comes with no warranty. \nSee the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GNU GPLv3</a> license for details.</string>
<string name="modes_title">Choose transmitter mode</string>
</resources>