mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added sat items filtering by transmitter mode
This commit is contained in:
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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user